213 - A26 - Matrix Transformations Revisited

15 hours ago by Professor213

In this worksheet, the user will experiment with Linear Transformations and Computer Graphics  but now allowing for  translations by using Homogeneous Coordinates.

John Travis

Mississippi College

Matrix Transformations

If T:$R^n \rightarrow R^m$ is a Linear Transformations, then $T(x)=Ax$, for some unique matrix $A$.  Therefore, one can completely describe a linear transformation using a matrix.  For computer graphics, all screen images consist of a discrete collection of points.  A linear transformation on these points will cause the image to be distorted in some manner.  Some interesting transformations discussed in Linear Algebra include reflections, expansion and contraction, shears, projections and combinations of these.  In the experiment below, we will start with the unit square and see what happens when an input transformation acts upon that box.  You can enter whatever you want for the matrix $A$ but you might want to utilize one (or a multiplicative product) of the standard transformations from the text.

# This one shows specific matrix transformations in 2D...skew, rotation, etc. N=3 @interact def _(transform=('Select:',list(['Identity', 'Reflect x-axis', 'Reflect y-axis', 'Rotate Origin', 'Skew Right','Skew Left', 'Skew Up', 'Skew Down','Horizontal Contraction','Horizontal Expansion','Vertical Contraction','Vertical Expansion','Rotation','Translation Up to the Right', 'Translation Down to the Right'])), trans = slider(1,4,1/2,3), theta = slider(-180,180,5,30)): A = identity_matrix(N) if transform=='Reflect x-axis': A = matrix([[1,0,0],[0,-1,0],[0,0,1]]) show(A) if transform=='Reflect y-axis': A = matrix([[-1,0,0],[0,1,0],[0,0,1]]) show(A) if transform=='Rotate Origin': A = matrix([[-1,0,0],[0,-1,0],[0,0,1]]) show(A) if transform=='Skew Right': A = matrix([[1,trans,0],[0,1,0],[0,0,1]]) show(A) if transform=='Skew Left': A = matrix([[1,-1*trans,0],[0,1,0],[0,0,1]]) show(A) if transform=='Skew Up': A = matrix([[1,0,0],[trans,1,0],[0,0,1]]) show(A) if transform=='Skew Down': A = matrix([[1,0,0],[-1*trans,1,0],[0,0,1]]) show(A) if transform=='Horizontal Contraction': A = matrix([[1/trans,0,0],[0,1,0],[0,0,1]]) show(A) if transform=='Horizontal Expansion': A = matrix([[trans,0,0],[0,1,0],[0,0,1]]) show(A) if transform=='Vertical Contraction': A = matrix([[1,0,0],[0,1/trans,0],[0,0,1]]) show(A) if transform=='Vertical Expansion': A = matrix([[1,0,0],[0,trans,0],[0,0,1]]) show(A) if transform=='Rotation': angle = theta*pi/180 A = matrix([[cos(angle),-sin(angle),0],[sin(angle),cos(angle),0],[0,0,1]]) show(A) if transform=='Translation Up to the Right': A = matrix([[1,0,trans],[0,1,trans],[0,0,1]]) show(A) if transform=='Translation Down to the Right': A = matrix([[1,0,trans],[0,1,-trans],[0,0,1]]) show(A) StartBox = line2d([(0,0),(2,0)],thickness=6)+line2d([(2,0),(2,2)],thickness=6)+line2d([(2,2),(1,3)],thickness=6)+line2d([(1,3),(0,2)],thickness=6)+line2d([(0,2),(0,0)],thickness=6) BoxCorners = matrix([[0, 2, 2, 1, 0],[0, 0, 2, 3, 2],[1, 1, 1, 1, 1]]) NewCorners = (A*BoxCorners).transpose() # switch result matrix to rows for easier extraction of A*B columns. EndBox = Graphics() for col in range(5): c1 = NewCorners[Mod(col,5)][0:2] c2 = NewCorners[Mod(col+1,5)][0:2] EndBox += line([c1,c2],thickness=5, rgbcolor=(0.5,1,0.5)) show(StartBox+EndBox,aspect_ratio=True) 
       

Click to the left again to hide and once more to show the dynamic interactive window

A = matrix([[1,0,-4],[0,1,5],[0,0,1]]) show(A) pt = matrix([[2,1],[3,5],[1,1]]) show(pt) show(A*pt) 
       

                                
                            

                                
A = matrix([[1,0,0,-4],[0,1,0,5],[0,0,1,7],[0,0,0,1]]) show(A) pt = matrix([[2,1],[3,5],[1,-2],[1,1]]) show(pt) show(A*pt) 
       

                                
                            

                                

Now, experiment with some transformation matrices that you choose.  You can combine transformation but multiplying the simple transformations already discussed above.

Assignment:

  • Create a matrix transformations which
    • reflects the image across the y-axis
    • skews to the right
    • expands vertically
    • does all three at the same time
  • Put your results in Matrix format in new cells below the interact.  Use a comment (start the line with a '#') to briefly describe each matrix.
# Here is an example of how you can combine transformations using sage. A1 = matrix([[1, 2],[0, 1]]) A2 = matrix([[-1, 0],[0, 1]]) A3 = matrix([[1, 0],[0, 2]]) A = A3*A2*A1 show(A) 
       

                                
                            

                                
# This one does matrix transformations in 2D # ...skew, rotation, translation N=3 @interact def _(A = identity_matrix(QQ, N),auto_update=True): # StartBox defines the image you want to manipulate # Our image has linear edges so we only need to # play with the corners stored in BoxCorners StartBox = line2d([(0,0),(0,1)],thickness=6) StartBox += line2d([(0,1),(1,2)],thickness=6) StartBox += line2d([(1,2),(2,1)],thickness=6) StartBox += line2d([(2,1),(2,0)],thickness=6) StartBox += line2d([(2,0),(0,0)],thickness=6) BoxCorners = matrix([[0, 0, 1, 2, 2],[0, 1, 2, 1, 0],[1, 1, 1, 1, 1]]) # switch result matrix to rows for easier extraction of columns. NewCorners = (A*BoxCorners).transpose() EndBox = Graphics() npts = 5 for col in range(npts): c1 = NewCorners[Mod(col,npts)][0:2] c2 = NewCorners[Mod(col+1,npts)][0:2] EndBox += line2d([c1,c2],thickness=5, rgbcolor=(0.5,1,0.5)) show(StartBox+EndBox,aspect_ratio=True) 
       

Click to the left again to hide and once more to show the dynamic interactive window

# This cell uses Homogeneous Coordinates to play with projections var('u,v') pt1 = (7,3,-5) pt2 = (12,8,2) pt3 = (1,2,1) eye = (0,0,10) G = point3d(pt1,size=20)+point3d(pt2,size=20)+point3d(pt3,size=20) G += line3d([pt1,pt2,pt3,pt1],color='orange',thickness=10) G += text3d('EYE',eye,color='red') # A perspective transformation from the point (0,0,10) T = matrix([[1,0,0,0],[0,1,0,0],[0,0,0,0],[0,0,-1/10,1]]) V = matrix([[7,3,-5,1],[12,8,2,1],[1,2,1,1]]).transpose() NewPts = (T*V).transpose() print "The Homogeneous Coordinates of the projected corners:" print NewPts pt1a = (NewPts[0]/NewPts[0][3])[0:3] pt2a = (NewPts[1]/NewPts[1][3])[0:3] pt3a = (NewPts[2]/NewPts[2][3])[0:3] G += point3d(pt1a,size=25,color='red') G += point3d(pt2a,size=25,color='red') G += point3d(pt3a,size=25,color='red') G += line3d([eye,pt1,pt1a],color='green') G += line3d([eye,pt2,pt2a],color='green') G += line3d([eye,pt3,pt3a],color='green') G += line3d([pt1a,pt2a,pt3a,pt1a],color='red',thickness=10) G += parametric_plot3d([u,v,0],(u,0,16),(v,0,12),opacity=0.2,color='green') G.show() 
       
The Homogeneous Coordinates of the projected corners:
[   7    3    0  3/2]
[  12    8    0  4/5]
[   1    2    0 9/10]
The Homogeneous Coordinates of the projected corners:
[   7    3    0  3/2]
[  12    8    0  4/5]
[   1    2    0 9/10]
 
       

For the images above, only the corners were transformed since lines are mapped to lines under linear transformations.  This saves time rather than transforming each pixel dot for all the lines in the square.  For more general images, each pixel must be submitted to the transformation.  For the experiment below, we will start with a general image and apply the same inputs as above.

(The hope is that the student would be able to upload an image on their own to use here.)

Below is under construction.  Suggestions are welcome!

Can you figure out how to take this image in Sage and apply the various transformations...

import pylab, numpy # This one is still under construction...need to find a nice b/w picture for the Start Image. It should work fine # so long as the pixels are stored as data points in columns. # This one shows matrix transformations in 2D...skew, rotation, etc. # Read in a png image as a numpy array. A = pylab.imread(DATA + 'Head.jpg')[::-1,:] A_image = numpy.mean(A, 2) N=2 @interact def _(A = identity_matrix(QQ, N),auto_update=False ): StartImage = pts = number of pixels in the Image StartPoints = convert StartImage to a collection of pixels with x-coords in first row and y-coord in 2nd NewPoints= (A*StartPoints).transpose() # switch result matrix to rows for easier extraction of A*B columns. EndImage= Graphics() for col in range(4): c1 = NewPoints[Mod(col,pts)] c2 = NewPoints[Mod(col+1,pts)] EndBox += line2d([c1,c2],thickness=5, rgbcolor=(0.5,1,0.5)) show(StartImage+EndImage,aspect_ratio=True) 
       

Click to the left again to hide and once more to show the dynamic interactive window

# future expansion for linear transformations into 3D