optimizing 'convert' speed

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?".
User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T16:50:06-07:00

jgrauman wrote:Thanks for the suggestion, but I'm not sure that is what I want. Can you clarify? I'm rotating and scaling images that came from several long videos. So I only need to do one rotate/scale per image, not multiple rotates per image. So it doesn't look like this helps, but maybe I'm missing something.
The technique makes N copies of the original image, but then applies one single distortion on each copy. the distortion for each copy is different. I repeat: Only one (1) distortion is applied to each copy of the image. The image is not distorted multiple times.

The distortion is modified by the index of the image copy being modified, so each copy (of the original image) gets distorted slightly differentially.

For a video! you already have a sequence of images! As such each image being distorted can be a different frame of the original image. That means in the ONE command you can distort a video, with each frame being distorts slightly differentially to the previous frame. That is while you are rotating the video, the video could still be actually playing as normal!!!!

Cool hey. I'd love a image sequence to try this myself!


This distortion method could eventually become part of a shape morphing technique!
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T17:04:58-07:00

jgrauman wrote:

Code: Select all

convert in.tga -set option:distort:viewport "640x640+400+220" -filter point +distort SRT '.6,1.2' -scale 640x480\! out.tga
the input is at:
http://grauman.com/in.tga
Hmmm the SRT can itself do scaling. which you are making use of. As such it is more a matter of figuring out the right scale for the rotation. If you then use -distort the 'viewport' is simply the original images dimensions.

It is figuring out the scale factor that is tricky. PS: shrinking the original image is never a good solution -- you loose image information!


Before going any further. Lets step back and figure out exactly what you really want!
You are rotating each frame of your video by a increasing amount of rotation.
You are also enlarging the image so as to get no undefined 'virtual pixels' in the results.

What is your final limits of this? What should the last frame look like?
In other words. What do you want exactly? Rather than how you think it should be done.


I ask this as, as it stands the image will rotate and enlarge at first, but as it stands there will be a point (at a 45 degree rotation) where the image will start shrinking again as the rotation proceeds. That does not sound like what you are after!
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T17:37:08-07:00

Taking the formula from the page Fred found...
http://www.mathhelpforum.com/math-help/ ... 02791.html

Which gives the location of the corner relative to the center of the image.
I just wanted a scaling ratio.
So I grabbed the 'X' coordinate

a=angle of rotation (radians)
w=width
h=height
X coord = wh/(w*sin(a)+h*cos(a))

and turned it into a ratio so as to scale it to be 'w' wide. so

scale = w/x_coord

which becomes (w in the ratio cancelling out, and assuming landscale - or larger width)

scale = ( w*sin(a) + h*cos(a) ) / h

NOTE as this is a ratio it did not matter that I used w,h and not w/2,h/2
Also I get exactly the same formula if I made the ratio using the y coodinate with height.
The 'h' on the bottom represents the smaller dimension of width and height!

at an angle of zero scale = 1.0
at 45 degrees (maxium scale) scale = 1.65
at 90 degrees scale = 1.33

that seems about right.

so at an angle of say 10 degrees rotation

Code: Select all

  convert in.tga -filter point -distort SRT '%[fx:(w*sin(10*pi/180)+h*cos(10*pi/180))/h], 10'  show:
Or generate 30 frames with increasing rotation of 3 degree increments, (note t= image index)

Code: Select all

convert in.tga  -duplicate 29 \
           -filter point -distort SRT '%[fx:(w*sin(3*t*pi/180)+h*cos(3*t*pi/180))/h], %[fx:3*t]' \
           frames_%02.png
NOTE this does not multiply-distort. each frame is distorted just once!

PERFECT! According to what is described in any case!
Of course instead of-duplicate, you can just load 30 frames of the original video :-)
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
fmw42
Posts: 22105
Joined: 2007-07-02T17:14:51-07:00
Location: Sunnyvale, California, USA

Re: optimizing 'convert' speed

Post by fmw42 » 2011-06-02T19:54:15-07:00

taking Anthony's concept (which magnifies the result) one step further to achieve a rotation with no change of scale and crop to maximum size without showing the background.


Image

convert zelda1.jpg -rotate 45 zelda1_45a.jpg

Image

convert zelda1.jpg -rotate
convert zelda1.jpg -filter point \
-distort SRT '%[fx:(w*sin(45*pi/180)+h*cos(45*pi/180))/h], 45' \
+distort SRT '%[fx:h/(w*sin(45*pi/180)+h*cos(45*pi/180))], 0' \
zelda1_45.jpg

Image

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T20:59:59-07:00

You should have been able to do that as a single viewport distortion. Take the corner X,Y coordinate from the linked math forum page, to determine X,Y coordinates needed. However remember it will be smaller than the original, and you may have to reduce the size by one as the viewport or crop needs integer arguments.

My method does as the original user requested,
Rotate, and scale image to fit original images bounds without virtual pixels.

However I am not certain he has described what he really wants. But I answered what he requested. I have asked if this is actually want he wants.

It is not clear for example if he just wanted to correct the picture angle, or actually create a rotating sequence, as I have done.The former only occurred to me AFTER seeing some of the links you provided. But the solution is still basically the same.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
fmw42
Posts: 22105
Joined: 2007-07-02T17:14:51-07:00
Location: Sunnyvale, California, USA

Re: optimizing 'convert' speed

Post by fmw42 » 2011-06-02T21:08:45-07:00

Anthony wrote:You should have been above to do that as a single viewport rotation. Take the corner X,Y coordinate from the linked math forum page, to determine X,Y coordinates. However remember it will be smaller than the original.
Can you provide that command line to reproduce what I did above in one distort, if convenient, as I am confused, since you still have to rotate the image then crop it. Thanks.

Fred

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T21:42:52-07:00

Rotate by an angle without scaling....

Hmm extracting 'common rotio' using shell variables (at least until FX can read other settings and global values, to save on 'constant' calculations)

Code: Select all

angle=10
ratio=`convert in.tga -format "%[fx:min(w,h)/(w*sin($angle*pi/180)+h*cos($angle*pi/180))]" info:`

convert in.tga -filter point \
    -set option:distort:viewport \
         "%[fx:floor(w*$ratio)]x%[fx:floor(h*$ratio)]+%[fx:ceil((w-w*$ratio)/2)]+%[fx:ceil((h-h*$ratio)/2)]" \
    +distort SRT $angle +repage  result.png
The use of 'min' removes the need for landscape/portrait restrictions.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-02T22:15:51-07:00

I have places basic examples of the above types of image rotations, (with and without scaling) in IM Examples. (will appear very shortly)
http://www.imagemagick.org/Usage/distor ... te_methods

This last method should also be exampled as a 'rotation correction' in "Photo Handling"...
I think I even have a picture for this.

EDIT: Done (online soon)
http://www.imagemagick.org/Usage/photos/#rotation
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

jgrauman
Posts: 15
Joined: 2010-06-15T23:42:05-07:00
Authentication code: 8675308

Re: optimizing 'convert' speed

Post by jgrauman » 2011-06-03T09:13:42-07:00

Hey wow, this is great! I knew there would be a formula to calculate this, but my trig/geometry was too rusty to figure it out! I had just written a program to calculate it iteratively, but the direct formula is much better. Basically what I'm doing is like your new example, my videos were taken with a slight rotational error (not a very good tripod), and so I'm doing the same rotational correction to thousands of images. However, each video has a slightly different angular error, so I need to calculate the angle and scale for each video, and then apply that scale/angle to each sequence of images. Thanks, it will have to be next week when I get to look at this in depth, but it looks real helpful!

Josh

jgrauman
Posts: 15
Joined: 2010-06-15T23:42:05-07:00
Authentication code: 8675308

Re: optimizing 'convert' speed

Post by jgrauman » 2011-06-03T09:32:36-07:00

Just for clarity's sake, let me explain the whole process.

1) I start with thousands of images for each video that have been extracted from the video with ffmpeg.

2) These images all have a slight rotational error that I want to correct before turning back into video.

3) The original images are 1440x1080 and are anamorphic (the 'real' resolution should be 1920x1080, the pixels aren't square)

4) I want the output video to be 640x480 with rotation applied at the center of my input image.

5) I want the operation to be as fast as possible since there are around 216000 images for *each* video (there are about 50 videos, around two hours each)!!! I'm hoping to have the project done by the end of summer. Some of my trial convert commands are taking around .2 seconds, which is doable, but I'm trying to shave it down (and I just ordered a faster processor!). I'm going to be converting around 10,000,000 images...

5) So, here's what I was thinking. Crop the image to a square (1080x1080) to throw out pixels that will never be used and should make the rest of the operations faster. Since the image is anamorphic, a square image before scaling has the same aspect ratio as 640x480 (the desired final output). Then I will do a SRT to rotate and scale the image down so that I have a 640x640 square with no 'colored corners'. Then I will scale that to 640x480. I actually just realized that an SRT can scale x and y separately, so maybe I can figure out separate x and y scaling factors and do everything with a single SRT and viewport crop! I'll have to look at this next week as I have a busy weekend coming up. But thanks so much everyone!

User avatar
fmw42
Posts: 22105
Joined: 2007-07-02T17:14:51-07:00
Location: Sunnyvale, California, USA

Re: optimizing 'convert' speed

Post by fmw42 » 2011-06-03T10:07:50-07:00

Anthony,

I am confused that the viewport works before the rotation to achieve a crop. I was under the impression that it just controlled what data was processed by the distort. Can you explain further? Is this because you compute what data is needed by the rotate so that +distort ends up with the right amount of data?

Anyway, using the same zelda1.jpg image above and 45 degree rotation, your result is a few pixels smaller (181x181) than my result above (184x184). Your result is correct as the image was 256 rotated 45 degrees and inscribed, so it should be

convert xc: -format "%[fx:256/sqrt(2)]" info:
181.019

Very nice examples on your web page. Glad you referenced that Math Help Forum. I think this is an important example that others will be using often.


Fred

User avatar
anthony
Posts: 8870
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: optimizing 'convert' speed

Post by anthony » 2011-06-03T17:50:03-07:00

jgrauman wrote:3) The original images are 1440x1080 and are anamorphic (the 'real' resolution should be 1920x1080, the pixels aren't square)
I thought somethign was odd about the video!

However you have a new problem. As the pixels are not square a rotated image will become skewed. You will thus probably need to use calculated control points (in the anamorphic space) to rotate the image so that the image remains un-skewed by the rotation.

That is set a frame of three pixels (probably as a right angled triangle, and then do the caculations to rotate that triangle in the anamorphic (horizontally compressed space) to 1: rotate and 2:scale the image. You would use "-distort Affine" for the task. Note the scale may also need to be re-calculated using anamorphic distorted units too, not certain.

I would make one coordinate the perfect center of the image, and the others just relative vectors from that point.
Much like the text distortion examples in http://www.imagemagick.org/Usage/distorts/#affine
5) So, here's what I was thinking. Crop the image to a square (1080x1080) to throw out pixels that will never be used and should make the rest of the operations faster. Since the image is anamorphic, a square image before scaling has the same aspect ratio as 640x480 (the desired final output). Then I will do a SRT to rotate and scale the image down so that I have a 640x640 square with no 'colored corners'. Then I will scale that to 640x480. I actually just realized that an SRT can scale x and y separately, so maybe I can figure out separate x and y scaling factors and do everything with a single SRT and viewport crop! I'll have to look at this next week as I have a busy weekend coming up. But thanks so much everyone!
Doing the calculation in that way may work, That is using control points based on a square right angled triangle (but with coordinates that are 640x480) but the rotate will not be a true rotate. You will still need to use a "-distort Affine" to get it right.

Fred is pretty good with the maths, so he may be able to help work out the control point coordinates for some specific 'angle', of rotation, image size (aspect ratio), and pixel aspect ratio. I would probably even add it as a specific example in the 'Video' section, of IM Example when we have the corrected formula. (without scale to start with).
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
http://www.imagemagick.org/Usage/

jgrauman
Posts: 15
Joined: 2010-06-15T23:42:05-07:00
Authentication code: 8675308

Re: optimizing 'convert' speed

Post by jgrauman » 2011-06-04T10:41:17-07:00

I'm thinking now the SRT can handle this for me perfectly. I didn't realize I could do a scale that had different x and y components. So I can calculate the x and y scale factors such that my original 1920x1080 image will get scaled down to something that when rotated will yield a 640x480 center image. I think I pretty much have it figured out now. It would be nice to figure out all the math, but it was just easier for me to write a simple program to calculate the scaling and cropping values iteratively... Thanks!

jgrauman
Posts: 15
Joined: 2010-06-15T23:42:05-07:00
Authentication code: 8675308

Re: optimizing 'convert' speed

Post by jgrauman » 2011-06-04T22:29:14-07:00

It's working perfectly now. Here's the final command for those interested. I wrote a program to calculate the scale values (here .604 and .453) for a given rotation (here 0.8), and everything else was straightforward:

convert in.tga -background white -virtual-pixel background -set option:distort:viewport "640x480+400+300" -filter point +distort SRT '720,540,.604,.453,.8' out.tga

Thanks!

jgrauman
Posts: 15
Joined: 2010-06-15T23:42:05-07:00
Authentication code: 8675308

Re: optimizing 'convert' speed

Post by jgrauman » 2011-06-05T08:50:58-07:00

Quick followup question:

For the SRT, in order to define the x and y scale components separately, you need to use the form of SRT with at least 5 parameters: X,Y ScaleX,ScaleY Angle. I would like the X and Y to be set to the center of the image automatically, what would the formula for that be? Thanks!

Post Reply