Blend multiple images with ImageMagic - imagemagick

My problem is the following :
I have several .png files. Each file has a small spot of a certain color. All the files have the same size. My question is how to overlay them together so that the spots of different colors will be a mixture of this colors and one color do not overlap completely the other one? The -flatten option combines images but on the example orange (img1) color will be covered by brown (img2), instead I want a spot of mixing color (brownish).
I tried:
convert -evaluate-sequences mean -- didn't help
convert -layers merge -- didn't help
composite -blend -- help, but can combine only two images
Thanks for any tips

Not sure what your images are like, since you only provided 2 whereas I was expecting two input images and one result!
So, let's make two of our own:
convert -size 200x100 xc:none -fill black -draw "circle 80,50 130,50" black.png
convert -size 200x100 xc:none -fill orange -draw "circle 120,50 170,50" orange.png
Then I guess you want this:
convert orange.png black.png -compose overlay -composite result.png
Or maybe you mean luminize blend mode:
convert orange.png black.png -compose luminize -composite result.png
If you want to experiment with other blend modes, you can use:
identify -list compose
to get a list of all of them.
Atop
Blend
Blur
Bumpmap
ChangeMask
Clear
ColorBurn
ColorDodge
Colorize
CopyAlpha
CopyBlack
CopyBlue
CopyCyan
CopyGreen
Copy
CopyMagenta
CopyRed
CopyYellow
Darken
DarkenIntensity
DivideDst
DivideSrc
Dst
Difference
Displace
Dissolve
Distort
DstAtop
DstIn
DstOut
DstOver
Exclusion
HardLight
HardMix
Hue
In
Intensity
Lighten
LightenIntensity
LinearBurn
LinearDodge
LinearLight
Luminize
Mathematics
MinusDst
MinusSrc
Modulate
ModulusAdd
ModulusSubtract
Multiply
None
Out
Overlay
Over
PegtopLight
PinLight
Plus
Replace
Saturate
Screen
SoftLight
Src
SrcAtop
SrcIn
SrcOut
SrcOver
VividLight
Xor
If you want to check them all:
for b in $(identify -list compose); do convert -gravity center -pointsize 72 -label "$b" orange.png black.png -compose $b -composite miff:- ; done | montage -geometry +0+0 miff: montage.png

Related

How to split an image with a grid and preserve transparency bounding box

I have some png images that I want to split it into parts, like by grid or size.
But each part should have the same bounding box (transparency) as original image.
Example:
Splitting image into 2 parts.
Original: 200 × 89
Output:
part_1.png, 200 × 89
part_2.png, 200 × 89
Can ImageMagick do this? Or any other app or method.
My actual goal is to split into 100+ slices images.
EDIT:
Another goal to have an indents for each slice. Say indent = 10px.
Example:
Input: 200 x 100
Output:
part_1.png, 200 x 100
part_2.png, 200 x 100
And just as example, to visually compare input and output: combined output images in Photoshop as layer added one onto another
200 x 100 :
Also this is showing input image added onto combined(so it's better to see what was cropped and how):
In ImageMagick, you can split an image into many parts with the -crop command. For your example above with two parts, you can do that with the following commands. ImageMagick will append -0, -1 ... to the output file names.
ImageMagick 6:
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% \) -layers composite result.png
ImageMagick 7:
magick \( image.png -set option:dim "%wx%h" -crop 50x100% \) null: \( -size "%[dim]" xc:none \) -reverse -layers composite result.png
The results are:
See
http://www.imagemagick.org/Usage/crop/#crop
http://www.imagemagick.org/Usage/crop/#crop_percent
http://www.imagemagick.org/Usage/crop/#crop_tile
http://www.imagemagick.org/Usage/crop/#crop_quad
http://www.imagemagick.org/Usage/crop/#crop_equal
http://www.imagemagick.org/script/command-line-options.php#layers
Note that -crop keeps the virtual canvas information if you do not add +repage afterwards. So to put the individual images back into their original placement, you have to composite them onto a transparent background the size of the input. That is done in one command using -layers composite using the null: separator.
Here is another way to add transparent areas between parts of a crop in ImageMagick. Crop the image into pieces, chop off the parts you want to remove, then pipe to montage to add the spacing back.
Input:
Here I make this into a 4x4 grid of images with 10 pixel spacing:
convert lena.png -crop 25%x25% +repage -gravity east -chop 10x0 -gravity south -chop 0x10 +repage miff:- | montage - -background none -tile 4x4 -geometry +5+5 result.png
To answer your new question, you can do that with a script loop. On a Unix-like platform, assuming your images do not have spaces, you can do the following:
cd path/to/current_folder
list=`ls *.png`
for img in $list; do
name=`convert $img -format "%t" info:`
dim=`convert $img -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( $img -crop 50x100% \) -layers composite -scene 1 path/to/new_folder/${name}_%d.png
done
If you want leading 0s in the output, say 3, use path/to/new_folder/${name}_%03d.png.
Note that to start with 1 rather than 0, I have added -scene 1.
Sorry, I do not know how to script for Windows.
Please always provide your ImageMagick version and platform.
In ImageMagick, the best way to put transparent areas into your image is with a binary mask that is put into the alpha channel of your image.
convert input.png \( -size 200x89 xc:white -size 10x89 xc:black -gravity center -composite \) -alpha off -compose copy_opacity -composite result.png
You can add as many blank areas as you want by adding more white areas to the mask or by tiling out one region of black and one region of white to create the mask with regular spacing of black and white.
Edited to add this ImageMagick 6 example which splits the input image into 4 pieces, 25% of the original width and 100% of its height, then creates a transparent canvas for each piece the same dimensions of the input image, and locates the pieces at their original offsets on those canvases.
convert input.png -set option:distort:viewport %[w]x%[h] -crop 25x100% \
-virtual-pixel none -distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
The output file names will be numbered starting from zero like "out000.png", etc.
Original message...
Here's a simple command using ImageMagick 7 that can crop an image into any number of pieces, and output all the pieces at their original offsets on transparent backgrounds of the original input dimensions...
magick input.png -crop 100x1# -background none \
-extent "%[fx:s.page.width]x%[fx:s.page.height]-%[fx:s.page.x]-%[fx:s.page.y]" out%03d.png
That "-crop 100x1#" tells it to split the image into a grid 100 pieces wide by 1 piece high. You could just as well specify the crop sizes as percents or numbers of pixels.
Edited again to add:
This following command will split the input image into the individual pieces specified with the "-crop" operator, then shave 5 pixels from every side of each piece, then apply a 5 pixel transparent border to every side of each piece. It will still remember the original locations of the pieces within the input canvas, so the "-distort affine ..." can extend the canvases and place the pieces where they were in the input image.
convert input.png -set option:distort:viewport %[w]x%[h] \
-bordercolor none -background none -virtual-pixel none \
-crop 25x100% -shave 5x5 -border 5x5 \
-distort affine "0,0 %[fx:s.page.x],%[fx:s.page.y]" out%03d.png
To use this command with IM7 you need to change "convert" to "magick".
Given the changes of requirements provided by Kamikaze, here is one way to achieve the split with indent in ImageMagick, assuming I understand correctly.
dim=`convert image.png -format "%wx%h" info:`
convert \( -size $dim xc:none \) null: \( image.png -crop 50x100% -shave 5x5 \) -geometry +5+5 -layers composite result.png
To check, I flatten over a blue background:
convert result-0.png result-1.png -background blue -flatten result.png

How to find out the average color (rgb) of masked area of an Image

I would like to get the average color in rgb of the mask area of a png image.
the following just outputs the average color of the whole image
convert demo.png -mask demo_mask.png -resize 1x1 txt:-
In ImageMagick, -scale 1x1! will ignore the transparent pixels and give you the average of the opaque pixels. So if you want the average of the masked region, you can put the mask into the alpha channel and then use -scale 1x1! to average it down to one pixel. The mask should be white where you want to get the average and black where it should be transparent and ignore those pixels in the average. So this should do it.
convert image.png mask.png -alpha off -compose copy_opacity -composite -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
For example if I make the logo: image transparent where it is white and then get the average, I get
convert logo: -transparent white -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
srgb(100,81,99)
You can show that this works, by doing it the long way. Multiply the mask by the image, then get the average of each channel of the product. Then get the average of the mask. Then compute the ratios scaled to the range 0 to 255.
convert logo: -transparent white logot.png
convert logot.png -alpha extract mask.png
declare `convert \( logot.png -alpha off \) mask.png -compose multiply -composite -format "IR=%[fx:mean.r]\nIG=%[fx:mean.g]\nIB=%[fx:mean.b]\n" info:`
echo "IR=$IR; IG=$IG; IB=$IB"
IR=0.0651798; IG=0.0529989; IB=0.0641607
MM=`convert mask.png -format "%[fx:mean]\n" info:`
echo "MM=$MM"
MM=0.165872
convert xc: -format "srgb(%[fx:round(255*$IR/$MM)],%[fx:round(255*$IG/$MM)],%[fx:round(255*$IB/$MM)])\n" info:
srgb(100,81,99)
Result is the same as above.
ASIDE: Note that
convert \( logot.png -alpha off \) mask.png -compose multiply -composite ...
in this case is the same as just
convert logot.png -alpha remove ...
But I show it the long way, if the user has a separate mask and image with no transparency.
You should be able to get very nearly what you want with a command something like this...
convert image.png mask.png -compose copyopacity -composite -resize 1x1! txt:-
To output only the color information you can try something like this...
convert image.png mask.png \
-compose copyopacity -composite -resize 1x1! -format "%[pixel:p]" info:
I haven't tried it, but you may have to "-negate" your mask image depending on which version of IM you're using because there have been changes in the way the alpha channel is handled.
You'll get a very slightly different result if you "-trim" before the "-resize".
If you don't want to output the alpha channel information, you can add "-alpha off" after the "-resize".
Perhaps...
convert demo.png -mask demo_mask.png -trim -fx mean -extent 1x1 txt:- |\
tail -1 | cut -d ' ' -f 4
This would work because -trim will reduce the masked image down to the MBR of the ROI. Fx operator -fx mean will convert all pixels into the overall average. And finally the -extent 1x1 will isolate the first pixel in the image. The rest is basic unix utilities.
Another option with better performance...
MEAN=$(convert demo.png -mask demo_mask.png -trim -format '%[fx:mean]' info:-)
convert null: -depth 8 -format "%[pixel:$MEAN]" info:-
Or from the Quantization documentation...
convert demo.png -mask demo_mask.png -trim -scale 1x1\! '%[pixel:s]' info:-

Imagemagick: How does RGB work with this software?

I want to change all colors #FF00FF in an image to #0000FF while keeping shades, ideally. So I figured I should at least get it to change colors to begin with to see if the software is even capable of doing things like that.
However its only changing a bit of the color to white and only with a high Fuzz. So it's obvious that RGB in Imagemagick doesn't work like it does anywhere else and I can't find anything to explain how it works.
It seems to replace some off-white with pure white.
Using PHP I do:
exec("convert ".$dir."".$file." -channel RGB -fuzz 30% -opaque rgb\(255,0,255\) -fill rgb\(0,0,255\) ".$dir."".$file);
I am not 100% certain what you mean as you haven't provided a sample of what other software does, but I'll have a try and see if we can get there.
So, if we make a starting image, including your presumed shades of magenta on the left and some test colours on the right:
convert -size 256x256 gradient:black-magenta -size 50x256 \
xc:black xc:white xc:red xc:lime xc:blue +append start.png
And, you want to change magenta shades into blue. I would call that a hue modulation, so I would want to find out the hue angle between blue and magenta, so I would create a 2x1 image with one magenta and one blue pixel and get their HSI values:
convert xc:magenta xc:blue -append -colorspace hsi txt:
Output
# ImageMagick pixel enumeration: 1,2,65535,hsi
0,0: (54612.5,65535,43690) #D555FFFFAAAA hsi(300,100%,66.6667%)
0,1: (43690,65535,21845) #AAAAFFFF5555 hsi(240,100%,33.3333%)
And I can see their hues are 60 degrees apart (300-240). So I would use the -modulate operator, which takes a Brightness, Saturation and Hue, leave the first two unchanged at 100%, and modify the Hue by 60 degrees:
convert start.png -modulate 100,100,60 result.png
Or maybe that is not what you mean? Maybe you only mean to affect specific colour. If so, it gets harder... but not that hard :-)
First, extract the Hue, Saturation and Brightness layers to separate files:
convert start.png -colorspace HSL -separate -colorspace gray HSL-%d.png
That will give us the Hue as a single channel greyscale image in HSL-0.png, the Saturation in HSL-1.png and the Lightness in HSL-2.png.
Now we want to make a new LUT (Lookup Table) for the Hue channel, so we make a 360 pixel long LUT that maps 1:1, i.e. everything maps to normal.
convert -size 1x360 gradient: -rotate 90 greyscale.png
Then we want to dink with the lookups around magenta (300) and make them blue (240). So we want to subtract 60 degrees (which is 0.16 if you scale 0-360 degrees onto the range 0-1) from all pixels in the range 280-320 so there is some tolerance:
convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<280||i>320?u:u-0.16" hueCLUT.png
Now apply that LUT to the Hue of the original image and rebuild it...
convert HSL-0.png -colorspace gray hueCLUT.png -clut HSL-1.png HSL-2.png -set colorspace HSL -combine -colorspace RGB result.png
So, as a simpler script, that might become:
#!/bin/bash
# Make a hue CLUT, transforming magenta hues to blue
convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<295||i>305?u:u-0.16" -resize 256x1! hueclut.png
# Apply to the hue channel
convert start.png -colorspace HSL -write MPR:HSL \
-channel R -separate hueclut.png -clut \
\( MPR:HSL -channel G -separate \) \
\( MPR:HSL -channel B -separate \) \
-set colorspace HSL -combine -colorspace RGB result.png

How to select all grayscale colors?

In ImageMagick convert, I can select a specific color with e.g. -opaque blue. How can I select all grayscale colors (e.g. #000000, #707070, #ffffff)?
Not sure what you are trying to do, but this may help. The greyscale pixels will have a saturation of zero, so that is probably the easiest way to identify them.
First, make a funky sample image:
convert -size 400x100 gradient:black-white -bordercolor red -border 80 image.png
Now make all grey areas (those with very low saturation) transparent:
convert image.png -alpha on -channel A -fx "saturation<0.01?0:1" result.png
Note
Note that the -fx operator is extremely powerful but notoriously slow because it is actually interpolated for each and every pixel. If your images are large, the following technique may be more appropriate.
Basically, I clone the image and convert the whole thing to HSL colorspace and separate the channels. Then I discard the Hue and Lightness channels so I am left with just the Saturation. I then threshold that and copy that back to the original image as the alpha channel. On a 2000x2000 pixel image, this method will run in under a second whereas the -fx method will require 5-6 seconds.
convert image.png \( +clone -colorspace hsl -separate -delete 0,2 -threshold 1% \) -compose copy-opacity -composite result.png

Export Multiple PSD Layer file to PNG while applying tint effect to each layer

We have the following PSD
https://app.box.com/s/rf514j3wnic1xkt6y1q3b5qnk0zds2rl
This is a transparent PSD with one base layer for the ring metal.
And additional layer for each individual stones.
Something like https://app.box.com/s/i8lhshbl27pvjmmczjq2bhla4mzw9cwn
and this
We want to be able to apply tint to each individual stone layer based of user input and export the final image as PNG file. To provide users the ability to design the ring to their liking.
Now I am trying to figure out what is the best way to achieve this functionality ?
We would like the image generated server side in .net so it can be shared.
What is the best way to approach this. I am thinking of using an image library like imagemagick to convert the image.
But I am unable to locate any examples where you can alter multiple layer with in a PSD file before converting it to another file format.
Any example or suggestion on methods to achieve this will of great help.
Editing layered PSD files is not going to be easy. I would suggest you maybe save the ring and each of the gemstone layers as a separate PNG file. Then you can do something along these lines with ImageMagick:
#!/bin/bash
convert ring.png \
\( layer-1.png \( +clone +level-colors red \) -compose Multiply -composite \) -compose overlay -composite \
\( layer-2.png \( +clone +level-colors green \) -compose VividLight -composite \) -compose overlay -composite \
\( layer-3.png \( +clone +level-colors blue \) -compose LinearBurn -composite \) -compose overlay -composite \
\( layer-4.png \( +clone +level-colors "#ffff00" \) -compose Saturate -composite \) -compose overlay -composite \
result.png
Giving you a PNG file like this:
You may like to experiment with the blending modes, I just tried a few that looked vaguely pleasing to my eye. If you want a list of all available blending modes, you can do:
identify -list compose
Atop
Blend
Blur
Bumpmap
ChangeMask
Clear
ColorBurn
ColorDodge
Colorize
CopyBlack
CopyBlue
CopyCyan
CopyGreen
Copy
CopyMagenta
CopyOpacity
CopyRed
CopyYellow
Darken
DarkenIntensity
DivideDst
DivideSrc
Dst
Difference
Displace
Dissolve
Distort
DstAtop
DstIn
DstOut
DstOver
Exclusion
HardLight
HardMix
Hue
In
Lighten
LightenIntensity
LinearBurn
LinearDodge
LinearLight
Luminize
Mathematics
MinusDst
MinusSrc
Modulate
ModulusAdd
ModulusSubtract
Multiply
None
Out
Overlay
Over
PegtopLight
PinLight
Plus
Replace
Saturate
Screen
SoftLight
Src
SrcAtop
SrcIn
SrcOut
SrcOver
VividLight
Xor
I also specified some colours by name and one by hex, so you can see how to do it that way if you prefer.
P.S. If you keep all your artwork as PSD files, you can always use Adobe's ExtendScript to script the export of the various layers as separate PNG files with a single keypress...
P.P.S. It is possible for ImageMagick to extract the layers from a PSD file itself, but I extracted the layers from your file and they are not all the same size as the background image and I cannot find their correct positioning relative to it. If you know something about how the layers were created and whether they could be made identical size and aligned with the background, you could replace layer-n.png in my examples with PhotoshopFile.psd[n]
P.P.P.S. If you want to do this server side in .NET you should take a look at the .NET library for ImageMagick that can be found here: https://magick.codeplex.com/. If you need help translating the commands above to C# you could ask a question on the discussions page there.

Resources