Combine RGB channels from separate images using ImageMagick - cmd

I'm trying to combine the RGB channels from 3 separate images using ImageMagick. The red channel from image01.png, blue channel from image02.png and the green channel from image03.png
Image01.png, Image02.png, Image03.png
The resulting image should look like this (left) but I'm getting this (right):
This is the command I'm running....
"C:/ImageMagick/magick.exe" convert "C:/images/image01.png" "C:/images/image02.png" "C:/images/image03.png" "-background" "#ff0000" "-channel" "red,green,blue" "-combine" "C:/images/combined.png"
Do I need to somehow save out the various channels of each image separating first and then combine the images?

In ImageMagick, -channel does not work to select channels from multiple images.
Furthermore and more importantly, white contains red, green and blue. So the red channel of the first image will have the red dot as white and the background white as white, leaving black for the green and blue lines. Similarly in the other images. So white needs to be made black in each image. Then the channels are separated and recombined. Then black needs to be made white again.
Unix syntax:
convert \
\( image01.png -fuzz 70% -fill black -opaque white \
-channel r -separate +channel \) \
\( image02.png -fuzz 70% -fill black -opaque white \
-channel g -separate +channel \) \
\( image03.png -fuzz 70% -fill black -opaque white \
-channel b -separate +channel \) \
-set colorspace sRGB -combine \
-fuzz 20% -fill white -opaque black \
result.png
Windows Syntax:
convert.exe ^
( image01.png -fuzz 70% -fill black -opaque white ^
-channel r -separate +channel ) ^
( image02.png -fuzz 70% -fill black -opaque white ^
-channel g -separate +channel ) ^
( image03.png -fuzz 70% -fill black -opaque white ^
-channel b -separate +channel ) ^
-set colorspace sRGB -combine ^
-fuzz 20% -fill white -opaque black ^
result.png
The -fuzz is needed to remove the anti-aliased colors that are near white around the edges of the colored regions.
You would be much better starting with the 3 input images that have a black background rather than white. Then all the fuzz and white to black and black back to white would not be needed.

Related

How to detect text/logo-details from an image of any consumer product?

I am trying to detect name of any consumer product from an image of its packaging.For eg- Maggie (I want to detect- Maggie happiness is homemade) Kellogg's
I have tried applying image prepossessing(e.g- erosion, open, close etc.) and then supplying that pre-processed image to pytesseract(OCR). I am planning to use Image-Magic tool if it can do any help.
Would just pre-processing of an image be enough, if not then what should I do?(Any code, software anything)
PS- I dont want to use Google Vision or anything similar API
In Imagemagick 6, you can do the following to isolate the "kelloggs".
fill back to replace everything but the red color
fill white to replace the red color
convert kellogg.jpg -fuzz 15% \
-fill black +opaque "rgb(240,0,0)" \
-fill white -opaque "rgb(240,0,0)" \
result.png
For your "maggie" image, it is a bit more complicated, since you have yellow for "maggie" and yellow elsewhere.
fill yellow color to replace the white in the corners
fill yellow color to replace black
floodfill the outside yellow with black
fill black to replace everything but yellow
fill white to replace yellow
convert maggie.jpg \
-fuzz 15% -fill "rgb(254,242,0)" -opaque white \
-fuzz 20% -fill "rgb(254,242,0)" -opaque black \
-fuzz 15% -fill black -draw "color 10,10 floodfill" -alpha off \
-fuzz 15% -fill black +opaque "rgb(254,242,0)" \
-fuzz 15% -fill white -opaque "rgb(254,242,0)" \
result2.png
But there is the trademark left. So to remove that we add connected components processing to filter out the smallest white areas.
convert maggie.jpg \
-fuzz 15% -fill "rgb(254,242,0)" -opaque white \
-fuzz 20% -fill "rgb(254,242,0)" -opaque black \
-fuzz 15% -fill black -draw "color 10,10 floodfill" -alpha off \
-fuzz 15% -fill black +opaque "rgb(254,242,0)" \
-fuzz 15% -fill white -opaque "rgb(254,242,0)" \
-define connected-components:area-threshold=50 \
-define connected-components:mean-color=true \
-connected-components 4 \
result3.png

ImageMagick: Why won't this text expand to fill?

I'm reading the text handling docs for label and it seems if I specify -size it should magically get as big as possible to fill the space.
I want to make it so this text gets as big as possible. I will set the \n characters myself in the title (if absolutely necessary).
I'd rather the \n get calculated automatically, but it seems label is what makes it the biggest possible (but doesn't support automatic \n), while caption will add \n where appropriate (but doesn't support a dynamic size which fills to fit a space).
My goal is to basically get the BIGGEST possible text, whether it's on 1 line or 3, to fit in the green box (between the 2 red ****** lines).
Below are 2 examples of how it won't change. The green color is just temporary so I can debug.
Heres my code for this text piece (without all the rest):
-size 290x54 -background green -fill blue -font ArialB -gravity center label:'Join Us'
Multiline...
-size 290x54 -background green -fill blue -font ArialB -gravity center label:'Join Us Tomorrow\nFor An HVAC Meeting'
I don't know if this is possible, but ideally it should ask "if the title is on 1 line, what is the max size it could be? if I put a \n after word 1, what is the max size it could be? if i put a \n after word 2, what is the max size it could be?"... and then choosing the largest of those.
Your command works for me with one correction. Apparently, the pointsize leaks from the your main command into the parenthesis processing, even though I added -respect-parenthesis. So the solution is to add +pointsize into the parenthesis command. Here is my command and result.
magick -respect-parenthesis -size 298x248 canvas:white \( 'arrows.png' -resize 300x \) -gravity northwest -geometry +0+140 -compose over -composite -bordercolor '#cccccc' -border 1 -font Arial -fill red -pointsize 22 -gravity north -annotate +0+4 '*************************' -font Arial -fill red -pointsize 22 -gravity north -annotate +0+68 '*************************' -font Arial -fill green -pointsize 15 -gravity south -annotate +0+64 'hvac.com' \( -size 279x55 +pointsize -background green -fill blue -font ArialB -gravity center caption:'test headline' \) -gravity center -geometry +0-82 -compose over -composite output.png
Note that I put the arrows.png file where I could access it at the same level as where the command is being issued. You can change the path to it.
In ImageMagick use caption by specifying both the widthxheight but not the pointsize. ImageMagick will figure out the proper pointsize to fill the text to the box. For example:
convert -size 500x200 -background white -font arial -fill black -gravity center caption:"Testing" -bordercolor red -border 1 test1.png
convert -size 500x200 -background white -font arial -fill black -gravity center caption:"Should Be Bigger" -bordercolor red -border 1 test2.png
convert -size 500x200 -background white -font arial -fill black -gravity center caption:"This is a title that will be fairly long and I want it to fit nicely" -bordercolor red -border 1 test3.png
You can also include the pointsize, so long as your text is not too long for the area of the box.
convert -size 500x200 -background white -font arial -fill black -pointsize 48 -gravity center caption:"Testing" -bordercolor red -border 1 test1b.png
convert -size 500x200 -background white -font arial -fill black -pointsize 48 -gravity center caption:"Should Be Bigger" -bordercolor red -border 1 test2b.png
convert -size 500x200 -background white -font arial -fill black -pointsize 48 -gravity center caption:"This is a title that will be fairly long and I want it to fit nicely" -bordercolor red -border 1 test3b.png
However, if you choose a font that is too big, you will get this:
convert -size 500x200 -background white -font arial -fill black -pointsize 64 -gravity center caption:"This is a title that will be fairly long and I want it to fit nicely" -bordercolor red -border 1 test3c.png

draw grid with cells of specific size over an image

How can I draw a grid, 1px black borders no fill, over an image?
Each section of the grid should be 480x360px.
E.g., given this 1440x1080px solid white input:
It should have a 3x3 grid drawn onto it (because 9 480x360px rectangles fit into it) to make an output kind of like this:
That's not as accurate as I'd like the command to be (I was just drawing rectangles by eye), but I hope it illustrates what I'm after.
Here is a command that will read an input image, create a 480x360 transparent cell with a black border, create a grid of those cells the size of the input image, and composite that grid over the input...
infile="MyPic.png"
convert "$infile" -size 480x360 -set option:distort:viewport "%[w]x%[h]" \
\( xc:none -shave 1x1 -compose copy -bordercolor black -border 1x1 \) \
-virtual-pixel tile -distort SRT 0 -compose over -composite output.png
That will make the lines of the grid 2 pixels thick. If the lines must be 1 pixel thick, the same sort of thing can be done with a command like this...
convert "$infile" -size 480x360 -set option:distort:viewport "%[w]x%[h]" \
\( xc:none -chop 1x1 -background black -splice 1x1 \) \
-virtual-pixel tile -distort SRT 0 -compose over -composite \
-bordercolor black -shave 1x1 -compose copy -border 1x1 output.png
EDITED TO ADD: If the objective is to divide the grid into a particular number of cells rather than cells of specified dimensions, a command like this should work...
convert "$infile" \( +clone -channel A -evaluate set 0 +channel \
-crop 3x4# -chop 1x1 -background black -splice 1x1 \) -background none \
-flatten -shave 1x1 -bordercolor black -border 1x1 output.png
That creates a clone of the input image and makes it transparent, uses "-crop 3x4#" to crop it into a grid of 3x4 cells, puts a black border on the top and left edges of the cells, then reassembles them into a grid by flattening them onto the input image. It finishes by adding a border to the right and bottom edges while preserving the input image's original dimensions.
Obviously using this method the cells may not all have the exact same dimensions if the the input image can't be divided evenly by the number of cells.
EDITED AGAIN: If you don't actually need the grid to be an overlay, you can directly crop the image into tiles, put black lines around the tiles, and reassemble them to create the required output image. That can be done with a simple command like this to make 480x360 sized cells...
convert "$infile" -background black -bordercolor black \
-crop 480x360 -chop 1x1 -splice 1x1 -flatten -shave 1x1 -border 1x1 output.png
Or it can be done with "-crop 3x3#" like this to make a grid of 3 rows and 3 columns letting ImageMagick calculate the sizes as nearly as possible...
convert "$infile" -background black -bordercolor black \
-crop 3x3# -chop 1x1 -splice 1x1 -flatten -shave 1x1 -border 1x1 output.png
Again, if the image size isn't evenly divisible by the number of cells, there will be one pixel difference in the sizes of some of the cells.
I had a little attempt at this and got kind of stymied at every turn. Here is the best I got so far.
convert xc:white[1440x1080\!] -colorspace gray -fx "(i==0||i==479||i==959||i==1439||j==0||j==359||j==719||j==1079)?0:1" grid.png
So, for practical use, you would take your snow scene and clone it. Then go to greyscale (to reduce the processing time by a factor of 3) and set all the lines black and the other pixels white. Then overlay onto the snow scene choosing the darkest pixel at each location:
convert scene.jpg \( +clone -colorspace gray \
-fx "(i==0||i==479||i==959||i==1439||j==0||j==359||j==719||j==1079)?0:1" \) -compose darken -composite result.png
If you wanted it marginally smarter and adaptive to different sized images, you could calculate the third-points as a function of image size:
magick scene.jpg \( +clone -colorspace gray \
-fx "(i==0||i==int(w/3)||i==2*int(w/3)||i==w-1||j==0||j==int(h/3)||j==2*int(h/3)||j==h-1)?0:1" \) \
-compose darken -composite result.png
The best I came up with so far:
convert blank.png -fill black -draw 'line 480,0 480,1080 line 960,0 960,1080 line 0,360 1440,360 line 0,720 1440,720' level1.png
But this is all manual.
Is there a way to automate this?
Here's another variant that is fast and easy to understand - not 100% identical to your requirements but maybe good enough.
Create a starter box with a black border, duplicate twice and append across the page, duplicate twice and append down the page, make minor correction to size:
convert xc:red[478x358\!] -bordercolor black -border 1 \
-duplicate 2,0 +smush -1 \
-duplicate 2,0 -smush -1 -transparent red -scale 1440x1080\! result.png
Or you could make your initial box, duplicate it 8 times and let montage lay the resulting 9 boxes out:
convert xc:red[478x358\!] -bordercolor black -border 1 \
-transparent red -duplicate 8,0 miff:- | montage -background none -geometry +0+0 miff:- result.png

Image circle cropping in imagemagick

People, I am using imagemagick to crop a circle out of an image. But I am getting nothing when I run this command :
convert input.jpg +clone -threshold -1 -negate -fill white -draw "circle 539,539 539,0" -alpha off -compose copy_opacity -composite output_circ.jpg
I am getting an output like this:
Please let me know if I am missing something.
Fundamentally, you are only missing one aspect - JPEG files cannot store transparency, so you need to use a PNG or GIF, for example.
convert input.jpg -alpha on \( +clone -threshold -1 -negate -fill white -draw "circle 539,539 539,0" \) -compose copy_opacity -composite output_circ.png

ImageMagick and Piping

I have the following commands that create a sprite containing a normal state and a hover state:
convert -background none -pointsize 11 -fill white -size 100x -gravity NorthWest caption:'Test' top.png
convert -background none -pointsize 11 -fill grey -size 100x -gravity SouthWest caption:'Test' bottom.png
montage top.png bottom.png -geometry +0+0 -tile 1x2 -background none test.png
I'm creating two images, top.png and bottom.png then combining them to create test.png.
Is there a way to do this without having to write the top and bottom images to disc?
Can I pipe the commands together some how?
Update: Solution
montage \
<(convert -background none -pointsize 11 -fill white -size 100x -gravity NorthWest caption:'Test' png:-) \
<(convert -background none -pointsize 11 -fill grey -size 100x -gravity SouthWest caption:'Test' png:-) \
-geometry +0+0 -tile 1x2 -background none test.png
This is completely untested, so make sure to backup the relevant images before testing:
montage \
<(convert -background none -pointsize 11 -fill white -size 100x -gravity NorthWest caption:'Test' png:-) \
<(convert -background none -pointsize 11 -fill grey -size 100x -gravity SouthWest caption:'Test' png:-) \
-geometry +0+0 -tile 1x2 -background none test.png
(This is called "Process Substitution")

Resources