Remove receipt image border using ImageMagick - ruby

I'm using ImageMagick service to pre-process the receipt image before using tesseract-OCR engine to extract texts. I need to remove the background of the receipts. I've gone through masking to remove the border here. But I'm unable to create the mask for the receipts.
However, I've tried to remove shadows from the receipt images.
Initial Image (Example receipt)
convert input.png -colorspace gray \
\( +clone -blur 0x2 \) +swap -compose divide -composite \
-linear-stretch 5%x0% photocopy.png
After the code is applied:
I've tried the code below to make all colors except white to black but this does not seem to be totally blacking out the background of photocopy.png.
convert receipt.jpg -fill black -fuzz 20% +opaque "#ffffff" black_border.jpg
Is there any way to remove the border of the receipt image? Or create any kind of masks out of the image? Note: I need to remove noise and border for multiple images with different backgrounds.

To answer your question
"Is there any way to remove the border of the receipt image? Or create any kind of masks out of the image?"
The following command (based on your own code) will create an image which you can use to derive the dimensions of an applicable mask:
convert \
origscan.jpg \
-colorspace gray \
\( +clone 0 -blur 0x2 \) \
+swap \
-compose divide \
-composite \
-linear-stretch 5%x0% \
-threshold 5% \
-trim \
mask-image.png
You can use that mask-image to create a monochrome (black) mask -- in one command:
convert \
origscan.jpg \
-colorspace gray \
\( +clone 0 -blur 0x2 \) \
+swap \
-compose divide \
-composite \
-linear-stretch 5%x0% \
-threshold 5% \
\( \
-clone 0 \
-fill '#000000' \
-colorize 100 \
\) \
-delete 0 \
black-mask.png
Here are the results of above two commands, side by side:
You can use identify to get the geometry of mask-image.png as well as black-mask.png:
identify -format "%g\n" *mask*.png
2322x4128+366+144
2322x4128+366+144
So the image canvases are 2322 pixels wide and 4128 pixels high. The visible parts both images are of course smaller, following our -trim operation. (The +366+144 part indicates a horizontal/vertical offset from the top left corner of the original image.)
Additional comment: Having said all this: you should really look into creating better photos from your receipts! (If you have a camera which can create images of 4128 pixels height this shouldn't be a problem. If you have so many receipts to process as you say, then it may be a good idea to acquire a small platten glass that you can place on top of the paper in order to have it straightened out while photographing...)

If using ImageMagick on a unix-like system, you could try my text cleaner script.
textcleaner -f 20 -o 10 -e normalize UhSV6.jpg result.jpg

Related

How to call an external command in Gimp Plugin?

How to use an external command to make an edit of pic in the gimp and then return the result to the stage in a plugin or script.
Example in shell script.:
magick label.gif +matte
( +clone -shade 110x90 -normalize -negate +clone -compose Plus -composite )
( -clone 0 -shade 110x50 -normalize -channel BG -fx 0 +channel -matte )
-delete 0 +swap -compose Multiply -
The command above (imagemagick app) create a gif and i want put back in gimp stage. May be other simple option or application, but i need of return the edited back to gimp. Python, script fu? Thanks so much.
enter image description here
There is a shellout.py Gimp plugin floating around from which you can borrow code. Typically:
you export the layer to a temp file (if you work on the whole image, you likely have to do a pdb.gimp_layer_new_from_visible())
call the executable with subprocess.Popen() and a list of arguments
load the result as a new layer with pdb.gimp_file_load_layer()
If GIMP will take stdin, then pipe from ImageMagick to GIMP using the GIMP XCF file format.
magick label.gif +matte
( +clone -shade 110x90 -normalize -negate +clone -compose Plus -composite )
( -clone 0 -shade 110x50 -normalize -channel BG -fx 0 +channel -matte )
-delete 0 +swap -compose Multiply XCF:- | GIMP -

How to create image with ImageMagick?

I need to dynamically create an image, and I'm trying to find a good 'starting place' using magick or convert from command line (the actual library I will convert the CLI command to is MiniMagick for ruby)
To be honest, it's a little bit overwhelming... I'm not asking someone to write the whole thing for me, just get me a good 'starting' place that I can then work on adding text "layers" to.
Here is what the final output image needs to look like, and the required things I'm looking for:
A background image (the gray circle) that I can position using x,y coordinates. The input file is circle.png. I'd also like to be able to enlarge/reduce the dimensions of the circle to be the exact size i want.
Red small, centered text.
Bold, larger, centered black text. For this text it needs to intelligently go on new lines when the line is too long (and have padding against the outside of the image so it doesn't touch the edge)
Blue, underlined, medium text thats centered.
A red border that overlays the background image
circle.png for reference
This will get you a start using ImageMagick to create your image. Unix syntax. ImageMagick does not have an underline feature. So you need to select an underline font for that section. (However, there are slightly more complex ways to achieve that using label: and then splicing in the underline)
convert -size 299x249 xc:white \( circle.png -resize 200x200 \) \
-gravity northwest -geometry +100+70 -compose over -composite \
-bordercolor red -border 1 \
-font arial -fill red -pointsize 18 -gravity north -annotate +0+20 "**Info**" \
-font arial -fill blue -pointsize 28 -gravity south -annotate +0+50 "click here" \
\( -size 279x -background none -fill black \
-font arial -pointsize 28 -gravity center \
caption:"Welcome John to your profile, have a look around" -trim +repage \) \
-gravity center -geometry +0-20 -compose over -composite \
result.png
NOTE: updated slightly

ImageMagick: combine multiple 'montage' commands into one to gain performance

I have a script that takes 4 pictures and duplicates them to produce 8 small pictures in one. The script also adds a background to the output.
Here is what I expect:
http://img11.hostingpics.net/pics/831624stack.png
I have a code that works well. But it needs to save multiple temporary images.
So I was looking if I could merge the commands of my script to get only one image saving operation. The goal is to make the script complete faster.
//Make image smaller:
convert /home/pi/images/*.png -resize 487x296 -flop \
-set filename:f "/home/pi/imagesResized/%t%p" '%[filename:f]'.png
//Make one column from 4 images:
montage /home/pi/imagesResized/*.png -tile 1x4 \
-geometry +0+15 -background none /home/pi/line.png
//Duplicate to two columns:
montage /home/pi/line.png /home/pi/line.png -tile 2x1 \
-geometry +45+0 -background none /home/pi/photos.png
//Add the background image:
suffix=$(date +%H%M%S)
montage /home/pi/photos.png -geometry +20+247 \
-texture /home/pi/data/background_photo.png \
/home/pi/photo_${suffix}.jpg
First, let me say this:
you'll save only significant processing time by putting the separate commands into one single ImageMagick command chain if your input images are quite large.
You may however save disk I/O time by skipping the need to write out and read in the intermediate result images.
Your code uses two different montage commands plus one convert command in order to achieve a first montage.
Finally you use one montage to place the previous result on the background.
From the top of my head, I can quickly come up with a way to combine the first three commands into a single one.
The last montage step to place the intermediate results onto the background is not so easy to get right, and very likely will not save much time either.
Hence, I will leave that open for now.
Unfortunately you did not provide any link to your source images.
I had to create my own ones in order to answer this question.
They can also serve to demo the validity of my answer.
To create four 800x600 pixel sized PNGs, I used Ghostscript with a little bit of PostScript code on the command line:
for i in 1 2 3 4 ; do
gs -o t${i}.png \
-g800x600 \
-sDEVICE=pngalpha \
-c "0.5 setgray" \
-c "0 0 800 600 rectfill" \
-c "1 0 0 setrgbcolor" \
-c "3 setlinewidth" \
-c "10 10 780 580 rectstroke" \
-c "0 setgray" \
-c "/Helvetica-Bold findfont" \
-c "560 scalefont setfont" \
-c "230 60 moveto" \
-c "(${i}) show " \
-c "showpage" ;
done
Then I first tested your code with my images.
Here is the result from the OP's commands. The result is complete, including montage on a background image from my own stock (updated), created with a command inspired by Mark Setchell's answer:
convert -size 200x200 xc:gray +noise gaussian background.png
Merging the first two commands:
The following was my first shot in order to come up with a single command.
It should achieve the same result as your first two commands outputting line.png.
I already knew it wouldn't work exactly as expected in some aspects, but I still tried.
I tried it in order to see if there are other places of the command that would show problems that I didn't expect.
No worries, the explanation of the complete, final code will be at the end of the answer.
You can try to figure out how the following command works once you read the complete answer:
_col1=blue ;
_col2=red ;
convert t*.png -flop -resize 487x296\! \
\( -size 15x15 \
-clone 0 xc:${_col1} \
-clone 1 xc:${_col1} \
-clone 2 xc:${_col1} \
-clone 3 \
-append \
+write f.png \
\) null:
Here is the result of my command (right) compared to the intermediate result after your second command (left):
So, one thing I had expected happened: there is a blue spacer between each image.
I colorized it for debugging reasons.
This can be fixed by setting the color variable to none (transparent).
Things I hadn't expected and which I only discovered after opening the resulting image f.png:
My background was white instead of transparent.
This can be fixed by adding -background none at the right place.
My spacing of the individual images in the columns is too narraw, being 15 pixels only.
This is because in the intermediate file line.png of the OP the spacing is not 15 pixels, but 30 pixels.
His parameter -geometry +0+15 for the montage creating the columns does add the 15 pixels on top as well as on bottom of each image.
My command (using convert ... -append instead of montage) does not allow for additional -geometry settings which would have the same effect.
But his can be fixed by adding more xc:{_col1} spacers into my command.
Merging the first three commands:
So here is the next iteration.
It integrates the effect of the third command from the OP.
This is achieved by adding +duplicate for duplicating the first created column.
Then it adds +append to append the duplicate column horizontally (-append would do so vertically):
_col1=blue ;
_col2=red ;
convert t*.png -flop -resize 487x296\! \
\( -size 15x15 \
-background none \
xc:${_col1} \
-clone 0 xc:${_col1} xc:${_col1} \
-clone 1 xc:${_col1} xc:${_col1} \
-clone 2 xc:${_col1} xc:${_col1} \
-clone 3 \
xc:${_col1} \
-append \
+duplicate \
-size 45x45 xc:${_col2} \
+append \
+write f2.png \
\) null:
Again one thing I had expected happened:
The red spacer between the two columns was on the right instead of sitting in between the columns.
We can fix that by swapping the last two images that get +append-ed.
This can be done by adding the +swap operator at the right place.
Also, the same thing as with the inter-image spacing in the first column will apply to the spacing in bewteen the columns: I have to double it.
I will not care at the moment that the same space (45 pixels) is not added to the +append-ed columns left and right.
So here is one more iteration:
_col1=red ;
_col2=blue ;
convert t*.png -flop -resize 487x296\! \
\( -background none \
-size 15x15 \
xc:${_col1} \
-clone 0 xc:${_col1} xc:${_col1} \
-clone 1 xc:${_col1} xc:${_col1} \
-clone 2 xc:${_col1} xc:${_col1} \
-clone 3 \
xc:${_col1} \
-append \
+duplicate \
-size 90x90 xc:${_col2} \
+swap \
+append \
+write f3.png \
\) null:
Here is the result:
On the right is the intermediate photos.png created by the OP code after the third command.
On the left is the image montage created by my command.
What's missing now is an explanation with a breakdown of the individual operations I packed into a single command:
\( :
This opens a "sideways" processing of some of the images.
The result of this sideway processing is then again inserted into the main ImageMagick process.
The backslashes are required so the shell does not try to interpret them.
\) :
This closes the sideways processing.
-size 15x15 :
This sets the size of a canvas to be filled next.
xc:${_col1} :
This fills the canvas with color specified.
xc: is just an alias to canvas:, but it is faster to type.
-clone 0 :
This creates a copy of the first image that is currently in the loaded image stack.
In this case it is a copy of t1.png.
-clone 1 copies t2.png, -clone 2 copies t3.png, etc.
-clone or +clone work best inside sideway processing chains, hence the previously explained use of \( and \).
-append :
This operator appends all currently loaded images vertically.
In this case these are the 4 copies of t1.png, ... t4.png.
+duplicate :
This operator similar to +clone.
It copies the last image in the currently loaded image stack.
In this case the last image (and only remaining one inside the sideways pipeline) is the result of the previous -append operation.
This operation had created the first column of 4 images, spaced apart by the red spacers.
+append :
This operator appends all currently loaded images horizontally.
There are currently three images: the result of the -append operation, its copy created by +duplicate, and the 90x90 sized xc:-canvas.
+swap :
This operator swaps the last two images on the currently loaded stack.
+write :
This operator writes out all of the images from the currently loaded stack.
When there are multiple images, it will write these images with the given name, but with a number appended.
It's a great tool for debugging complex ImageMagick commands.
It is great because after the +write operation is finished, the previously loaded images remain all on the stack.
These images remain unchanged, and processing can continue.
However, we are finished now and won't continue in this case.
Hence we close the side-way process with a \).
null :
Now that we closed the sideway process, ImageMagick puts the resulting image from the sideway into the main pipeline again.
Remember, +write didn't finish the processing, it wrote an file to disk that is meant to be an intermediate result.
In the main pipeline, there are now still the original t1.png ... t4.png plus the result from the sideway processing.
However we will not do anything with them.
We will take the intermediate result from +write as our final one.
But the convert command expects to now see an output filename.
If it doesn't see one, it will complain and show us an error message.
Hence we tell it to write off all it has loaded and discard all images from the stack.
To achieve this, we use null: as output filename.
(If you feel adventurous, use out.png as a filename instead of null:.
You will see that ImageMagick actually creates multiple out-0.png, out-1.png,...out-3.png filenames.
You will find that out-4.png is the same as f.png, and out-{0,1,2,3}.png are the same as the input images. --
You could also replace null: by -append output.jpg and see what happens then...)
Update
Now for the speed comparison...
For a first rough benchmark, I did run the OP's first three commands in a loop with 100 iterations.
Then I did run my own command 100 times as well.
Here are the results:
OP first three commands, 100 times: 61.3 seconds
My single command replacing these, 100 times: 48.9 seconds
So my single command saved roughly 20% time over the original commands from the OP.
Given that my disk I/O performance can be assumed to be pretty fast (the test system has an SSD) in comparison with a spinning harddisk, the speed gain from the merged command (which avoids too many temporary file write/reads) may be more distinct on a system with a slower disk.
To check if a little re-architecture of the command (where not so many loaded images are simply discarded at the end, as can be seen by the null: output file name) would gain more improvements, I also tried this:
convert t*.png -flop -resize 487x296\! \
-background none \
-size 0x15 \
xc:red \
-duplicate 7 \
-insert 0 \
-insert 2 \
-insert 3 \
-insert 5 \
-insert 6 \
-insert 8 \
-insert 9 \
-append \
\( +clone -size 45x0 xc:blue +swap \) \
+append \
f4.png
The architecture of this command is a bit different.
First, it loads all the images. It -flops them and it -resizes them.
Second, it creates a single 15x15 pixels canvas, which then is also placed on the image stack.
Third, it creates 7 additional copies of that canvas.
Now there are 12 images on the stack:
the 4 input files, 1 xc:-canvas, and 7 copies of the canvas.
Then, it uses a series of -insert N operations.
The -insert N operation manipulates the order of the image stack.
It removes the last image from the stack and inserts it into image index position N.
When the -insert series of operations starts, there are 4 images (t1, t2, t3, t4) on the stack, plus 8 "spacers" (s).
This is their original order:
index: 0 1 2 3 4 5 6 7 8 9 10 11
image: t1 t2 t3 t4 s s s s s s s s
I've picked the index numbers in a way so that from above original order the changed new order after all -insert N operations are finished is:
index: 0 1 2 3 4 5 6 7 8 9 10 11
image: s t1 s s t2 s s t3 s s t4 s
Since all spacers s are 15 pixels wide, this achieves the same spacing as my initial command.
Next, a similar sideway processing happens: this time to +clone the result of the previous -append operation and to create the horizontal spacer.
Last, the +append (which operates on the result from the previous -append and from the sideway-process) creates the final result, f4.png.
When I benchmarked this last command, I got the following results for 100 repetitions of each command:
My first command before the update, 100 times: 48.3 seconds
My last command explained after the update, 100 times: 46.6 seconds
So the speed gain is not quite so notable, roughly 3% better if you want to trust these numbers.
(It should be noted, that I did run both loops in parallel on the same machine to create more fairness in the benchmarking competition.
By running in parallel, they both have to deal with the same CPU and I/O load which may be caused by themselves as well as by other processes happening on the machine concurrently.)
As I don't have your images or your texture or their sizes, I will show you something similar for you to adapt...
Make some input images:
convert -size 500x400 xc:black 1.png
convert -size 500x400 xc:red 2.png
convert -size 500x400 xc:green 3.png
convert -size 500x400 xc:blue 4.png
and a background texture:
convert -size 2000x2000 xc:gray +noise gaussian background.png
Now do what you asked, but without intermediate files to disk:
montage [1234].png -background none -tile 1x4 -geometry +0+15 miff:- |
convert -background none :- -size 15 xc:none -clone 0 +append png: |
convert -gravity center background.png :- -composite z.png
The first line lays out the 4 images one above the other, and sends the combined result in a MIFF (Mutiple Image File Format) through a pipe to the next command. The second command reads an image from the pipe and appends a 15 pixel wider "spacer" and then duplicates the first column of images (with clone) and writes as a PNG to the next command through another pipe. The final command reads the 8 small images combined and puts them on a background, centred.
If the right hand column of images is supposed to be the left column reflected - it's hard to tell from your poor example which shows flat black boxes - you may need to change the second line of the command from
convert -background none :- -size 15 xc:none -clone 0 +append png: |
to
convert -background none :- -size 15 xc:none \( -clone 0 -flop \) +append png: |
Here is another answer. It took inspiration from Mark Setchell's approach. Here I come up with a new command pipeline. The difference is, that I...
...use exclusively 3 montage commands in a pipeline (Mark used 1 montage and 2 converts in his pipeline), and I
...reproduce exactly the output of the OP's 3 different commands.
As input I used the four images created by the Ghostscript command in my other answer, t{1,2,3,4}.png.
To create a suitable background image I used the command from Mark, though modified: I made the image a tad bit smaller, so that the -texture operator from the OP could by meaningfully used:
convert -size 200x200 xc:gray +noise gaussian background.png
Then I benchmarked all three commands/scripts,...
...the OP commands as a shell script,
...the approach of Mark, albeit modified as outlined above,
...my initial approach, amended with adding the background image.
For benchmarking, I did run 100 repetitions each.
When doing so, I started each script/command in a separate terminal window, roughly at the same time.
The CPU on the test machine has 4 cores.
So when the commands were running in parallel, they had to deal with the same CPU- and I/O-load each, competing with each other for resources.
This is the most "fair" ad-hoc performance testing setup I could come up with.
I also confirmed that the output files created by the 3 tests (photo_test1.jpg, ms+kp_test2.jpg and kp_test3.jpg) are pixelwise (almost) identical.
If the output is switched to PNG (instead of JPEG, how the OP asked for), then these small differences also disappear between the 3 approaches.
Here are the results:
Script using 4 commands from the original post (OP):
mkdir ./imagesResized
time for i in {1..100}; do
convert t*.png -resize 487x296\! -flop \
-set filename:f "./imagesResized/%t%p" '%[filename:f]'.png
montage ./imagesResized/*.png -tile 1x4 -geometry +0+15 \
-background none line.png
montage line.png line.png -tile 2x1 -geometry +45+0 \
-background none photos.png
montage photos.png -geometry +20+247 \
-texture background.png \
photo_test1.jpg
done
Results:
real 2m13.471s
user 1m54.306s
sys 0m14.340s
Roughly 133 seconds in real time.
Take this as 100% time consumption.
Modified command pipeline inspired by Mark's answer:
time for i in {1..100}; do
montage t[1234].png -resize 487x296\! -flop -background none \
-tile 1x4 -geometry +0+15 miff:- \
| montage :- -background none -clone 0 -tile 2x1 -geometry +45+0 miff:- \
| montage :- -geometry +20+247 -texture background.png ms+kp_test2.jpg ;
done
Results:
real 1m50.125s
user 1m32.453s
sys 0m16.578s
Roughly 110 seconds.
About 83% time consumption compared to original commands.
My original command, now completed with missing background compositing:
time for i in {1..100}; do
convert t*.png -flop -resize 487x296\! \
-background none \
-size 0x15 \
xc:white \
-duplicate 7 \
-insert 0 \
-insert 2 \
-insert 3 \
-insert 5 \
-insert 6 \
-insert 8 \
-insert 9 \
-append \
\( +clone -size 90x0 xc:white +swap \) \
+append \
-transparent white \
miff:- \
| montage :- -geometry +65+247 -texture background.png kp_test3.png
done
Results:
real 1m34.786s
user 1m20.595s
sys 0m13.026s
Roughly 95 seconds.
About 72% time consumption compared to original commands.

Imagemagick not outputting reflection on windows

I am trying to do the same as described here http://www.imagemagick.org/Usage/advanced/#reflections
I am using imagemagick on windows and the command I am using is like this -
convert test3.jpg -alpha on -virtual-pixel transparent -clone 0 +distort Perspective "0,0,100,50 0,394,100,344 300,394,300,394 394,0,394,0" -clone 0 -channel A -evaluate multiply .35 +channel +distort Perspective "0,0,100,-50 0,394,100,344 300,394,300,394 394,0,394,0" -delete 0 +swap -background none -layers merge +filter -size "594x500^!" xc:none +swap -gravity North -geometry +0+5 -composite reflect_distort_new.jpg
The actual image is
The result I am getting is like this -
I was wondering if any one can help me fixing the following issues -
I want to add a reflection as explained in the example, but it does not appear with my command line. I have removed parenthesis from the -clone command as it was giving error on windows.
How to remove the black background being added there?
How to apply antialising as there are edges on the resultant image.
Ah Well, after trying 1000+ times, I got it correct -
convert magCover1.png -alpha on -virtual-pixel transparent ^
( +clone -flip -channel A -evaluate multiply .35 +channel ) -append ^
+distort Perspective "0,0,200,100 0,788,200,788 600,788,600,850 788,0,740,50" ^
-gravity North -crop "1094x1000+0-5^!" ^
-background none -compose Over -flatten -transparent white reflect_distort.png
I get the following result -

Create a bitonal image for OCR using Image Magick

nice /usr/local/bin/convert \
-colors 2 \
-colorspace gray \
-compress group4 \
/var/www/html/uploads/pokemon.jpg \
/var/www/html/uploads/pokemontest.jpg
This command worked with a really OLD version of Image Magick.
With the newest version this method produces a completely black image.
nice /usr/local/bin/convert \
-colorspace gray \
-compress group4 \
/var/www/html/uploads/pokemon.jpg \
/var/www/html/uploads/pokemontest.jpg
nice /usr/local/bin/convert \
-colors 2 \
/var/www/html/uploads/pokemontest.jpg \
/var/www/html/uploads/pokemontestfinal.jpg
This results in a bitonal gray and black image, but it's really rough. NOT clean at all.
You could try a simple
convert input.jpg -threshold 50% output.jpg
(and play a bit with variations of the 50% setting) and see if this gets you any further.
Also, you may want to have a look at these answers:
Image Preprocessing steps to improve the recognition rate

Resources