imagemagickcommand-line-interfaceperspective

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

Solution

  • 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:

    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                                                                   \
       https://i.sstatic.net/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...

    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'