CS 395/495  IBMR-- Project B: 
                        Projective 2D Rectification


Goals:

1) Use the Singular Value Decomposition (SVD) to solve a serious null-space problem.  You will write a function that finds a 2D homography (an H matrix) from 4 or more point pairs (x,x') using the Direct Linear Transformation (DLT) method. 

2) Interactively Experiment with P2 Image Rectification Methods.  You will use apply your DLT function to CP2Point objects that you can move around on the screen 
(and maybe CP2Line objects too, if you're willing-- it is easy to add 'vanishing point' solutions to this project).


Instructions:

1) Build on your ProjA code, or Download the 'starter' code I wrote for you (and will continue to refine), see Project A for a detailed description, or the comments in the file quikGL.h.

4/22/03 Newer Version:   ProjA_09.zip Matrx_01.zip  

4/29/03 Latest Revision: ProjA_17.zip  
        has steps 1-4 done for you: (also: CquikColor class simplifies lighting)

2) Make it work as before. Use these zip files to update your results from Project A if you wish. (NOTE: you can use 'Windiff' utility supplied with Visual C++ Tools to quickly find all changes in all files, line-by-line: put ProjA_09.zip contents in one directory, all your ProjA files in another, and use Windiff's 'compare directories' feature).    Be sure to include your CP2Point, CP2Line, and CP2H classes, and the user-interactions code your wrote (keyboard inputs) from Project A.  You should be able to select point objects and move them around in (x1,x2,x3) space.  Don't add any new features yet--just be sure that everything compiles and works properly.  Save a copy in a separate directory (e.g. ProjB_01).

3) Add a viewing transform H. In the CquikMeshImg class, add a private member variable named 'm_H' of type CP2H (your 3x3 H matrix class from Proj A), and be sure the constructor initializes it as an identity matrix.  You will now need to change the CquikMeshImg::drawMe() function to use the m_H matrix when it displays the CquikMeshImg object.  Re-read that carefully: m_H won't change any stored vertex positions for any member of the CquikMeshImg class, but  m_H will change the way we draw all its members on-screen.
      Recall that the existing CquikMeshImg class displays a textured mesh of quadrilaterals in the (x1,x2,-1) plane and with its center at (0,0,-1).  However, the stored vertex positions are different, so that texture mapping and mesh-making are kept as simple as possible.  When we load a texture map (in CquikMeshImg::fileLoad()) texture addresses (tx,ty) run from 0,0 at the lower-left corner to (m_xTexmax,m_yTexmax)<=(1.0, 1.0). (if the input image is square and its size is a power of two, e.g. 64x64, or 1024x1024, then m_xTexmax,m_yTexmax = (1.0,1.0), but otherwise it is less).  To keep things simple, we store mesh vertex positions in the same coordinate system: the lower-left corner vertex position is (0,0,0), and the upper right corner vertex's stored location is  (m_xTexmax,m_yTexmax,0.0).  The CquikMeshImg::drawMe()display function draws these stored vertices at the proper screen location using glScalef() and glTranslatef() matrices that modify the GL_MODELVIEW matrix used by openGL.
    Your task is to further modify GL_MODELVIEW using the m_H matrix.  Be sure that m_H properly affects the display of both the mesh and the CP2Point and CP2Line members.  You can test your m_H matrix with a few simple transformations: look at page 22 of book--does a translation by 0.25, 0.25 work? rotation by 30 degrees? separate scaling on x1 and x2 axes? etc.  It is critical that your m_H matrix affects the displayed CquikMeshImg object properly before you go on to the next step. Save a copy of everything in a separate directory (ProjB_02, etc.).

4) Apply an H matrix while the H key is pressed down. Add another CP2H matrix member to the CquikMeshImg class--call this one 'm_Hnew'.  Next, add a new keystroke response: when users push the 'H' key on the keyboard, your program should change m_H to be a copy of  m_Hnew, and when they release the 'H' key then m_H should change back to the identity matrix.  Pressing the "H" key lets people see CquikMeshImg with and without the effects of the m_Hnew matrix.

5) Make 4 (or more) user-adjustable point-pairs(x,x'). Add 4 more CP2Point objects as members of the CquikMeshImg class (you should have 4 already), but unlike the others, these are NOT affected by the m_H matrix when displayed; pressing the 'H' key has no effect on them. (you may want to make them a different color too).  We will use the original 4 CP2Point objects as the 'input' points x1,x2,x3,x4, and the 4 new point objects as 'output' points x1', x2', x3', x4'.  Like the originals, these should also be selectable and movable (you may want to discard the C2Line members of CquikMeshImg, and select the 4 new points using SHIFT 1, SHIFT 2, SHIFT 3, SHIFT 4.). 

6) Apply DLT to compute m_Hnew.  We now have everything we need to implement the DLT method and try it interactively.  Make a new member function for CquikMeshImg class named DLTsolver() that computes a new H matrix from 4 (or more) CP2Point pairs. Test it on a few obvious settings: arrange x1,x2,x3,x4 in a square and place x1',x2',x3',x4' at precisely the same locations--you should get an identity matrix for H (or something close to it).  Next, rotate the x1',x2' by 90 degrees, or scale by 2, etc; the H matrices should make sense for simple settings.

7) Trigger DLTsolver() when point pairs move.  Finally, write code that triggers DLTsolver to compute a new m_Hnew matrix every time the user moves an x or x' point.  You can then press the 'H' key to see how well the transformed x points match the locations of the (non-transformed) x' points.

8) Fun Examples:Image-Based Grading  Load any of the images from 
IBMRexample01.zip --a blocky brick building
IBMRexample02.zip
--a nearby 'Leaning Tower of Pisa' (in Skokie)
IBMRexample03.zip
--a 4-seat airplane 
IBMRexample04.zip
--STOP signs
IBMRexample05.zip
--TARGET signs
IBMRexample06.zip
--Sphinx at Giza; The Oldenburg Saw
 or use other images that you like (starter code can load 24-bit BMP format image files). Demonstrate your interactive DLT solver on some interesting images, and capture the results. You can use Window's 'Paint' app to do this: SHIFT Print-Screen grabs the whole screen into the clipboard: start 'MS Paint' and 'paste' (ctrl-V) it there--then you can crop and save any part of the image (push the dotted-square button on the left; select, then Edit->Copy To....  Show the image before/after transformation, and include these image files as part of your results.  Surprise me--extra credit for novel results, and I'll post the best ones on the class website.