Imagemagick: distorting images on top of background? - image-processing

I've got one background image: sky.jpg
And two transparent PNG images: gradient.png and tree.png
Now I want to draw the two images on the background with a perspective distortion, like this:
The destination coordinates of the two images are, in clockwise order (starting top left) :
gradient: 62,129 421,218 383,458 147,548
tree: 445,100 765,47 698,368 529,396
I cannot figure out how to start with one image (in this case the sky background) and then take another image and draw that with perspective distortion to specific destination coords within the background. Also doing this with more than one image at a time, within one convert command, troubles me.
For example, when I start with just one image (the gradient) and try this:
convert sky.jpg \( gradient.png -alpha set -virtual-pixel transparent \
+distort Perspective "0,0 62,129 255,0 421,218 255,255 383,458 0,255 147,548" \) \
-compose src-over -composite result.jpg
It gets correctly warped (so the coordinates are relatively correct) but it's drawn in the top left corner, not at the coordinates I specify.
Also I'm a bit unsure if my usage of -compose and -composite is correct (I took this from various IM manual examples).
One other thing that is unclear to me: in case of the 256x256 image, should I use 255,0 and 255,255 and 0,255 as the corner coordinates, or 256,0 and 256,256 and 0,256 ?
Any IM experts who can shed light on these issues?

Add a -geometry just before the -composite like this:
convert -size 800x600 xc:black \( -size 300x200 xc:red \) -geometry +90+10 -composite result.png

Related

Imagemagick: Create 1 image out of 3 with luminance/overlay mask

I want to generate an image out of 3 images. One of these images is the background, one the shape mask and one the color of the shape.
Here are the images:
shape.png
(transparent background, white circle in the middle and black circle inside and gray circle inside the black one)
shapecolor.png
background.png
The background.png should be the overall background. On top of that is the shape and all white parts (and also the white in the gray parts) should be in the color of shapecolor.png
I used simple mono color images to make it easier but I use some textures in reality ^^
I have no idea how to solve this problem in Imagemagick, the tool is very powerful and the documentation is not so easy to understand. Tried to solve this for 3h, but did not get the result, which should look like this:
Can anyone help please?
Here is one way to do it in Imagemagick. In the second line, extract the alpha channel from omg.png and save it in an mpr: in-memory image and then delete the clone. Then I use the mpr: image later in the last step.
convert red.png img.png \
\( +clone -alpha extract -write mpr:alpha +delete \) \
-compose multiply -composite \
green.png +swap mpr:alpha -compose over -composite \
result.png

Image rotation relative to wrong (top right) point

I am trying to place a rotated image onto a blank canvas.
This is the command i am using:
convert "(" -size 1000x1000 xc:transparent ")" "(" "img.jpg" -virtual-pixel white -rotate -10.75 ")" -geometry +136+148 -composite "overlay.png" -geometry +0+0 -composite out.png
I would expect the image to appear at +136+148 rotated around its center. However, it appears to be rotated around its upper right corner instead.
I confirmed this in Photoshop:
This is the resulting image (using slightly different size but same parameters as my example command given here):
The 4 lines are the guides that mark the coordinates that define where the image sits. As you can see, the image is rotated -10.75 degrees. And the rotation center is the upper right corner.
Here i select the box at the correct coordinates in Photoshop:
And here i rotate it after setting the rotation point to the top right:
As you can see, the selection now matches the image as it was calculated by my convert command.
I have tried dealing with this for many hours. I tried switching to +distort and -distort and what not, but there i simply get either a cropped image or another wrongly positioned bounding box.
I don't know how to address this problem. What am i doing wrong? How can i tell -rotate to rotate my image around its center, not around the top right corner (why top right anyway?).
Thank you for your help!
The default gravity for offsetting is the northwest corner or top-left corner. The geometry offset you are using moves the top left corner of the padded rotated image after its background has been added and not the top left corner of the where the Input gets rotated. So I think that may be why you are not getting the expected result. ImageMagick -rotate does rotate about its center, but it fills the background out to make a complete rectangular image that is the bounding rectangle about the rotated image.
In ImageMagick, a better approach to what you did would be to use -gravity center and align the center of the rotated input image with the center of the transparent region in the overlay image.
Alternately, measure the 4 corners of your transparent region in the overlay and 4 corners of the input image and do a perspective or affine distortion to align the two.
Here is how to do it in bash unix syntax.
over1="122,186"
over2="466,118"
over3="510,345"
over4="166,411"
WxH=`convert -ping "Image.jpg" -format "%wx%h" info:`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`
ww=$((ww-1))
hh=$((hh-1))
in1="0,0"
in2="$ww,0"
in3="$ww,$hh"
in4="0,$hh"
convert overlay.png \
\( Image.jpg -virtual-pixel none +distort Perspective \
"$in1 $over1 $in2 $over2 $in3 $over3 $in4 $over4" \) \
-layers merge +repage \
out.png
See https://imagemagick.org/Usage/distorts/#perspective
Try using the offset geometry that aligns with the outer edges of your target area. That would be more along the red lines I've added here, not along the cyan lines in your example image.
Edited to add: For a method of finding the proper offset information to fill the hole and placing the image under the hole, see my other answer in this thread.
You can find the location of the cutout in your overlay image, then use that information to properly place your under image with a command like this...
convert overlay.png -background none \
\( +clone -alpha extract -trim \
-set option:offset +%[fx:page.x]+%[fx:page.y] +delete \) \
\( image.jpg -rotate -10.7 -set page %[offset] \) \
-set page %[fx:u.w]x%[fx:u.h] +swap -layers merge result.png
This makes use of the fact that the bounding box dimensions of the rotated input image are the same as the bounding box dimensions of the cutout of the transparent region in the overlay image.
That reads in the overlay, and inside parentheses it makes a clone of it, extracts the alpha channel, and trims the result to find the offset of the cutout. It saves the offset to a variable named "offset".
Then inside another set of parentheses it reads in the under image, rotates it the known -10.7 degrees, and uses that variable "offset" to set the paging offset on the rotated "image.jpg".
Then outside the parentheses it uses the width and height of the overlay to set the paging dimensions for the under image.
It finishes by swapping the order of the images to put the overlay on top, then merging the two layers to create the output.
Here is an alternate to GeeMack's excellent ImageMagick solution. This computes the center of the original input.jpg, and the center of the transparent region in the Overlay.png. Then it uses +distort SRT to translate and rotate the image before finally compositing with -layers merge.
convert Overlay.png \
\( +clone -alpha extract -trim -set option:center "%[fx:page.x+w/2],%[fx:page.y+h/2]" +delete \) \
\( Image.jpg -virtual-pixel none +distort SRT "%[fx:w/2],%[fx:h/2] 1 -10.7 %[center]" \) \
+swap -layers merge +repage result2.png
The second line is much line GeeMack's, but it computes the center of the transparent region's bounding box and saves that in the "center" argument and then deletes the trimmed image.
The third line computes the center of the Input.jpg image (before rotation). It then uses +distort SRT to translate from the input center, (scale=1) and rotate -10.7 and translate to the center of the transparent region's bounding box.
See https://imagemagick.org/Usage/distorts/#srt

Applying a circle gradient with imagemagick

I want to draw a circular gradient mask on an image, so that the image starts to fade at the outside of the circle with radius R, and fades to white with radius r < R. Is there a way to do this + how?
Example source image: (not the real one I'm trying to work with, but it doesn't matter)
If I do
convert flag1.png -fill white -draw "circle 400,234 200,200" flag2.png
then I get this:
In gimp I an do something like this with a radial gradient in another layer; my attempt looks crappy but this is vaguely what I want, except that it's not a smooth transition at the circle boundary, and my poor hand-eye coordination means I didn't get it centered:
Hmm: I muddled my way (via http://www.imagemagick.org/discourse-server/viewtopic.php?t=16692 ) to
convert flag1.png -size 800x468 radial-gradient:black-white -compose copy_opacity -composite flag3.png
which gives me something that's close to what I want with r=0 (never really completely fades out except at the very center); is there a way to expand to a white hole that fades out to a larger hole? And what does -compose copy_opacity -composite actually do?
Not sure what you are looking for exactly, but you could experiment with the percentages in this:
convert flag.png \( -size 800x468 radial-gradient:black-white -contrast-stretch 60%x0% \) -compose copy_opacity -composite flag3.png
The part in parentheses makes a black and white circle, and the -compose copy_opacity -composite part adopts that black and white circle as the alpha/transparency layer of the original flag image.
The parentheses ensure that the contrast stretch is only applied to the alpha/transparency layer and not the original coloured image.

Compositing premultiplied images using ImageMagick

I have two images. One is background with no alpha. The other is a white cloud. The alpha of the cloud image is premultiplied with black. When I composite them the white cloud has black in it, so it looks grey instead of white like it should. I'm doing:
convert -gravity Center bg.tga whitecloud.tga -composite comp.tga
Is there a way to composite premultiplied images in ImageMagick, or does the image have to be non-premultiplied? Can I make a premultiplied image non-premultiplied using ImageMagick?
Update:
Ok, here are the images as TGA for download:
http://acatysmoof.com/posting/problems/imagemagick/premultiplication/bg.tga
http://acatysmoof.com/posting/problems/imagemagick/premultiplication/whitecloud.tga
http://acatysmoof.com/posting/problems/imagemagick/premultiplication/aftereffects.tga
http://acatysmoof.com/posting/problems/imagemagick/premultiplication/imagemagick.tga
and in the same order as jpgs to view in your browser:
I tried all the modes provided, but none of them create the same result as After Effects.
It would be easier if you showed your images, but try adding -compose lighten before -composite in your command, like this:
convert a.tga b.tga -compose lighten -composite out.tga
Basically that will make ImageMagick choose the lighter pixel of the two images at every point.
If that doesn't work, try other blending modes
for b in $(identify -list compose); do
convert -label "$b" bg.tga whitecloud.tga -compose $b -composite miff:-
done | montage - -tile 5x out.png
I am kind of thinking Atop, Dissolve, SrcAtop and SrcOver might be your friends but have a look full-size and see what floats your boat. That would be
convert a.tga b.tga -compose Atop -composite out.tga
Here is an Imagemagick command that does what you want:
convert -gravity Center whitecloud.tga -fx "u/max(u.a, 1/255)" bg.tga +swap -composite -fx "u*u.a" comp.tga
What's happening here?
-fx command #1: Convert whitecloud.tga from premultiplied alpha to "normal". The max() operator is a special case to avoid dividing by zero.
+swap command: Make bg.tga the first image and the revised whitecloud.tga the second.
-composite these two regular, non-premultiplied images.
-fx command #2: take the result, and return to a premultiplied alpha format.
This gives exactly the same result as After Effects.
Note that, as I wrote it, it only works for an opaque bg.tga. You'd need to do some extra work to handle a transparent background image.
If you want to duplicate the After Effects result, then I believe what you want to do in ImageMagick is the following -- composite the background image with a white image using the cloud as a mask:
convert bg.tga \( -clone 0 -fill white -colorize 100 \) whitecloud.tga -compose over -composite cloud_blue.tga
I have posted a JPG result, but my .tga result is the same.

How to apply tile to specifics cordinates and size?

This is what I want to do:
1- I have this image (transparent on the center)
2- I have this "pattern"
3- I want to apply this pattern to a specific X and Y and also specify the size of the repitition. The expected result should look something like this:
Do you know how I can accomplish that?
Thank you.
The easiest way is probably to create the textured rectangle then place it over the top of the circle using composite.
convert circle.png \( -size 88x61 tile:texture.png \) -geometry +50+63 -composite result.png
[edit] If you want the texture underneath, you could do this:
convert -size 200x200 xc:transparent
-page +50+63 -size 88x61 tile:texture.png
-page +0+0 circle.png
-layers flatten result.png
I think that's self explanatory but 88x61 is the size of the rectangle, 200x200 is the size of the circle image, +50+63 is the location you want it to be placed at, circle.png is the transparent circle image, and texture.png is the seamless pattern.
I tested this with your images and it worked, but the pattern you included doesn't seem to be the full seamless version so it didn't come out looking exactly like your expected result.

Resources