SIFTaffine.H

Go to the documentation of this file.
00001 /*!@file SIFT/SIFTaffine.H Simple helper struct for affine transforms */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Philip Williams <plw@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/SIFT/SIFTaffine.H $
00035 // $Id: SIFTaffine.H 6005 2005-11-29 18:49:14Z rjpeters $
00036 //
00037 
00038 #ifndef SIFTAFFINE_H_DEFINED
00039 #define SIFTAFFINE_H_DEFINED
00040 
00041 #include "Util/sformat.H"
00042 #include "SIFT/KeypointMatch.H"
00043 
00044 #include <ostream>
00045 
00046 //! A simple struct to store 2D affine transforms as used in the SIFT code
00047 class SIFTaffine {
00048 public:
00049   //! Constructor; initializes to identity
00050   inline SIFTaffine();
00051 
00052   //! Constructor
00053   inline SIFTaffine(const float mm1, const float mm2, const float mm3,
00054                     const float mm4, const float ttx, const float tty);
00055 
00056   //! Transform (x,y) into (u,v) using aff forward
00057   inline void transform(const float x, const float y,
00058                         float& u, float& v) const;
00059 
00060   //! Returns true if the affine can be inverted
00061   inline bool isInversible() const;
00062 
00063   //! Get the backward affine given a forward one
00064   inline SIFTaffine inverse() const;
00065 
00066   //! Decompose into rotation, scaling, and stretching components
00067   /*! This decomposition requires that the affine be inversible.  It
00068     is based on a polar decomposition as proposed in this excellent
00069     paper: 'Matrix animation and polar decomposition', Ken Shoemake
00070     and Tom Duff, Proceedings of the conference on Graphics interface
00071     '92, Vancouver, British Columbia, Canada, pp. 258-264. The
00072     resulting decomposition is such that:
00073 
00074     <PRE>
00075 
00076     [ m1 m2 ]   [ cos(theta) -sin(theta) ]   [ sx  str ]
00077     [ m3 m4 ] = [ sin(theta)  cos(theta) ] * [ str  sy ]
00078 
00079     </PRE>
00080 
00081     which you can also interpret as:
00082 
00083     <PRE>
00084 
00085     [ m1 m2 ]   [ cos(theta) -sin(theta) ]   [ sx  0 ]   [   1   str/sx ]
00086     [ m3 m4 ] = [ sin(theta)  cos(theta) ] * [ 0  sy ] * [ str/sy   1   ]
00087 
00088     </PRE>
00089 
00090     (if sx and sy are non-null), i.e.,
00091 
00092     <PRE>
00093 
00094     M = ROT(theta) * SCALE(sx, sy) * SHEAR(str/sx, str/sy)
00095 
00096     </PRE> */
00097   inline void decompose(float& theta, float& sx, float& sy,
00098                         float& str) const;
00099 
00100   //! Get residual distance squared for a given KeypointMatch
00101   /*! The return value is the squared distance between the coordinates
00102     of the ref Keypoint in the Keypointmatch, transformed by our
00103     affine transform, and the coordinates of the test Keypoint. Thus
00104     it is in squared units of the pixel size in the test image. */
00105   inline float getResidualDistSq(const KeypointMatch& km) const;
00106 
00107   //! Compose two affine transforms
00108   /*! We are the one that is applied first, other is applied second
00109     (i.e., to our results). Transforming by the resulting affine is
00110     like transforming first by us then by other. */
00111   inline SIFTaffine compose(const SIFTaffine& other) const;
00112 
00113   // our data members are public for easy access
00114   float m1, m2, m3, m4, tx, ty; //!< our contents
00115 };
00116 
00117 // ######################################################################
00118 // SIFTaffine I/O:
00119 // ######################################################################
00120 
00121 //! Print a SIFTaffine to an ostream
00122 inline std::ostream& operator<<(std::ostream& os, const SIFTaffine& a);
00123 
00124 
00125 
00126 
00127 
00128 // ######################################################################
00129 // ########## Implementation of inline functions
00130 // ######################################################################
00131 inline SIFTaffine::SIFTaffine() :
00132   m1(1.0F), m2(0.0F), m3(0.0F), m4(1.0F), tx(0.0F), ty(0.0F)
00133 { }
00134 
00135 // ######################################################################
00136 inline SIFTaffine::SIFTaffine(const float mm1, const float mm2,
00137                               const float mm3, const float mm4,
00138                               const float ttx, const float tty) :
00139   m1(mm1), m2(mm2), m3(mm3), m4(mm4), tx(ttx), ty(tty)
00140 { }
00141 
00142 // ######################################################################
00143 inline void SIFTaffine::transform(const float x, const float y,
00144                                   float& u, float& v) const
00145 {
00146   u = m1 * x + m2 * y + tx;
00147   v = m3 * x + m4 * y + ty;
00148 }
00149 
00150 // ######################################################################
00151 inline bool SIFTaffine::isInversible() const
00152 { return (fabsf(m1 * m4 - m2 * m3) > 1.0e-10F); }
00153 
00154 // ######################################################################
00155 inline SIFTaffine SIFTaffine::inverse() const
00156 {
00157   // M^-1 is given by 1/det [ d -b; -c -a] with det = ad - bc
00158   const float det = m1 * m4 - m2 * m3;
00159 
00160   ASSERT(fabs(det) > 1.0e-10);
00161 
00162   SIFTaffine ret;
00163   ret.m1 =  m4 / det; ret.m2 = -m2 / det;
00164   ret.m3 = -m3 / det; ret.m4 =  m1 / det;
00165 
00166   ret.tx = - ret.m1 * tx - ret.m2 * ty;
00167   ret.ty = - ret.m3 * tx - ret.m4 * ty;
00168 
00169   return ret;
00170 }
00171 
00172 // ######################################################################
00173 inline void SIFTaffine::decompose(float& theta, float& sx, float& sy,
00174                                   float& str) const
00175 {
00176   float mm1 = m1, mm2 = m2, mm3 = m3, mm4 = m4;
00177   const float det = mm1 * mm4 - mm2 * mm3; ASSERT(fabs(det) > 1.0e-10);
00178 
00179   // make sure the determinant is positive:
00180   float fac = 1.0F;
00181   if (det < 0.0F)
00182     { mm1 = -mm1; mm2 = -mm2; mm3 = -mm3; mm4 = -mm4; fac = -1.0F; }
00183 
00184   // polar decomposition: M = QS where Q is a rotation and S a
00185   // symmetric non-negative matrix. In the 2x2 case, Q = M +
00186   // det(M).M^-T, scaled so that the columns have unit norm:
00187   float q1 = mm1 + mm4, q2 = mm2 - mm3; // note: q3 = -q2, q4 = q1;
00188   float coln = sqrtf(q1*q1 + q2*q2);
00189   q1 /= coln; q2 /= coln; fac /= coln;
00190   //LINFO("q1: %f q2:%f",q1,q2);
00191 
00192   // ok, q1 = cos(theta) while q2 = -sin(theta):
00193   theta = acosf(q1); // in [0 .. pi]
00194   //LINFO("theta: %f",theta);
00195   const float theta2 = asinf(-q2); // in [-pi/2 .. pi/2]
00196   //LINFO("theta2: %f",theta2);
00197   if (theta2 < 0.0F) theta = -theta;  // theta now in [-pi .. pi]
00198 
00199   // to get S, we just need to apply the inverse rotation, i.e.,
00200   // rotate M by -theta. Note that q1 = cos(-theta), q2 =
00201   // sin(-theta). After simplification, we obtain: sx = q1*mm1-q2*mm3,
00202   // sy= q2*mm2 + q1*mm4, and str=(mm1*mm2+mm3*mm4)*fac:
00203   sx = q1 * mm1 - q2 * mm3;
00204   sy = q1 * mm4 + q2 * mm2;
00205   str = (mm1 * mm2 + mm3 * mm4) * fac;
00206 
00207   //LINFO("fac=%f t2=%f t=%f sx=%f sy=%f str=%f",
00208   //     fac, theta2, theta, sx, sy, str);
00209 }
00210 
00211 // ######################################################################
00212 inline std::ostream& operator<<(std::ostream& os, const SIFTaffine& a)
00213 {
00214   os<<sformat("[testX]   [ %- .3f %- .3f ] [refX]   [%- .3f]",
00215               a.m1, a.m2, a.tx)<<std::endl;
00216   os<<sformat("[testY] = [ %- .3f %- .3f ] [refY] + [%- .3f]",
00217               a.m3, a.m4, a.ty)<<std::endl;
00218   return os;
00219 }
00220 
00221 // ######################################################################
00222 inline float SIFTaffine::getResidualDistSq(const KeypointMatch& km) const
00223 {
00224   // get the coords of the ref keypoint in the ref image:
00225   const float x = km.refkp->getX();
00226   const float y = km.refkp->getY();
00227 
00228   // get transformed coords of ref keypoint, now in the test image:
00229   float u, v; transform(x, y, u, v);
00230 
00231   // compute squared distance to the test keypoint:
00232   const float dx = km.tstkp->getX();
00233   const float dy = km.tstkp->getY();
00234 
00235   return (u-dx) * (u-dx) + (v-dy) * (v-dy);
00236 }
00237 
00238 // ######################################################################
00239 inline SIFTaffine SIFTaffine::compose(const SIFTaffine& other) const
00240 {
00241   // the resulting M is other.M * ours.M, the resulting T is other.M *
00242   // ours.T + other.T:
00243   SIFTaffine r;
00244 
00245   r.m1 = m1 * other.m1 + m2 * other.m3;
00246   r.m2 = m1 * other.m2 + m2 * other.m4;
00247   r.m3 = m3 * other.m1 + m4 * other.m3;
00248   r.m4 = m3 * other.m2 + m4 * other.m4;
00249 
00250   r.tx = other.m1 * tx + other.m2 * ty + other.tx;
00251   r.ty = other.m3 * tx + other.m4 * ty + other.ty;
00252 
00253   return r;
00254 }
00255 
00256 #endif
00257 
00258 // ######################################################################
00259 /* So things look consistent in everyone's emacs... */
00260 /* Local Variables: */
00261 /* indent-tabs-mode: nil */
00262 /* End: */
Generated on Sun May 8 08:42:16 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3