how to search an image for subimages on linux - imagemagick

i've seen the answer of Mark Setchell (https://stackoverflow.com/users/2836621/mark-setchell), which seems to be outdated and not working anymore. How to search an image for subimages using linux console?
https://stackoverflow.com/a/31874879/17686212
How to search an image for subimages using linux console?
downloading the needle and creating the haystack image and "hiding" the needles within it works fine.
Needle Image
convert -size 256x256 gradient:lime-blue haystack.png
convert haystack.png needle.png -geometry +30+5 -composite haystack.png
convert haystack.png needle.png -geometry +100+150 -composite haystack.png
Running the specified compare Images command causes an error:
compare -metric RMSE -subimage-search haystack.png needle.png locations.png
compare: images too dissimilar `haystack.png' # error/compare.c/CompareImagesCommand/1166.
i've tried to apply -similarity-threshold and -dissimilarity-threshold and changed/lowered the convert location threshold but had no success aka bad results like this:
compare -similarity-threshold 0 -dissimilarity-threshold 1 -metric RMSE -subimage-search haystack.png needle.png locations.png
convert locations-1.png -threshold 95% txt: | grep white
locations-0.png
locations-1.png
I've used imagemagick version 7.1.0.14 on gentoo and 6.9.11.60+dfsg-1.3 on kali Linux
Hopefully you can help me to resolve this issue.

Here is how to do masked composite in ImageMagick 7.
Template:
Image:
Create Mask:
magick needle.png -transparent white -alpha extract mask.png
magick compare -metric rmse -subimage-search -dissimilarity-threshold 1 haystack.png \( -read-mask mask.png needle.png \) compare.png
9031.97 (0.137819) # 100,150
Compare-0 (differences):
Compare-1 (match scores):
If you want to find the best matches, you would need to use my script, maxima
maxima -t 80 -n 10 compare-1.png
max=1 100,150 gray=56540,220,86.2745%
max=2 30,5 gray=54484,212,83.137%
You will not get a good result from ImageMagick 6 with
compare -metric rmse -subimage-search -dissimilarity-threshold 1 haystack.png needle.png compare.png
26789 (0.408773) # 96,114
because there is too much white in your needle image and it will mismatch with the green and blue in the haystack image. Unfortunately, you cannot do masked compare in ImageMagick 6.

Related

How to preserve red color only using ImageMagick command line

I have the following image:
What I want is to preserve only red color and desaturate
every other color into grayscale. Resulting in this:
How can I do that with Imagemagick command line?
I tried this but failed:
convert original.png \( -clone 0 -transparent red -alpha extract -transparent black \) redonly.png
Here is one way, though not perfect, using ImageMagick. I specify hue=0 deg for red and tolerance=25 deg both in range 0 to 360.
Input:
hue=0
tolerance=25
toler=`convert xc: -format "%[fx:(100*$tolerance/360)]" info:`
hueval=`convert xc: -format "%[fx:50-$hue]" info:`
thresh=`convert xc: -format "%[fx:100-$tolerance]" info:`
convert tomato.jpg \
\( -clone 0 -colorspace gray -colorspace sRGB \) \
\( -clone 0 -colorspace HSL -channel 0 -separate +channel \
-evaluate AddModulus ${hueval}% \
-solarize 50% -level 0x50% \
-threshold $thresh% \) \
-swap 0,1 -alpha off -compose over -composite \
result.jpg
Also not perfect, but fairly easy to understand. Basically, you could use the fx operator to inspect the Hue of each pixel and, depending on its Hue/colour, return either the original pixel or its greyscale equivalent.
So, as a first stab, you might do this to replace all pixels exhibiting a high Hue value with their greyscale (lightness) equivalent:
magick ripe.jpg -fx "(u.hue<0.1)? u : u.lightness" result.jpg
Then you might realise that red Hues wrap around at 0/360 degrees on the Hue circle, so you could do:
magick ripe.jpg -fx "(u.hue<0.1)||(u.hue>0.9)? u : u.lightness" result.jpg
Explanation
There are a couple of things going on here. Firstly, the -fx operator is a very low-level, extremely powerful (and sadly rather slow because it is interpreted) way of running a piece of "code" on every pixel in the image. Secondly, I am running a ternary operator with the format:
condition? valueA : valueB
so I am testing a condition for every pixel, and if true I return valueA, and if false I return valueB. When I refer to u and u.hue and u.lightness, the u means the first image in my command - I could load two images and use features of the first to select features of the second, then I would use u and v to differentiate. Finally, the values are scaled on the range [0,1] so I don't test for "Hue>350 in the range [0,360]", instead I test for Hue>0.9 as a sloppy equivalent - I guess I could have used Hue>(350/360). Note that you can make the expression arbitrarily complicated and also put it in a separate file to re-use it like this:
magick ripe.jpg -fx #DeSatNonRed.fx result.jpg
DeSatNonRed.fx might look something like this:
hueMin=350/360;
hueMax=20/360;
(hue>hueMin) || (hue<hueMax) ? u : u.lightness
Note that, in the general case, you should also really consider Saturation when looking at Hues, which you can add in above, but which I omitted for clarity, and because your image is almost fully saturated anyway.
Keywords: Image processing, ImageMagick, low-level fx operator, ternary, pixel-by-pixel, evaluate, expression.

ImageMagick - Make a color semi-transparent

I am trying to overlay image1 over image2. I want to make a color in image1 semi-transparent. So far I have only been able to overlay image1 over image2 using
composite -gravity north image2.png image1.png image3.png
How do I make a color (grey in this case) in image1 semi-transparent before overlaying it over image2?
I am using:
Version: ImageMagick 7.0.8-23 Q16 x86_64 2019-01-09
Thnx
Let's make an overlay (image2.png) first, with 3 progressively lighter shades of grey starting with 80/255 on the left, 128/255 in the middle and 200/255 on the right:
convert -size 200x438 xc:"gray(80,80,80)" xc:gray xc:"gray(200,200,200)" +append image2.png
Assuming our starting image is this:
We can now make precisely mid-grey into semi-transparent mid-grey and overlay like this:
convert bean.jpg \( image2.png -fill "rgba(128,128,128,0.5)" -opaque gray \) -composite result.png
Or, if we want to also affect the grey(80), we can incorporate some fuzz:
convert bean.jpg \( image2.png -fill "rgba(128,128,128,0.5)" -fuzz 20% -opaque gray \) -composite result.png
Note that at Version 7 of ImageMagick, the commands changed:
Version 6 | Version 7
=================================
identify | magick identify
convert | magick
mogrify | magick mogrify
composite | magick composite
montage | magick montage
compare | magick compare
animate | magick animate
stream | magick stream
The order of parameters is also stricter, favouring:
magick [settings] INPUT [settings] [operators] OUTPUT
over:
convert [settings] [operators] INPUT [settings] [operators] OUTPUT
What I mean is that you are expected to load an image prior to applying operators to it, rather than to build up a list of operators and then load an image and hope ImageMagick remembers what you said you wanted done if you ever loaded anything.

Multiple resize operations in ImageMagick

I'm trying to combine some operations using ImageMagick's magick CLI, specifically two operations that resize/scale the image, a random one that does -resize and a bunch of other stuff, plus the answer from this question (Average image color excluding transparency with Imagemagick).
The naive "mix everything together" doesn't work:
magick image -resize 10x10 ... -scale 1x1! -alpha off -format "%[pixel:u.p]\n" info:
...as I get an answer of "black", because this is obviously ignoring my image and using a blank image instead.
I've also tried with subimages (using \( ... \)) but that has the same problem
The following command works fine for me on ImageMagick 6.9.10.16 Q16. What is your ImageMagick version and what other commands do you need in the command line. You only show ...! What else is there? Also can you post your image? You cannot just put "image" in your command line. You have to specify the actual image file and possibly the path to it.
Input:
convert logo.png -transparent white -resize 50% -scale 1x1! -alpha off -format "%[pixel:u.p]" info:
srgb(100,82,99)
Same with IM 7.0.8.16 Q16 HDRI:
magick logo.png -transparent white -resize 50% -scale 1x1! -alpha off -format "%[pixel:u.p]" info:
srgb(100,81,99)
The slight difference is likely a difference from precision with IM 6 (non-hdri) and IM 7 (with hydra).

Extracting data digitally

I have 200 copies of this page(15 * 10 matrix) and i have to write all the numbers from 0 - 9 in each corresponding cell and then extract those digits digitally in a seperate image of (32*32 pixels) for each digit, after scanning each page once. How can i achieve this? This is required for my research purpose. I am a CS student so i can code too.
Update:
For mark : Here is one of the scanned image
This is for some local language ( 0 - 9) ..
Update 2:
The commands for the previous image are working fine but on new images,something is getting wrong(some kind of offsets)..
I am attaching the image below
What changes do u suggest ?
Updated Answer
I have taken your feedback and improved the algorithm to the following bash script now...
#!/bin/bash
################################################################################
# dice
#
# Trim borders off an image (twice) and then dice into 10x15 cells.
#
# Usage: ./dice image
################################################################################
# Pick up image name from first parameter
image="$1"
echo DEBUG: Processing image $image...
# Apply median filter to remove noisy black dots around image and then get the
# dimensions of the "trim box" - note we don't use the (degraded) median-filtered image in
# later steps.
trimbox=$(convert "$image" -median 9x9 -fuzz 50% -format %# info:)
echo DEBUG: trimbox $trimbox
# Now trim original unfiltered image into stage1-$$.png (for debug)
convert "$1" -crop $trimbox +repage stage1-$$.png
echo DEBUG: Trimmed outer: stage1-$$.png
# Now trim column headings
convert stage1-$$.png -crop 2000x2590+120+190 +repage stage2-$$.png
echo DEBUG: Trimmed inner: stage2-$$.png
# Now slice into 10x15 rectangles
echo DEBUG: Slicing and dicing
convert stage2-$$.png -crop 10x15# +repage rectangles-%03d.png
# Now trim the edges off the rectangles and resize all to a constant size
for f in rectangles*png; do
echo DEBUG: Trimming and resizing $f
trimbox=$(convert "$f" -median 9x9 -shave 15x15 -bordercolor black -border 15 -threshold 50% -floodfill +0+0 white -fuzz 50% -format %# info:)
echo DEBUG: Cell trimbox $trimbox
convert "$f" -crop $trimbox +repage -resize 32x32! "$f"
done
Here are the resulting cells - i.e. 150 separate image files. I have put a red border around the individual cells/files so you can see their extent:
Original Answer
I would do that with ImageMagick which is free and installed on most Linux distros and is available for OSX and Windows too. There are Perl, PHP, Java, node, .NET, Ruby, C/C++ bindings too if you prefer those languages. Here I am using the command line in Terminal.
First job is to get rid of noise and trim the outer edges:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage trimmed1.png
Now, trim again to get rid of outer frame and column titles across the top:
convert trimmed1.png -crop 2000x2590+120+190 +repage trimmed2.png
Now divide into 10 cells by 15 cells and save as rectangles-nnn.png
convert trimmed2.png -crop 10x15# rectangles-%03d.png
Check what we got - yes, 150 images:
ls -l rect*
rectangles-000.png rectangles-022.png rectangles-044.png rectangles-066.png rectangles-088.png rectangles-110.png rectangles-132.png
rectangles-001.png rectangles-023.png rectangles-045.png rectangles-067.png rectangles-089.png rectangles-111.png rectangles-133.png
rectangles-002.png rectangles-024.png rectangles-046.png rectangles-068.png rectangles-090.png rectangles-112.png rectangles-134.png
rectangles-003.png rectangles-025.png rectangles-047.png rectangles-069.png rectangles-091.png rectangles-113.png rectangles-135.png
rectangles-004.png rectangles-026.png rectangles-048.png rectangles-070.png rectangles-092.png rectangles-114.png rectangles-136.png
rectangles-005.png rectangles-027.png rectangles-049.png rectangles-071.png rectangles-093.png rectangles-115.png rectangles-137.png
rectangles-006.png rectangles-028.png rectangles-050.png rectangles-072.png rectangles-094.png rectangles-116.png rectangles-138.png
rectangles-007.png rectangles-029.png rectangles-051.png rectangles-073.png rectangles-095.png rectangles-117.png rectangles-139.png
rectangles-008.png rectangles-030.png rectangles-052.png rectangles-074.png rectangles-096.png rectangles-118.png rectangles-140.png
rectangles-009.png rectangles-031.png rectangles-053.png rectangles-075.png rectangles-097.png rectangles-119.png rectangles-141.png
rectangles-010.png rectangles-032.png rectangles-054.png rectangles-076.png rectangles-098.png rectangles-120.png rectangles-142.png
rectangles-011.png rectangles-033.png rectangles-055.png rectangles-077.png rectangles-099.png rectangles-121.png rectangles-143.png
rectangles-012.png rectangles-034.png rectangles-056.png rectangles-078.png rectangles-100.png rectangles-122.png rectangles-144.png
rectangles-013.png rectangles-035.png rectangles-057.png rectangles-079.png rectangles-101.png rectangles-123.png rectangles-145.png
rectangles-014.png rectangles-036.png rectangles-058.png rectangles-080.png rectangles-102.png rectangles-124.png rectangles-146.png
rectangles-015.png rectangles-037.png rectangles-059.png rectangles-081.png rectangles-103.png rectangles-125.png rectangles-147.png
rectangles-016.png rectangles-038.png rectangles-060.png rectangles-082.png rectangles-104.png rectangles-126.png rectangles-148.png
rectangles-017.png rectangles-039.png rectangles-061.png rectangles-083.png rectangles-105.png rectangles-127.png rectangles-149.png
rectangles-018.png rectangles-040.png rectangles-062.png rectangles-084.png rectangles-106.png rectangles-128.png
rectangles-019.png rectangles-041.png rectangles-063.png rectangles-085.png rectangles-107.png rectangles-129.png
rectangles-020.png rectangles-042.png rectangles-064.png rectangles-086.png rectangles-108.png rectangles-130.png
rectangles-021.png rectangles-043.png rectangles-065.png rectangles-087.png rectangles-109.png rectangles-131.png
Look at first couple:
You can do those 3 steps in 1 like this:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage \
-crop 2000x2590+120+190 +repage \
-crop 10x15# rectangles-%03d.png
You may want to shave a few pixels off each side of each image and resize to 32x32 with something like (untested):
mogrify -shave 3x3 -resize 32x32! rectangles*png

How to improve image output from montage in ImageMagick?

I joined images using montage, but the resolution of the image output is less than that of the image's input.
My image's input have dimensions of 640x480 each
But the output that I get was 256x378
I was searching in the web and couldn't find a solution to improve the output's image quality.
The montage command that I'm using
montage -tile 2x3 1.png 2.png 3.png 4.png 5.png 6.png -resize 1024x1024 montage_png.png
Anyone know how can I get better output resolution?
Set the mode of operation style (-mode) to the concatenate value (as in the documentation).
For example:
montage -mode concatenate file1.jpg file2.jpg output.jpg
Suggestion 1
Try it this way... let montage organise the images into a montage and then pass the result on to convert to do the resizing of the result.
montage -tile 2x3 1.png 2.png 3.png 4.png 5.png 6.png miff:- | convert miff:- -resize 1024x1024 montage.png
The intermediate image is passed as a MIFF (Magick Image File Format) which preserves all detail and metadata and quality.
Suggestion 2
If it is always just 5 or 6 images and not hundreds, you can also do it all in one go with convert like this. All you need to know is that +append joins images in a row and -append joins images in a column. So I am joining 1&2 in a row, 3&4 in a row, 5 & 6 in a row and then putting the three rows in a stack and resizing the result.
convert [12].png +append \( [34].png +append \) \( [56].png +append \) -append -resize 1024x1024 result.png
Montage is simple to use like so:
montage -mode concatenate -tile 2x3 *.png -resize 1024x1024 outfile.png
But if you run it a second time this command will also include outfile.png as part of the new montage, of course.
Montage is smart enough to change formats properly, so the command can be changed to:
montage -mode concatenate -tile 2x3 *.png -resize 1024x1024 outfile.jpg
Which results in a file that is 2048 pixels wide.
If the input files are they are all of uniform size, the simplest way is to use it like so:
montage -mode concatenate -tile 2x3 *.jpg outfile.jpg
To the point of the question:
In gnuplot with the png terminal the default canvas size is 640x480, so a 2x3 montage to a proper JPG results in a file that is 1280 pixels wide.
Displayed on a web page that is too wide to print. Print boundaries are roughly 640 pixels wide (depending on how the margins are set), so it will usually work well with:
montage -mode concatenate -tile 2x3 -resize 320x240 *.png outfile.jpg
Using 320x240 preserves the aspect ratio of the original plot.
Forcing it to be square should be done in the set terminal command inside gnuplot if that is the desired outcome.
Best practice for image post-processing is to avoid distorting the image beyond the intent of the program which generates the originals.

Resources