Image rotation relative to wrong (top right) point - imagemagick

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

Related

ImageMagick get image side only - not a edge detection problem

This is not a finding edge problem but I am trying to find the background color of the image, in order to find it, I am trying to get the edge of the image and guess the best color.
In order to do so, I want to remove the center of the image and just get image like a frame with transparent center.
Is it possible through ImageMagick?
For example
If want
Try this tested on Windows with IM V7:
magick "input.png" ( -size 200x200 xc:black ) -gravity center -compose DstOut -composite "output.png"
Takes the original photo, creates a rectangular mask, places it over the middle of the image and "cuts" out the rectangle
If the input is not a png ( for instance a jpg ) you will have to do some work setting the alpha channel
EDIT: This seems to work for both jpg and png images
magick "input.png" -alpha on ( -size 200x200 xc:black ) -gravity center -compose DstOut -composite "output.png"
I'll offer a simple variation on Bonzo's solution. This command allows you to specify in pixels the amount of edge you want to keep...
magick input.jpg -alpha on -bordercolor none -background none ^
( +clone -shave 24 -border 24 ) -compose dstout -composite output.png
It reads the input image, sets the alpha "on", and sets the border and background colors to "none".
Then inside the parentheses it makes a clone of the input image, shaves off the amount you want to retain around the edges, then adds that amount back as a transparent border all around. That will be the mask.
Then after the parentheses use a compose method of "dstout" to composite that mask onto the input image, which results in a transparent "hole" in the image with your specified amount of the original edge retained.
If you want to keep different amounts from the vertical and horizontal edges, specify those amounts in the shave and border operations...
... -shave 24x32 -border 24x32 ...
If you're using IMv7 you can even use FX expressions to specify the widths...
... -set option:v1 %[fx:(w+h)/2*0.1] -shave %[v1] -border %[v1] ...
The command is in Windows syntax using IMv7. Change "magick" to "convert" to use it with IMv6. To make it work in *nix you need to change the continued-line caret "^" to a backslash "\" and escape the parentheses with backslashes "\(...\)".

Wrapping an image over a product image convexly

What I want: When I apply an image over the pillow texture the artwork of the image should wrap convexly on the pillow.
Here is the link for the desired image
Above output is the correct output that I want
Note: In the above image, you can see the image is wrapped around the corners and convex from the center.
Problem: But when I apply image over the pillow texture image artwork is not curved convexly.
Here is the the output I currently have
Also, for reference,
here is the product image that I am using
And here is the artwork, that I am overlaying it with
Also, in the product image linked above, as you can see, there is some distortion in the top left corner, if I am overlaying it with any design, how can I achieve that distortion as well.
I am new to imagemagick, so are there any good resources to learn from and practice with?
Here is how to do that in ImageMagick.
Input:
First make a mask for the pillow. ImageMagick could not get a good mask, so I used http://remove.bg to make the background transparent and then extracted the alpha channel and got this:
I then measured the size and offset of the white part of the mask:
convert mask.png -format "%#" info:
642x646+78+77
Then I processed the images. I resized the text image, then applied pincushion distortion (opposite of barrel distortion) and inserted it into a white image the size of the pillow at the offset location from above. Then using the mask, I did a blend composite of the pillow and distorted image to make the result. See https://imagemagick.org/Usage/distorts/#barrel
convert pillow.jpg \
\( -size 800x800 xc:white \
\( pillow_overlay.jpg -resize 646x646 -distort barrel "0.0 0.0 -0.2 1.3" \) \
-geometry +78+77 -compose over -composite +geometry \) \
mask.png -define compose:args=60,40 -compose blend -composite \
pillow_new.jpg

Relative imagemagick transforms: Relative Crop?

I'm trying to execute the following set of transformations without knowing the absolute width or height of the target image:
1. Crop image A by 10px on every size :: A1
2. Create duplicate of A1 translating image by 1270px on the y-axis :: A2
3. Create montage of A1 && A2 :: A3
4. Translate A3 by 385px on the y-axis :: A4
5. Crop A4 at 100% width, and 1270px tall (box from 0,0 to WIDTH,1270) :: A5
My issue is how do I do steps 1 and 5 with relative coordinates? Below are my steps that I've come up with:
1. convert A.jpg -shave 10x10 A1.jpg
2. convert A1.jpg -page +0-1270 -background none -flatten A2.jpg
3. montage A1.jpg A2.jpg -geometry +0+0 A3.jpg
4. convert A3.jpg -page +0-385 -background none -flatten A4.jpg
5. convert A4.jpg ????? A5.jpg
Updated Answer
Ok, I think I understand what you want a bit better now. Here's how I would do it:
convert start.jpg -crop +0+383 +repage \
\( -clone 0 -crop x1270+0+0 \) \
\( -clone 0 -crop x1270+0+1270 \) \
-delete 0 +append result.jpg
The first line says..."Take the starting image and crop off the top 383 pixels and reset all the sizes to match what is left. Call that the first image from now onwards."
The second line says..."To one side (because of the parentheses), clone the first image and crop out the full width and 1270 pixels in height from the top. Hold onto that till later - i.e. keep it in the image list.".
The third line says..."To one side (because of the parentheses), clone the first image, and crop out a piece the full width and 1270 pixels in height, but start 1270 pixels from the top. Hold onto that till later - i.e. keep it in the image list."
The last line says..."Delete the initial image, and then take the two slices in the image list and append them side-by-side, Save as result.jpg".
Original Answer
I think we will need to work together on this one, but it can be done. Let's start with a concrete image that is a 400x250 gradient with a 15px black border:
convert -size 250x400 gradient:red-cyan -rotate 90 -bordercolor black -border 15 A.png
So, step 1.
convert A.png -shave 10x10 A1.png
Step 2&3. I don't get the point of these! You appear to be trying to add transparent space to a JPEG which doesn't support transparency. Also, I can't tell what you are montaging where. Please try and express what you want with these two steps in plain English, like "add a transparent area N pixels wide/tall above/below, left/right of A2", or maybe "add a transparent area such that the new dimensions are X,Y and the original A2 image is at the bottom-right of the new canvas."
If I have a stab at steps 2&3, I'll guess this (and add a purple border so you can see it on StackOverflow's white background). I am appending a transparent area 1270 pixels tall below the image.
convert A.png -background none -shave 10x10 xc:none[1x1270\!] -append b.png
Step 4&5. As above.
Or maybe you mean this:
convert A.png -background magenta -shave 10x10 -gravity southeast -extent 1270x385 result.png
I think we can get you down to a single command, with no intermediate files, if we understand your needs.

Imagemagick: distorting images on top of background?

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

imagemagick composite with min width but varying height

I want to have a background image with another image composited over top to the bottom edge. The final image will have maximum width (say, 1000px, but may be less). The composited image can shrink in width but always needs to be at the bottom. I can't seem to find a way get this all done in one command with imagemagick.
Here is some dummy images as an example.
Image to composite over the background:
Here are two examples of end products I want:
This one is 960px wide, but yet the composited image is flush bottom and left/right edge.
This one is quite narrow, but the composited image has shrunk to make it flush bottom/left/right.
Since the images may vary in size and aspect ratio, I'd rather not have to do some sort of external calculation to scale and position the composited image. I feel like this should be possible within imagemagick, right?
It would be easiest to identify the width of background image beforehand.
#!/bin/bash
# Get background width
WIDTH=`convert background.jpg -format "%w" info:`
# Apply composite
convert background.jpg \
\( arrows.png -resize "${WIDTH}x" \) \
-alpha set \
-gravity South \
-compose ATop \
-composite output.png
The \( arrows.png -resize "${WIDTH}x" \) is a subprocess for matching widths, and -gravity South will keep the arrows anchored to the bottom.

Resources