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: */