Is it possible to dynamically calculate the required rotation angle while processing an image?

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
I'd like to place a watermark over a number of images. Since the dimensions of these images vary, but the watermark should always have the maximal possible size at constant proportions, I have to calculate the perfect angle for the resizing. (It should look like that. Not like that.)

I use the following algorithm:

Code: Select all

ratio1 = pic1_width / pic1_height
ratio2 = pic2_width / pic2_height
angle = atan ((ratio1 - ratio2) / (1 - ratio1 * ratio2))
For a detailed explanation see here.

Is there any way to do this calculation dynamically during image processing?

I'm using ImageMagick 6.8.9-9 Q16 x86_64 on Ubuntu Linux.
In Bash it might look something like this:

Code: Select all

convert -background none -gravity center -density 300 "$pic" \
		\( "$wmark" -rotate "%[fx:atan(((u.w/u.h)-(v.w/v.h))/(1-(u.w/u.h)*(v.w/v.h)))]" \) \
		-compose over -composite "$result"
The code does not rotate the image. I think that's because "-rotate" does not accept "%[fx:]" arguments? Unfortunately, I have not been able to find clear information about this so far ...
In addition, the variables "w" and "h" seem to have the value "0" ... which I also do not understand.

I would like to extend GeeMacks solution from this thread.

Best regards
AVoeee
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by fmw42 »

An answer to a similar question is at viewtopic.php?f=1&t=33414
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
first of all: thanks for the reply!
fmw42 wrote: 2018-01-25T11:02:58-07:00 An answer to a similar question is at viewtopic.php?f=1&t=33414
Unfortunately, this is my own thread. Although I am very grateful for the answers there, my current question was not answered.

To briefly explain why I opened a new thread for this topic:
  • In the first thread I searched for an algorithm with which I can calculate the desired angle.
    So it was the approach I was looking for.
  • In this thread I ask if it is possible to perform a computation at runtime that accesses the dimensions of the currently processed images. In addition, I would like to know if I can use the result e.g. to rotate an image.
    The answer from the first thread serves as a case study.
To refer to this case example: At the moment, I have to execute four commands to get a watermarked image:
  1. Get the dimensions of the watermark.
  2. Get the dimensions of the underlying image (at 300 dpi).
  3. Calculate the necessary angle.
  4. Composing the picture (with the actual rotating and resizing).
The user GeeMac has shown that it is possible to integrate the step for "getting the dimensions" in the last step. Therefore, I ask if it is possible to integrate the calculation also into it.

Best regards
AVoeee
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by snibgo »

For "-fx" in "-rotate", you need v7, magick not convert.

"atan" returns angles in radians but "-rotate" needs degrees.

u.w and v.w refer to two images in the current list. So you need to have both images inside the parentheses.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by fmw42 »

Inline access and usage of the image dimensions can be done in IM 7. IM 6 does not have as many features for inline computation and usage.
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
thanks for the replies.

I will try to switch to IM7 next week.

Best regards
AFoeee
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
I have now switched to IM7. I am using ImageMagick 7.0.7-22 Q16 x86_64.

However, I am still perplexed how to perform the calculation.

snibgo wrote: 2018-01-26T03:20:17-07:00 "atan" returns angles in radians but "-rotate" needs degrees.
Thanks for pointing this out. I'm now converting the radians to degrees via "* 180 / Pi".

snibgo wrote: 2018-01-26T03:20:17-07:00 u.w and v.w refer to two images in the current list. So you need to have both images inside the parentheses.
That makes perfect sense. But if I put the underlying image in the parentheses, it does also rotate.


Here's my current attempt in Bash:

Code: Select all

wmark="watermark.png"
file="some.pdf"
result="result.jpg"

rotation="%[fx:ratioUI=u.w/u.h; ratioWM=v.w/v.h; atan((ratioUI-ratioWM) / (1-ratioUI*ratioWM)) * 180 / Pi]"

magick -background none -density 300 "$file" \
	-bordercolor none -border 1x1 -trim +repage \
       	-set option:dim "%wx%h" \
	\( "$wmark" -rotate "$rotation" -resize "%[dim]" \) \
	-compose over -gravity center -composite \
	"$result"

I explain briefly my thoughts behind it:
  • as far as I could observe, it makes no difference where I put the definition of the background color, so I set it before reading the image.
  • I also set the density before the image is read. I do this since I also read PDF files and these may otherwise become blurred (?)
  • after the image has been read in, I remove a potential transparent border.
  • then I get the dimensions of the underlying image and store this information in a variable. (This was originally suggested by the user fmw42 in this thread).
  • then I read in the watermark and want to:
    1. rotate it by the calculated degrees
    2. resize it to the dimensions of the underlying image.
  • Finally, I put the two pictures together.

Unfortunately the watermark is not rotated!

Best regards
AVoeee
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by snibgo »

AVoeee wrote:That makes perfect sense. But if I put the underlying image in the parentheses, it does also rotate.
Yes, so delete it.

If you use u.w and v.w, there must be two images in the current list to get the numbers from. If there aren't two images, it won't work. So do the rotation, which will rotate both images in the list, and then "-delete" whichever one you don't want.

(An alternative is to use "-distort SRT" and a more complex expression that will only rotate one image, which saves time. GeeMack often shows how to do this. But this still needs both images in the list, and still needs one to be deleted.)
snibgo's IM pages: im.snibgo.com
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
thanks for your reply.

I tried to follow your hints and wrote this code:

Code: Select all

wmark="watermark.png"
file="some.pdf"
result="result.jpg"

rotation="%[fx: ratioUI=u.w/u.h; ratioWM=v.w/v.h; atan((ratioUI-ratioWM) / (1-ratioUI * ratioWM)) * 180 / Pi]"

magick -background none -density 300 "$file" \
	-bordercolor none -border 1x1 -trim +repage \
	-set option:dim "%wx%h" \
	\( -clone 0 "$wmark" +swap -rotate "$rotation" +delete -resize "%[dim]" \) \
	-compose over -gravity center -composite \
	"$result"
This command seems to work. (I have not tested it extensively yet.)

Just to be sure: There is no way to access within the "%[fx: ..] part e.g. the variables that I defined using "-set option:xxx" or similar? I can't help it, but this feels like a "workaround".

Best regards
AVoeee
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by snibgo »

When an "fx:" expression uses dimensions of images, those images must be in the current list.

Your "-rotate" includes the fx expression. An alternative is to put the fx expression in an earlier "-set option:DEGS %[fx:..blah..]", so that is when the dimensions of the two images are required. Then, you would have "-rotate %[DEGS]" when you need it.
snibgo's IM pages: im.snibgo.com
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by GeeMack »

AVoeee wrote: 2018-02-04T03:03:26-07:00I have now switched to IM7. I am using ImageMagick 7.0.7-22 Q16 x86_64.

However, I am still perplexed how to perform the calculation.
Take a look at this example command...

Code: Select all

magick -background none -density 300 "$file" \
   -bordercolor none -border 1x1 -trim +repage \
   "$wmark" \
   -rotate "%[fx:t*(atan(((u.w/u.h)-(v.w/v.h))/(1-(u.w/u.h)*(v.w/v.h)))*180/Pi)]" \
   -resize "%[fx:u.w]x%[fx:u.h]" \
   -compose over -gravity center -composite \
      "$result"
It reads in the main input image, adds the 1x1 border, and trims it.

Then it reads in the watermark image, so now there are two image in the stack.

The next line uses the formula you've written to rotate just the watermark image. That happens because I multiplied your formula by "t", which is the position of the image in the stack. The main input image is number "0", so it rotates zero degrees. The watermark is image "1" in the stack, so it rotates "1" times the formula.

Next is the resize. By using "u.w" and "u.h" it will resize both images to the dimensions of the main input image, which is already that size so it remains unchanged.

Then the "-compose over -gravity center -composite" places the rotated sized watermark over the input image.

Finish by naming the output file and you're done.
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
GeeMack wrote: 2018-02-04T10:10:30-07:00

Code: Select all

-rotate "%[fx:t*(atan(((u.w/u.h)-(v.w/v.h))/(1-(u.w/u.h)*(v.w/v.h)))*180/Pi)]" \
The next line uses the formula you've written to rotate just the watermark image. That happens because I multiplied your formula by "t", which is the position of the image in the stack. The main input image is number "0", so it rotates zero degrees. The watermark is image "1" in the stack, so it rotates "1" times the formula.
That is a pretty elegant way to solve this problem!


Thanks to both of you! That resolved my problem. :)

Best regards
AVoeee
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
I have an additional question and I'm unsure if I should open a new thread.

When I convert images which have a transparent background to jpgs, the background turns black. (As can be seen here).
That seems to be a very common problem and I have also found some approaches and explanations in the forum.

But all the approaches I have found so far do suggest that transparency should be replaced by a color (on all layers of the image). But it is precisely this transparency that I need so I can place the rotated watermark on the underlying image ... :(

These approaches lead to something like this. So the transparency of the watermark turns also white and covers the whole picture.

Is there a way that all layers are taken into account and thus only the pixels that remained transparent at the end are replaced with a given color?
I've read that there are several options for "-compose" and "-composite" that will cause the image to merge instead of placing individual layers over each other. Could that be a possible solution?

The test image is available here.
The test "watermark" is available there.

Please kindly note that I am aware that png supports transparency. Nevertheless, I am interested in whether there is a way to achieve this with jpg.

Best regards
AVoeee
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by fmw42 »

JPG does not support transparency. So if you are making a JPG output, then you must flatten your processing over some background color or image, otherwise the JPG will replace any transparency with black (or the color or texture in the intermediate image under the transparent area). Perhaps you understand this already.

But to understand what you are trying to do, it would be helpful to see your command line that produced the resulting image you showed and explain where the problem is in the resulting image. It is not clear to me what you want.
AVoeee
Posts: 15
Joined: 2018-01-14T12:17:32-07:00
Authentication code: 1152

Re: Is it possible to dynamically calculate the required rotation angle while processing an image?

Post by AVoeee »

Hello,
@fmw42: Sorry, I had overlooked that it was not made clear which approach I actually use. I'm using Geemack's approach from this thread.
fmw42 wrote: 2018-02-05T14:27:15-07:00 So if you are making a JPG output, then you must flatten your processing over some background color or image, otherwise the JPG will replace any transparency with black (or the color or texture in the intermediate image under the transparent area).
Thanks to your pointer, I found this excellent guide.
You don't need to create an initial canvas as we did above, you can instead let "-flatten" create one for you. The canvas color will be the current "-background" color, while its size is defined by the first images Virtual Canvas size.
So I wrote the following bash code, which apparently fixes the problem:

Code: Select all

wmark="watermark.png"
file="some.pdf"
result="result.jpg"

rotation="%[fx:ratioUF=u.w/u.h; ratioWM=v.w/v.h; t*(atan((ratioUF-ratioWM)/(1-ratioUF*ratioWM))*180/Pi)]"

magick  -define registry:temporary-path=/tmp/imagemagick \
	-background none \
	-density 300 \
        "$file" \
        -bordercolor none -border 1x1 -trim +repage \
        "$wmark" \
        -rotate "$rotation" \
        -resize "%[fx:u.w]x%[fx:u.h]" \
        -compose over -gravity center -composite \
	-background white \
	-flatten \
        "$result"
My mistake was that I did not understand that I can set the "-background" multiple times. I tried to do everything with one "-background".

Best regards
AVoeee
Post Reply