Print pixel values where images differ with imagemagick? - imagemagick

Is there an easy way to print the pixel value where two images differ using imagemagick?
To be clear, I want to know what the value of that pixel is, as well as its coordinate. It doesn't matter from which image, since I can simply swap them to get the right one.

Let's make two images, both 3px wide and 1px tall:
convert xc:red xc:lime xc:blue +append 1.png
convert 1.png -flop 2.png
If we do the following, we can make any pixels that are identical in the two images become transparent:
convert {1,2}.png -compose changemask -composite mask.png # Note that {1,2}.png is just bash shorthand for "1.png" "2.png"
And if we re-order the input images:
convert {2,1}.png -compose changemask -composite mask.png # Note that {2,1}.png is just bash shorthand for "2.png" "1.png"
So, I assume you want the above, but in text format with the transparent pixels suppressed:
convert {1,2}.png -compose changemask -composite txt: | grep -v ",0)"
Output
# ImageMagick pixel enumeration: 3,1,65535,srgba
0,0: (65535,0,0,65535) #FF0000FF red
2,0: (0,0,65535,65535) #0000FFFF blue
Note that if you want to permit a small difference between the images, you can add some "fuzz-factor". So, if you want rgb(0,100,200) to be considered near enough equal to rgb(3,96,205), you could add -fuzz 5 at the start of the command.

In Imagemagick 6, you can do the following to list the coordinates where the two images differ:
convert image1 image2 -compose difference -composite -threshold 0 txt: | tail -n +2 | grep "white" | awk '{print $1}' | sed 's/://g'
If using Imagemagick 7, change convert to magick
ADDITION:
If you want both the coordinates and the color in one of the two images, then assuming the image has no perfect black pixels, you can do the following:
convert image1 image2 \
\( -clone 0,1 -compose difference -composite -threshold 0 \) \
-delete 1 \
-compose multiply -composite txt: |\
tail -n +2 | grep -v "black" | awk '{print $1,$4}'
For example, I take the lena image and put a blue square in the top left corner to make a second image.
Input:
convert lena.png \( -clone 0 -size 5x5 xc:blue -composite \) \
\( -clone 0,1 -compose difference -composite -threshold 0 \) \
-delete 1 \
-compose multiply -composite txt: |\
tail -n +2 | grep -v "black" | awk '{print $1,$4}'
Results:
0,0: srgb(226,137,124)
1,0: srgb(224,137,130)
2,0: srgb(225,135,121)
3,0: srgb(228,134,121)
4,0: srgb(227,138,125)
0,1: srgb(226,137,124)
1,1: srgb(224,137,131)
2,1: srgb(225,135,121)
3,1: srgb(228,134,121)
4,1: srgb(227,138,126)
0,2: srgb(226,138,124)
1,2: srgb(224,136,127)
2,2: srgb(225,135,120)
3,2: srgb(228,134,121)
4,2: srgb(227,137,121)
0,3: srgb(228,137,122)
1,3: srgb(225,134,114)
2,3: srgb(225,134,118)
3,3: srgb(229,132,112)
4,3: srgb(227,133,113)
0,4: srgb(224,130,109)
1,4: srgb(223,132,110)
2,4: srgb(224,132,116)
3,4: srgb(226,131,112)
4,4: srgb(226,134,117)
If you do have black and the images have no transparency, then you can do:
convert image1 image2 \
\( -clone 0,1 -compose difference -composite -threshold 0 \) \
-delete 1 \
-alpha off -compose copy_opacity -composite \
-background black -alpha background txt: |\
tail -n +2 | grep -v "none" | awk '{print $1,$4}'
For example:
convert lena.png \( -clone 0 -size 5x5 xc:blue -composite \) \
\( -clone 0,1 -compose difference -composite -threshold 0 \) \
-delete 1 \
-alpha off -compose copy_opacity -composite \
-background black -alpha background txt: |\
tail -n +2 | grep -v "none" | awk '{print $1,$4}'
Results:
0,0: srgba(226,137,124,1)
1,0: srgba(224,137,130,1)
2,0: srgba(225,135,121,1)
3,0: srgba(228,134,121,1)
4,0: srgba(227,138,125,1)
0,1: srgba(226,137,124,1)
1,1: srgba(224,137,131,1)
2,1: srgba(225,135,121,1)
3,1: srgba(228,134,121,1)
4,1: srgba(227,138,126,1)
0,2: srgba(226,138,124,1)
1,2: srgba(224,136,127,1)
2,2: srgba(225,135,120,1)
3,2: srgba(228,134,121,1)
4,2: srgba(227,137,121,1)
0,3: srgba(228,137,122,1)
1,3: srgba(225,134,114,1)
2,3: srgba(225,134,118,1)
3,3: srgba(229,132,112,1)
4,3: srgba(227,133,113,1)
0,4: srgba(224,130,109,1)
1,4: srgba(223,132,110,1)
2,4: srgba(224,132,116,1)
3,4: srgba(226,131,112,1)
4,4: srgba(226,134,117,1)

Related

Crop page from facing-page scan

Suppose I want to crop just the left pages from facing-page scans of a spiral notebook like the example below (from Paolini.net).
Is there a more robust way than simply dividing the image's width by half? For example, a smarter algorithm would detect the spiral binding and make that the right boundary and even exclude black area to the left of the page.
If there's a relatively easy way to do this with OpenCV or ImageMagick, I'd love to learn it.
One possible way in ImageMagick 6 with Unix scripting is to do the following:
Trim the image to remove most of the black on the sides
Scale the image down to 1 row, then scale up to 50 rows just for visualization
Threshold the scaled image so that you get the black region down the spine as the largest black region
Do connected components process to find the x coordinate of the largest black region
Crop the image according to the results from the connected components
Input:
convert img.jpg -fuzz 25% -trim +repage img_trim.png
convert img_trim.png -scale x1! -scale x50! -threshold 80% img_trim_x1.png
centx=$(convert img_trim_x1.png -type bilevel \
-define connected-components:mean-color=true \
-define connected-components:verbose=true \
-connected-components 4 null: | \
grep "gray(0)" | head -n 1 | awk '{print $3}' | cut -d, -f1)
convert img_trim.png -crop ${centx}x+0+0 img_result.jpg
Data from connected components has the following header and structure:
Objects (id: bounding-box centroid area mean-color):
So head -n 1 gets the first black, i.e. gray(0) region which is the largest (sorted largest to smallest). The awk prints the 3rd entry, centroid, and the cut gets the x component.
If using ImageMagick 7, then change convert to magick
If you want to exclude the binders in the middle, then use the x-offset of the bounding box from the connected components listing:
convert img_trim.png -scale x1! -scale x50! -threshold 80% img_trim_x1.png
leftcenterx=$(convert img_trim_x1.png -type bilevel \
-define connected-components:mean-color=true \
-define connected-components:verbose=true \
-connected-components 4 null: | \
grep "gray(0)" | head -n 1 | awk '{print $2}' | cut -d+ -f2 | cut -d+ -f1)
convert img_trim.png -crop ${leftcenterx}x+0+0 img_result2.jpg
If you want just both pages, then we can find the white regions, i.e. gray(255) and crop them according to the width and x offset from the bounding boxes.
convert img.jpg -fuzz 25% -trim +repage img_trim.png
convert img_trim.png -scale x1! -scale x50! -threshold 80% img_trim_x1.png
OLDIFS=$IFS
IFS=$'\n'
bboxArr=(`convert img_trim_x1.png -type bilevel \
-define connected-components:mean-color=true \
-define connected-components:area-threshold=100 \
-define connected-components:verbose=true \
-connected-components 4 null: | \
grep "gray(255)" | awk '{print $2}'`)
IFS=$OLDIFS
num=${#bboxArr[*]}
for ((i=0; i<num; i++)); do
WW=`echo ${bboxArr[$i]} | cut -dx -f1`
Xoff=`echo ${bboxArr[$i]} | cut -d+ -f2`
convert img_trim.png -crop ${WW}x+${Xoff}+0 img_result3_$i.jpg
done

Bold Table Bars Removal using ImageMagick

I have an Invoice Image which contains table bars as below example.
I am using ImageMagick to pre-process Images using the below command.
convert 0.png -type Grayscale -negate -define morphology:compose=darken -morphology Thinning 'Rectangle:1x80+0+0<' -negate 0.png
My Problem is that output with horizontal bold bars. ImageMagick fails to convert it correctly and output as below.
What can I do to solve this?
Here is a different way using ImageMagick and connected components. First trim the image to remove the outer white, then use connected components to get the id of the largest black region, which should be id=0. The run it again removing the id of the largest area making it transparent and finally flattening the result against white. Then add the thinning operation to remove the horizontal lines that were not fully black. See https://imagemagick.org/script/connected-components.php
convert image.png -fuzz 5% -trim +repage \
-bordercolor black -border 1 \
-define connected-components:verbose=true \
-define connected-components:mean-color=true \
-connected-components 4 \
null:
Objects (id: bounding-box centroid area mean-color):
0: 953x205+0+0 478.7,65.6 31513 srgba(0,0,0,1)
10789: 943x19+5+184 488.4,193.1 16885 srgba(255,255,255,1)
1: 465x17+5+1 237.0,9.0 7905 srgba(255,255,255,1)
2: 474x17+474+1 733.5,9.0 7096 srgba(255,255,255,1)
3820: 281x21+667+67 807.0,76.9 5609 srgba(255,255,255,1)
5195: 281x21+667+90 807.0,99.9 5609 srgba(255,255,255,1)
7959: 281x20+667+137 807.0,146.4 5328 srgba(255,255,255,1)
9341: 281x20+667+160 807.0,169.5 5328 srgba(255,255,255,1)
6540: 281x20+667+114 807.0,123.4 5295 srgba(255,255,255,1)
2375: 281x19+667+46 807.0,55.0 5047 srgba(255,255,255,1)
...
convert image.png -fuzz 5% -trim +repage \
-bordercolor black -border 1 \
-define connected-components:remove=0 \
-define connected-components:mean-color=true \
-connected-components 4 \
-background white -flatten \
-negate \
-define morphology:compose=darken \
-morphology Thinning 'Rectangle:1x80+0+0<' \
-negate \
result.png

Multiple converts from one source using imagemagick

Is it possible to have one source and from that have 2 types of processed images with different configurations? (and not to read the source image twice)?
Something like
convert input.jpg -resize 300 output1.jpg -resize 600 output2.jpg
Sure, use an intermediate -write like this, and do the big one first:
convert input.jpg -resize 600 -write im600.jpg -resize 300 im300.jpg
Or, if you want to start afresh with each operation:
convert input.png \
\( +clone -resize 300 -write result300.jpg \) \
\( +clone -resize 600 -write result600.jpg \) null:
If using GraphicsMagick, I am not sure if there is a better way than the following:
#!/bin/bash
{ echo convert input.png mpr:orig;
echo convert mpr:orig -resize 300 result300.jpg;
echo convert mpr:orig -resize 600 result600.jpg; } | gm batch -prompt off
This is a slightly different version that only invokes convert twice:
#!/bin/bash
cat - <<EOF | gm batch -prompt off
convert input.png -write mpr:orig -resize 300 result300.jpg
convert mpr:orig -resize 600 result600.jpg
EOF

Imagemagick (convert: pixels are not authentic)

I have a command-line that outputs an image as intended but gives me an error on completion of convert: pixels are not authentic. Why could this be happening?
I am using ImageMagick 6.9.2-8 Q16 x86_64 2015-12-06 in Term2 on OSX El Capitan.
The command / output / error :
convert -verbose artwork.jpg -resize 1800x \
\( +clone -gravity center -background white -extent 2000x2000 \) \
\( -clone 1 displaceY.png -compose displace -define compose:args=0x5% -composite \) \
\( -clone 2 -gravity west displaceX.png -compose displace -define compose:args=5x0% -composite \) \
-delete 0--2 \( +clone alpha.png -compose copy_opacity -composite \) -delete 0 out.png
artwork.jpg JPEG 2952x2124 2952x2124+0+0 8-bit sRGB 911KB 0.000u 0:00.000
displaceY.png PNG 2000x2000 2000x2000+0+0 8-bit sRGB 109KB 0.000u 0:00.000
displaceX.png PNG 2400x2400 2400x2400+0+0 8-bit sRGB 104KB 0.000u 0:00.000
alpha.png PNG 2000x2000 2000x2000+0+0 8-bit sRGB 63.9KB 0.000u 0:00.000
artwork.jpg=>out.png JPEG 2952x2124=>2000x2000 2000x2000+0+0 8-bit sRGB 572KB 0.000u 0:00.000
convert: pixels are not authentic `artwork.jpg' # error/cache.c/QueueAuthenticPixelCacheNexus/4017.
It's hard to debug without the files and without knowing what you are trying to achieve, but I'll say what I see and maybe that will help. Here is what I think you have in the various layers:
0 - artwork 1800px wide
1 - artwork extended to 2000x2000
2 - clone of (1)
3 - clone of (2)
and then we come to the last line... and you delete 0--2 which is suspicious, did you mean 0-2, because 0--2 is actually 0,1.
So what did you mean to have in your image list after this -delete 0--2, I mean, how many images? I guess you meant to have 1 left.
Then you clone it, why do you do that? You could just copy the opacity right onto it and then you wouldn't need a -delete at the end?
No one can answer why this may have been happening but most could agree there is a better way of doing it, a few of these produce no error. It seems to be related to using clone request after a certain point in the chain.
Here are two commands that resolve this issue and provide the correct output image:
convert artwork.jpg +repage -thumbnail 1800x -gravity center -background white -extent 2000x2000 \
-gravity northwest displaceY.png +repage -compose over -compose displace -define compose:args=0x5% -composite \
-gravity northwest displaceX.png +repage -compose over -compose displace -define compose:args=5x0% -composite \
-gravity center alpha.png -compose over -compose copy_opacity -composite final.png
or
convert artwork.jpg +repage -thumbnail 1800x -gravity center -background white -extent 2000x2000 \
-gravity northwest displaceX.png displaceY.png +repage -compose over -compose displace -define compose:args=0x5% -composite \
-gravity center alpha.png -compose over -compose copy_opacity -composite final.png
Thanks to Fred over in the ImageMagick forums.

Transparent PNGs and a JPEG combine in ImageMagick

I have a case where I need to combine two transparent layers on top of JPEG files.
Here a sample setup:
wget -O bg.jpg http://www.grahamowengallery.com/photography/Flowers/roadside-flowers.jpg
wget -O layer.png http://www2.picturepush.com/photo/a/6271450/640/TRANSPARENT-EMBELLISHMENTS/pink-flower-transparent-png.png
wget -O logo.png http://upload.wikimedia.org/wikipedia/commons/0/0d/Imagemagick-logo.png
I can get desired result with commands:
composite bg.jpg \( -compose Overlay layer.png \) bg2.jpg
composite bg2.jpg \( -compose Overlay logo.png \) result.jpg
This is good, but I want to avoid writing bg2.png to drive.
I tried:
composite bg.jpg \( -compose Overlay layer.png \) \( -compose Overlay logo.png \) result2.jpg
but this results on layer.png on black background. How can I fix this?
I couldn't make composite working, but convert works:
convert.exe bg.jpg layer.png -compose Overlay -composite logo.png -compose Overlay -composite result2.jpg
Further reading: http://www.imagemagick.org/Usage/compose/
I can not test this at the moment but you may be able to use layers merge and you should be able to use the URLs in your code.
$cmd = "http://www.grahamowengallery.com/photography/Flowers/roadside-flowers.jpg ".
" http://www2.picturepush.com/photo/a/6271450/640/TRANSPARENT-EMBELLISHMENTS/pink-flower-transparent-png.png ".
" http://upload.wikimedia.org/wikipedia/commons/0/0d/Imagemagick-logo.png -layers merge ";
exec(" convert $cmd result.jpg ");
You are not using any positioning for your layers - are you going to introduce that later? If so you can add -page +0+0 in front of each image to locate them where you want. +0+0 would be changed to the location.

Resources