ImageMagick count how many identical or almost identical color pixels are on the edges left and right of image - imagemagick

This is an example PNG image:
it's 50x40 but enlarged here to see it better.
The hex of bottom left and bottom right pixels is F9E4B7
I need to know how many pixels there are on vertical edges from the bottom left and right with almost this color, like 1% fuzz because they are not all exactly F9E4B7 but some are very slightly different.
In this case it would be 20px of each side:
I'll mark the areas which need to be counted just to make it perfectly clear:
I also need to be able to count how many pixels are exactly F9E4B7, which in this case would be 15 left and 20 right, I'll mark the slightly different areas so it's clear where the counter needs to stop:

The way to do that in Imagemagick is to use fuzz to change all your pixels close to that color to white and the rest black. The crop the first or last column and use -fx to get the count from mean*width*height. So for example for the left full column of the whole image, one has
Unix Imagemagick 6 syntax:
convert tan.png -alpha off \
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white \
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Windows Imagemagick Syntax:
convert tan.png -alpha off ^
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white ^
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Result:
108
To get the right side, use -gravity east.
For exact count, use -fuzz 0
For Imagemagick 7, change convert to magick

Related

Find colored box in image and create a mask file

I would like to create a hotfolder for my motion camera, into which I can drop images marking areas, which should be excluded in motion recognition via a *pgm mask. On these images, there is a small area marked with a transparent box with a magenta colored outline. My aim is to replace this box and outline with a black solid box and the rest of the image with white. (Tried to post samples here, but not enough reputation to do so.)
I know how to do this "by foot" using gimp, but I cannot figure out a clever and simple way achieving this with imagemagick.
I tried googling for solutions with -trim and -virtual-pixel, but no luck. Any help would be appreciated.
I'll do this step-by-step so you can see the intermediate parts in case you are on Windows and bash doesn't work.
First, let's make make everything that is not within 10% of your magenta colour, namely rgb(225,75,130), into lime green:
magick source.jpg -fill lime -fuzz 10% +opaque "rgb(225,75,130)" result.png
Ok, now let's get the trim box - i.e. all the constant junk that ImageMagick could trim off to focus on the magenta bit.
magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info:
14x66+426+118
So your magenta box is 14x66pixels and located at offset 426,118 from the top-left. Now we want to get those in bash variables w,h,x,y. We need to change x and + into spaces using tr:
read w h x y < <(magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info: | tr 'x+' ' ')
If we print this we get:
echo $w, $h, $x, $y
14, 66, 426, 118
Now we want to draw a rectangle, but that needs top-left and bottom-right, so we need to do some maths:
((x1=x+w))
((y1=y+h))
Ok, now we can load the original image, make it fully white, then draw our black rectangle:
magick source.jpg -threshold -1 -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm
So, the whole thing boils down to:
#!/bin/bash
read w h x y < <(magick source.jpg -fill black -fuzz 10% +opaque "rgb(225,75,130)" -format '%#' info: | tr 'x+' ' ')
echo $w, $h, $x, $y
((x1=x+w))
((y1=y+h))
magick source.jpg -threshold -1 -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm
There are other (maybe more elegant) ways of doing it, using flood-fills and/or connected components but I didn't want it to rely on your magenta box being "watertight", i.e. not rely on the sides being continuous and complete.
Also, if the size of your images is known and constant, you can avoid reloading the original and making it white by thresholding like I do in the last line and just create a canvas of the known dimensions, i.e.:
magick -size ${W}x${H} xc:white -fill black -draw "rectangle $x,$y $x1,$y1" -depth 8 mask.pgm

ImageMagick count how many identical or almost identical color pixels are vertically by x coordinate

I have this image:
I need to count how many red pixels there are vertically on x 60 which would be the red line on the right containing 4 pixels.
I tried this:
img.png -alpha off -fuzz 2% -fill white -opaque "#FF0000" -fill black +opaque white -gravity west -crop 61x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
but it also counts all the red pixels left to x 60
Try:
magick ... -crop 1x+61+0 ...
to crop a full-height, 1px wide column starting at 61,0.

remove white background with ImageMagick but not the white inside picture?

im trying to delete the background with a batch process in pictures of products for an e-commerce site.
The problem is that the script also remove the white color in the inside of the product, leaving the product transparent in some areas..
For example:
Command:
convert *.jpg -set filename: %t -fuzz 5% -transparent white %[filename:].png
this is the best I can get..im ok with this result around the product, but I need that the white inside the product remains white and not transparent.
The problem with your current approach is that it doesn't respect boundaries, it is just applied globally, making all white pixels transparent regardless of their connectivity to the background.
Instead, you will get on better using a "floodfill" that only floods into areas that are within the fuzz distance of the top-left corner pixel.
So, I chose an unused colour of magenta so you can see what is happening:
convert product.jpg -fuzz 5% -fill magenta -draw 'color 0,0 floodfill' result.png
You would then follow that with the command to make magenta transparent like this:
convert product.jpg -fuzz 5% -fill magenta -draw 'color 0,0 floodfill' -transparent magenta result.png

Image Magick: dimmed caption with border

I am using Image Magick to overlay a dimmed caption to an image, with IM automatically choosing the best fontsize:
convert -background '#0008' -fill white -geometry +0+330 -size 370x60 caption:$title $image +swap -composite $imageOutput
My problem is that there is not enough space around the text, I would like to add some "padding". I usually do that with the -border option but if I add this to my command above, the caption is not dimmed anymore.
Do you have a solution to create a dimmed caption with enough room around the text?
I have a solution, but it's a bit of a kludge because I had trouble extending or bordering a semi-transparent background. In the end, I just constructed the caption on a black background and bordered it in black, then I tweaked the alpha channel afterwards:
convert -background black -bordercolor black -fill white \
-size 370x60 caption:"This is the title" \
-trim -border 20 -channel A -fx '(lightness/2)+.5' \
-geometry +0+200 background.gif +swap -composite result.png
The only tricky part is -channel A -fx .... The first part means that we are only affecting/modifying the alpha/opacity channel. The 0.5 means that all pixels become at least 50% opaque, and (lightness/2) means that absolutely white pixels, i.e. your lettering, (which will have a lightness of 1) become fully opaque because 0.5+(1/2) totals to one. The point of this is to preserve the anti-aliasing around the edges of the letters to some degree.

Cleaning the left side of an image

Using imagemagick, I want to clean the left side of an image, i.e. make white without cropping. For example cleaning the left-most vertical strip of 25 pixels wide. I figured out how to crop to a given geometry, but I couldn't figure out how to clean without cropping.
Here is my start image, made like this:
convert -size 256x256 gradient:cyan-yellow image.png
Method 1
One way to do it would be to use -fx and set all pixels where the x-coordinate is less than 25 to 1.0 (i.e. white) and leave all other pixels as they are:
convert image.png -fx "i<25?1:u" result.png
Method 2
Another, faster way to do it might be to clone the original image, and scale it down to 25 pixels wide, fill it with white and composite that over the original image:
convert image.png \
\( +clone -scale 25x! -fill white -colorize 100 \) \
-composite result.png
The result is the same.
Method 3
A third way to do it might be to crop the image 25 pixels in from the left side, then splice 25 white pixels back on the left side:
convert image.png -crop +25+0 -background white -gravity west -splice 25x result.png
Method 4
Bit of a kludge, but nearer to what you asked. Here, I guess that your image height doesn't exceed 10,000 pixels and draw a rectangle:
convert image.png -fill white -draw "rectangle 0,0 24,9999" result.png
I guess the proper way to do this is to get the height first then use it:
#!/bin/bash
h=$(convert image.png -format "%[fx:h-1]" info:)
convert image.png -fill white -draw "rectangle 0,0 24,$h" result.png

Resources