Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Perspective Projection Distortion ImageMagick

For a project I am trying to create a perspective distortion of an image to match a DVD case front template. So I want to automate this using ImageMagick (CLI) but I have a hard time understanding the mathematical aspects of this transformation.

convert \
  -verbose mw2.png \
  -alpha set \
  -virtual-pixel transparent \
  -distort Perspective-Projection '0,0 0,0   0,0 0,0' \
   box.png

This code is en empty set of coordinates, I have read the documentation thoroughly but I can't seem to understand what parameter represents what point. The documentation gives me variables and names where I have no clue what they actually mean (more useful for a mathematical mastermind maybe). So if someone could explain me (visually prefered, or give me a link to useful information) on this subject because I have no clue on what I am doing. Just playing around with the parameters just wont do for this job and I need to calculate these points.

Here you will find an easy image of what I am trying to achieve (with CLI tools):

input example image

Update:

   convert \
        -virtual-pixel transparent \
        -size 159x92 \
        -verbose \
        cd_empty.png \
        \(mw2.png -distort Perspective '7,40 4,30   4,124 4,123   85,122 100,123   85,2 100,30'\) \
         -geometry +3+20 \
        -composite cover-after.png

Gives me as output:

cd_empty.png PNG 92x159 92x159+0+0 8-bit sRGB 16.1KB 0.000u 0:00.000
convert: unable to open image `(mw2.png': No such file or directory @ error/blob.c/OpenBlob/2641.
convert: unable to open file `(mw2.png' @ error/png.c/ReadPNGImage/3741.
convert: invalid argument for option Perspective : 'require at least 4 CPs' @ error/distort.c/GenerateCoefficients/807.
convert: no images defined `cover-after.png' @ error/convert.c/ConvertImageCommand/3044.

Correction by Kurt Pfeifle:

The command has a syntax error, because it does not surround the \( and \) delimiters by (at least one) blank on each side as required by ImageMagick!

Since there are no links to the source images provided, I cannot test the outcome of this corrected command:

   convert                         \
        -virtual-pixel transparent \
        -size 159x92               \
        -verbose                   \
         cd_empty.png              \
           \(                      \
           mw2.png -distort Perspective '7,40 4,30  4,124 4,123  85,122 100,123  85,2  100,30' \
           \)                      \
        -geometry +3+20            \
        -composite                 \
         cover-after.png
like image 893
Jurgen Avatar asked Sep 05 '12 07:09

Jurgen


2 Answers

Did you see this very detailed explanation of ImageMagick's distortion algorithms? It comes with quite a few illustrations as well.

From looking at your example image, my guess is that you'll get there using a Four Point Distortion Method.

Of course, the example you gave with the 0,0 0,0 0,0 0,0 parameter does not do what you want.

Many of the distortion methods available in ImageMagick work like this:

  • The method uses a set of pairs of control points.
  • The values are numbers (may be floating point, not only integer).
  • Each pair of control points represents a pixel coordinate.
  • Each set of four values represent a source image coordinate, followed immediately by the destination image coordinate.
  • Transfer the coordinates for each source image control point into the respective destination image control point exactly as given by the respective parameters.
  • Transfer all the other pixel's coordinates according to the distortion method given.

Example:

Sx1,Sy1 Dx1,Dy1   Sx2,Sy2 Dx2,Dy2   Sx3,Sy3 Dx3,Dy3   ...   Sxn,Syn Dxn,Dyn  

x is used to represent an X coordinate.
y is used to represent an Y coordinate.
1, 2, 3, ... n is used to represent the 1st, 2nd, 3rd, ... nth pixel.
S is used here for the source pixel.
D is used here for the destination pixel.

First: method -distort perspective

The distortion method perspective will make sure that straight lines in the source image will remain straight lines in the destination image. Other methods, like barrel or bilinearforward do not: they will distort straight lines into curves.

The -distort perspective requires a set of at least 4 pre-calculated pairs of pixel coordinates (where the last one may be zero). More than 4 pairs of pixel coordinates provide for more accurate distortions. So if you used for example:

-distort perspective '1,2  3,4     5,6  7,8     9,10  11,12     13,14  15,16'

(for readability reasons using more {optional} blanks between the mapping pairs than required) would mean:

  1. From the source image take pixel at coordinate (1,2) and paint it at coordinate (3,4) in the destination image.
  2. From the source image take pixel at coordinate (5,6) and paint it at coordinate (7,8) in the destination image.
  3. From the source image take pixel at coordinate (9,10) and paint it at coordinate (11,12) in the destination image.
  4. From the source image take pixel at coordinate (13,14) and paint it at coordinate (15,16) in the destination image.

You may have seen photo images where the vertical lines (like the corners of building walls) do not look vertical at all (due to some tilting of the camera when taking the snap). The method -distort perspective can rectify this.

It can even achieve things like this, 'straightening' or 'rectifying' one face of a building that appears in the 'correct' perspective of the original photo:

original image ==> distorted image

The control points used for this distortion are indicated by the corners of the red (source controls) and blue rectangles (destination controls) drawn over the original image:

source control points: corners of 'red' ==> destination control points: corners of 'blue'

This particular distortion used

-distort perspective '7,40 4,30   4,124 4,123   85,122 100,123   85,2 100,30'

Complete command for your copy'n'paste pleasure:

convert                                                                      \
  -verbose                                                                   \
   http://i.stack.imgur.com/SN7sm.jpg                                        \
  -matte                                                                     \
  -virtual-pixel transparent                                                 \
  -distort perspective '7,40 4,30  4,124 4,123  85,122 100,123  85,2 100,30' \
   output.png

Second: method -distort perspective-projection

The method -distort perspective-projection is derived from the easier understandable perspective method. It achieves the exactly same distortion result as -distort perspective does, but doesn't use (at least) 4 pairs of coordinate values (at least 16 integers) as parameter, but 8 floating point coefficients.

It uses...

  1. A set of exactly 8 pre-calculated coefficients;
  2. Each of these coefficients is a floating point value (unlike with -distort perspective, where for values only integers are allowed);
  3. These 8 values represent a matrix of the form

     sx   ry   tx
     rx   sy   ty
     px   py

    which is used to calculate the destination pixels from the source pixels according to this formula:

    X-of-destination = (sx*xs + ry+ys +tx) / (px*xs + py*ys +1)
    Y-of-destination = (rx*xs + sy+ys +ty) / (px*xs + py*ys +1)
    
    (TO BE DONE -- 
        I've no time right now to find out how to
        properly format + put formulas into the SO editor)
    

To avoid (the more difficult) calculating of the 8 required cooefficients for a re-usable -distort perspective-projection method, you can...

  • FIRST, (more easily) calculate the coordinates for a -distort perspective ,
  • SECOND, run this -distort perspective with a -verbose parameter added,
  • LAST, read the 8 coefficients from the output printed to stderr .

The (above quoted) complete command example would spit out this info:

Perspective Projection:
  -distort PerspectiveProjection \
    '1.945622, 0.071451, -12.187838, 0.799032, 
     1.276214, -24.470275, 0.006258, 0.000715'
like image 155
Kurt Pfeifle Avatar answered Nov 05 '22 14:11

Kurt Pfeifle


Thanks to ImageMagick Distorting Images Documentation, I ended up with this clean-understandable code:

$points = array(

                0,0, # Source Top Left
                0,0, # Destination Top Left
                
                0,490, # Source Bottom Left 
                2.2,512, # Destination Bottom Left 
                
                490,838, # Source Bottom Right 
                490,768, # Destination Bottom Right 
                
                838,0, # Source Top Right 
                838,50 # Destination Top Right 

                );

$imagick->distortImage(Imagick::DISTORTION_PERSPECTIVE, $points, false);

Please keep in mind that each set of coordinates are separated into two parts. The first is the X axis and the second is the Y axis .. so when we say 838,0 at Destination Right Top, we mean the X axis of Destination Right Top is 838 and the Y axis of it is zero (0).

like image 1
Amirhossein Hosseinpour Avatar answered Nov 05 '22 14:11

Amirhossein Hosseinpour