contrib/oxl/mvl/ProjectiveBasis2D.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/ProjectiveBasis2D.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 //  \file
00007 
00008 #include "ProjectiveBasis2D.h"
00009 #include <vcl_iostream.h>
00010 #include <vcl_vector.h>
00011 #include <vcl_cassert.h>
00012 #include <vnl/vnl_double_3.h>
00013 #include <vnl/vnl_double_3x3.h>
00014 #include <vnl/vnl_double_3x4.h>
00015 #include <vnl/vnl_inverse.h>
00016 #include <vnl/algo/vnl_svd.h>
00017 
00018 static const int warn_ = false;
00019 static const int check_collinear = true;
00020 
00021 //: Compute projective basis for 4 points.
00022 ProjectiveBasis2D::ProjectiveBasis2D(const HomgPoint2D& p1, const HomgPoint2D& p2, const HomgPoint2D& p3, const HomgPoint2D& p4)
00023 {
00024   compute(p1, p2, p3, p4);
00025 }
00026 
00027 //: Compute projective basis for first 4 points in given array.
00028 ProjectiveBasis2D::ProjectiveBasis2D(const vcl_vector<HomgPoint2D>& points)
00029 {
00030   assert(points.size() >= 4);
00031   compute(points[0], points[1], points[2], points[3]);
00032 }
00033 
00034 // Copy ctor
00035 ProjectiveBasis2D::ProjectiveBasis2D(const ProjectiveBasis2D& that)
00036 {
00037   operator=(that);
00038 }
00039 
00040 // Assignment
00041 ProjectiveBasis2D& ProjectiveBasis2D::operator=(const ProjectiveBasis2D&)
00042 {
00043   assert(!"ProjectiveBasis2D::operator=");
00044   return *this;
00045 }
00046 
00047 //: Destructor
00048 ProjectiveBasis2D::~ProjectiveBasis2D()
00049 {
00050 }
00051 
00052 //:
00053 // Find the transformation which maps the 4 points to the canonical
00054 // projective frame using the linear method of [Beardsley et. al., ECCV96].
00055 // If three of the four points are nearly collinear, an error message is
00056 // printed, but the computation is still carried out.
00057 void ProjectiveBasis2D::compute(const HomgPoint2D& p1, const HomgPoint2D& p2, const HomgPoint2D& p3, const HomgPoint2D& p4)
00058 {
00059   if (check_collinear) {
00060     vnl_double_3x4 full_matrix;
00061     full_matrix.set_column(0, p1.get_vector());
00062     full_matrix.set_column(1, p2.get_vector());
00063     full_matrix.set_column(2, p3.get_vector());
00064     full_matrix.set_column(3, p4.get_vector());
00065 
00066     if (! full_matrix.is_finite() || full_matrix.has_nans()) {
00067       vcl_cerr << "Error (ProjectiveBasis2D): given matrix has infinite or NaN values\n";
00068       T_.set_identity(); collinear_ = true; return;
00069     }
00070 
00071     vnl_svd<double> s(full_matrix.as_ref(), 1e-8); // size 3x4
00072     collinear_ = (s.rank() < 3);
00073 
00074     if (collinear_ && warn_)
00075       vcl_cerr << "Warning (ProjectiveBasis2D): Three out of the four points are nearly collinear\n";
00076   }
00077   else {
00078     collinear_ = false;
00079   }
00080 
00081   vnl_double_3x3 back_matrix;
00082   back_matrix.set_column(0, p1.get_vector());
00083   back_matrix.set_column(1, p2.get_vector());
00084   back_matrix.set_column(2, p3.get_vector());
00085 
00086   vnl_svd<double> svd(back_matrix.as_ref()); // size 3x3
00087   vnl_double_3 scales_vector = svd.solve(p4.get_vector().as_ref());
00088 
00089   back_matrix.set_column(0, scales_vector[0] * p1.get_vector());
00090   back_matrix.set_column(1, scales_vector[1] * p2.get_vector());
00091   back_matrix.set_column(2, scales_vector[2] * p3.get_vector());
00092 
00093   if (! back_matrix.is_finite() || back_matrix.has_nans()) {
00094     vcl_cerr << "Error (ProjectiveBasis2D): back matrix has infinite or NaN values\n";
00095     T_.set_identity(); collinear_ = true; return;
00096   }
00097 
00098   T_.set(vnl_inverse(back_matrix));
00099 }