Message Boards Message Boards

Fun with Perspective Anamorphism: a coke can, a coffee cup and Lady Liberty

Posted 4 years ago

enter image description here

We all know that what you see depends on your viewpoint or, as Mathematica says, the ViewVector. If you look with one eye or a camera at a 3D scene, you see a "3D Perspective Projection" of the scene. So what you see can be modified, fooled or embellished by modifying this projection. This "3D perspective anamorphism" has been widely used in popular art forms. 3D sidewalk- and street art are only some of the examples. Mathematica has some very useful functions to explore the mathematics of 3D perspective anamorphism and to create some examples yourself. In this community contribution, I explore some of the many possibilities and hope to give inspiration to others...

Here is some perspective geometry: Point A in the x-y plane is observed by the eye E as an image point I. The point I is in the view-plane of E. This is the plane perpendicular to the view- line EO and anchored at O. The angle between the view-line and an x-y plane is the view direction [Phi]. The function perspectivePoint computes the perspective point A from the image point I (xi,yi) given the view direction phi. xE and xO are the abscissas of the points E and O.

enter image description here

perspectivePoint[imagePoint : {xi_, yi_}, viewDirection : phi_, 
  eyeAbscissa : xE_, anchorAbscissa : xO_] := 
 Quiet[Module[{zE, eye, zO, ptO, imPlane, ptI, ray}, zE = xE Tan[phi];
    zO = xO Tan[phi]; ptO = {xO, 0, zO}; 
   imPlane = InfinitePlane[ptO, {{0, 1, 0}, {xO, 0, -xO Cot[phi]}}]; 
   ptI = {xO - yi Sin[phi], xi, zO + yi Cos[phi]}; eye = {xE, 0, zE}; 
   ray = HalfLine[{eye, ptI}]; 
   First[{x, y, z} /. 
     NSolve[{{x, y, z} \[Element] ray, z == 0}, {x, y, z}]]]]

enter image description here

Applying the function perspectivePoint to a unit square (the blue polygon), we see its projection in the x-y plane as the red polygon. Likewise, all image points within the blue polygon will be projected as points within the red polygon. The following GIF shows the transformation of the red polygon into its blue projection as the ViewVector is directing the camera towards the right viewpoint.

enter image description here

To apply the function perspectivePoint to real images, we can use two methods:

  1. Converting the image to graphics primitives using ImageGraphics and map the function perspectivePoint to all the coordinates of the resulting graphics objects .

  2. Using the function perspectivePoint to create a set of corresponding pairs (image-point/perspective-point). We use this point set inside FindGeometricTransform to compute a TransformationFunction. This transformation function can then be used inside ImagePerspectiveTransformation

We first start with a coke can and use method 1

Module[{w, h, colaGC, colaGCScaled, colaGCOK},
 {w, h} = ImageDimensions@cola; colaGC = ImageGraphics[cola][[1]]; 
 colaGCScaled = 
  MapAt[# /. {x_?NumericQ, 
       y_?NumericQ} :> {y - h/2, x - w/2}/h*1.65 &, colaGC, 1]; 
 colaGCOK = 
  MapAt[Most@perspectivePoint[#, .35, 10, 4] &, 
    colaGCScaled, {1, All}] /. {x_?NumericQ, y_, 0} :> {x, y}; 

enter image description here

The following GIF shows the effect of changing the camera position with ViewVector toward the right viewpoint:

enter image description here

After printing the output on paper, we can create a mixed scene of anamorphic and real objects creating a welcome confusion between the real and the perspective:

enter image description here

To use method 2 with a coffee cup, we first find the necessary transformation function to be inserted into ImagePerspectiveTransformation. We use FindGeometricTransform with a set of points on a circle and their corresponding perspectives .

Block[{xv = -10, zv = 8, imagePoints, perspectivePoints},
  imagePoints = Table[{ Cos[t], Sin[t]}, {t, 6}]; 
  perspectivePoints = (Most[perspectivePoint[#1, .35, 10, 4]] &) /@ 
  tf = Last[FindGeometricTransform[imagePoints, perspectivePoints]]];

This is the result of our transformation function applied to a circle:

    g = Graphics[{AbsoluteThickness[5], 
       Line[Table[{2.68 Cos[t], 2.68 Sin[t]}, {t, 0, 
          6.3, .1}]]}]] ImagePerspectiveTransformation[g, tf, 
    PlotRange -> {{-1, 1}, {-1, 1}}, DataRange -> {{-1, 1}, {-1, 1}}, 
    Padding -> "Fixed", Masking -> Full]}]

enter image description here

And this is how the transformation function performs on a photo of a coffee cup.

enter image description here

As the following movie shows, an unexpected scene can be created by mixing real world objects with a printout of our anamorphic coffee cup. What you see is not always what you get!

enter image description here

Perspective Anamorphism is when only one viewpoint gives the correct image. An extreme example of this are the "Living Photographs" made in the US by Arthur Mole during the first world war. Using tens of thousands of soldiers positioned in a deformed but well designed layout, he made photographs from the right vantage point on top of a tower. Using our function perspectivePoint, we try to simulate the setup of his "Human Statue of Liberty" photograph from 1918.

enter image description here

The right picture shows the view from above and shows the positions of the 18,000 (!) soldiers. The middle picture is the photo of the same soldiers made by a camera on top of a 25 meter high tower. According to the website "Human Statue of Liberty" by David Mikkelson, those were the number of soldiers in each part of the scene:

Number of men in the flame of torch: 12,000

Number of men in the torch: 2,800

Number of men in the right arm: 1,200

Number of men in the body, head and balance of the figure only: 2,000

I used the following Manipulate to get an idea of the surface area distribution within the anamorphic image and this way, approximate the settings for the function perspectivePoint. Starting from the 16 equal squares (left) we see 16 polygons (right) with a surface area distribution close to that of the number of soldiers in the original 1918 layout.

Module[{verticesI, verticesQ, areasQ}, 
 verticesI = 
  Table[{{-1 + i, -1 + j}, {-.5 + i, -1 + j}, {-.5 + i, -.5 + 
      j}, {-1 + i, -.5 + j}}, {i, 0, 1.5, .5}, {j, 0, 1.5, .5}]; 
 verticesQ = 
  Map[Most[perspectivePoint[#1, 0.35, 10, 4]] &, verticesI, {3}]; 
 areasQ = First[Map[Area[Polygon[#1]] &, verticesQ, {2}]]; 
   GraphicsRow[{Graphics[{{FaceForm[], EdgeForm[Black], 
        Polygon /@ (.75 verticesI)}}], 
     Graphics[{{FaceForm[], EdgeForm[Black], 
        Map[Polygon, verticesQ, {2}]}}]}]}]]

enter image description here

Together with other dimensions gathered from the internet, we could make a close estimate for the settings of our perspectivePoint function.

enter image description here

Above is the result of this "investigation": To the left is the historic aerial view of the 18,000 servicemen, in the middle is the perspective transformation by our function perspectivePoint using the original postcard by Arthur Mole, and to the right is the same transformation using a modern photograph of the statue of liberty. The human statue of liberty, understandingly, did not have exactly the same proportions as the real Lady Liberty. I hope these experiments entice community members to explore the astonishing world of anamorphic and perspective art. Have fun!

POSTED BY: Erik Mahieu
4 Replies

Congratulations! This post was featured in the Wolfram Blog Wolfram Community Takes on Current Events: COVID-19 Data, Green Spaces, Homeschool Puzzles and More. We are looking forward to your future contributions.

enter image description here

POSTED BY: Moderation Team

Interesting math game.

POSTED BY: Dmitriy Ivanenko

Regarding the Statue of Liberty: I especially like your choosing of material from 1918.

POSTED BY: Jack Ritter

enter image description here -- you have earned Featured Contributor Badge enter image description here

Your exceptional post has been selected for our editorial column Staff Picks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: Moderation Team
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract