[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2005-2006 by Ullrich Koethe */ 00004 /* Cognitive Systems Group, University of Hamburg, Germany */ 00005 /* */ 00006 /* This file is part of the VIGRA computer vision library. */ 00007 /* ( Version 1.6.0, Aug 13 2008 ) */ 00008 /* The VIGRA Website is */ 00009 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ 00010 /* Please direct questions, bug reports, and contributions to */ 00011 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00012 /* vigra@informatik.uni-hamburg.de */ 00013 /* */ 00014 /* Permission is hereby granted, free of charge, to any person */ 00015 /* obtaining a copy of this software and associated documentation */ 00016 /* files (the "Software"), to deal in the Software without */ 00017 /* restriction, including without limitation the rights to use, */ 00018 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00019 /* sell copies of the Software, and to permit persons to whom the */ 00020 /* Software is furnished to do so, subject to the following */ 00021 /* conditions: */ 00022 /* */ 00023 /* The above copyright notice and this permission notice shall be */ 00024 /* included in all copies or substantial portions of the */ 00025 /* Software. */ 00026 /* */ 00027 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00028 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00029 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00030 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00031 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00032 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00033 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00034 /* OTHER DEALINGS IN THE SOFTWARE. */ 00035 /* */ 00036 /************************************************************************/ 00037 00038 #ifndef VIGRA_AFFINEGEOMETRY_HXX 00039 #define VIGRA_AFFINEGEOMETRY_HXX 00040 00041 #include "mathutil.hxx" 00042 #include "matrix.hxx" 00043 #include "tinyvector.hxx" 00044 #include "splineimageview.hxx" 00045 #include <cmath> 00046 00047 namespace vigra { 00048 00049 /** \addtogroup GeometricTransformations Geometric Transformations 00050 */ 00051 //@{ 00052 00053 /********************************************************/ 00054 /* */ 00055 /* create affine matrices */ 00056 /* */ 00057 /********************************************************/ 00058 00059 /** \brief Create homogeneous matrix representing a 2D translation. 00060 00061 For use with \ref affineWarpImage(). 00062 */ 00063 inline 00064 linalg::TemporaryMatrix<double> translationMatrix2D(TinyVector<double, 2> const & shift) 00065 { 00066 linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); 00067 ret(0,2) = shift[0]; 00068 ret(1,2) = shift[1]; 00069 return ret; 00070 } 00071 00072 /** \brief Create homogeneous matrix representing a 2D uniform scaling about the coordinate origin. 00073 00074 For use with \ref affineWarpImage(). 00075 */ 00076 inline 00077 linalg::TemporaryMatrix<double> scalingMatrix2D(double scalingFactor) 00078 { 00079 linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); 00080 ret(0,0) = scalingFactor; 00081 ret(1,1) = scalingFactor; 00082 return ret; 00083 } 00084 00085 /** \brief Create homogeneous matrix representing a 2D non-uniform scaling about the coordinate origin. 00086 00087 For use with \ref affineWarpImage(). 00088 */ 00089 inline 00090 linalg::TemporaryMatrix<double> scalingMatrix2D(double sx, double sy) 00091 { 00092 linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); 00093 ret(0,0) = sx; 00094 ret(1,1) = sy; 00095 return ret; 00096 } 00097 00098 /** \brief Create homogeneous matrix representing a 2D shearing. 00099 00100 For use with \ref affineWarpImage(). 00101 */ 00102 inline 00103 linalg::TemporaryMatrix<double> shearMatrix2D(double s01, double s10) 00104 { 00105 linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); 00106 ret(0,1) = s01; 00107 ret(1,0) = s10; 00108 return ret; 00109 } 00110 00111 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin. 00112 00113 For use with \ref affineWarpImage(). Angle must be in radians. 00114 */ 00115 inline 00116 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle) 00117 { 00118 linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3)); 00119 double s = std::sin(angle); 00120 double c = std::cos(angle); 00121 ret(0,0) = c; 00122 ret(1,1) = c; 00123 ret(0,1) = -s; 00124 ret(1,0) = s; 00125 return ret; 00126 } 00127 00128 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin. 00129 00130 For use with \ref affineWarpImage(). Angle must be in degrees. 00131 */ 00132 inline 00133 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle) 00134 { 00135 return rotationMatrix2DRadians(angle*M_PI/180.0); 00136 } 00137 00138 /** \brief Create homogeneous matrix representing a 2D rotation about the given point. 00139 00140 For use with \ref affineWarpImage(). Angle must be in radians. 00141 */ 00142 inline 00143 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle, TinyVector<double, 2> const & center) 00144 { 00145 return translationMatrix2D(center) * rotationMatrix2DRadians(angle) * translationMatrix2D(-center); 00146 } 00147 00148 /** \brief Create homogeneous matrix representing a 2D rotation about the given point. 00149 00150 For use with \ref affineWarpImage(). Angle must be in degrees. 00151 */ 00152 inline 00153 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle, TinyVector<double, 2> const & center) 00154 { 00155 return rotationMatrix2DRadians(angle*M_PI/180.0, center); 00156 } 00157 00158 /********************************************************/ 00159 /* */ 00160 /* rotateImage */ 00161 /* */ 00162 /********************************************************/ 00163 00164 /** \brief Rotate image by an arbitrary angle. 00165 00166 The algorithm performs a rotation about the given center point (the image center by default) 00167 using the given SplineImageView for interpolation. The destination image must have the same size 00168 as the source SplineImageView. The rotation is counter-clockwise, and the angle must be given in degrees. 00169 00170 <b> Declarations:</b> 00171 00172 pass arguments explicitly: 00173 \code 00174 namespace vigra { 00175 // rotate about given center point 00176 template <int ORDER, class T, 00177 class DestIterator, class DestAccessor> 00178 void rotateImage(SplineImageView<ORDER, T> const & src, 00179 DestIterator id, DestAccessor dest, 00180 double angleInDegree, TinyVector<double, 2> const & center); 00181 00182 // rotate about image center 00183 template <int ORDER, class T, 00184 class DestIterator, class DestAccessor> 00185 void 00186 rotateImage(SplineImageView<ORDER, T> const & src, 00187 DestIterator id, DestAccessor dest, 00188 double angleInDegree) 00189 } 00190 \endcode 00191 00192 use argument objects in conjunction with \ref ArgumentObjectFactories : 00193 \code 00194 namespace vigra { 00195 // rotate about given center point 00196 template <int ORDER, class T, 00197 class DestIterator, class DestAccessor> 00198 void 00199 rotateImage(SplineImageView<ORDER, T> const & src, 00200 pair<DestImageIterator, DestAccessor> dest, 00201 double angleInDegree, TinyVector<double, 2> const & center); 00202 00203 // rotate about image center 00204 template <int ORDER, class T, 00205 class DestIterator, class DestAccessor> 00206 void 00207 rotateImage(SplineImageView<ORDER, T> const & src, 00208 pair<DestImageIterator, DestAccessor> dest, 00209 double angleInDegree); 00210 } 00211 \endcode 00212 00213 <b> Usage:</b> 00214 00215 <b>\#include</b> <<a href="affinegeometry_8hxx-source.html">vigra/affinegeometry.hxx</a>><br> 00216 Namespace: vigra 00217 00218 \code 00219 00220 Image src(width, height); 00221 vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)); 00222 00223 Image dest(width, height); 00224 00225 vigra::rotateImage(spline, destImage(dest), 38.5); 00226 00227 \endcode 00228 00229 <b> Required Interface:</b> 00230 00231 \code 00232 DestImageIterator dest_upperleft; 00233 00234 double x = ..., y = ...; 00235 00236 if (spline.isInside(x,y)) 00237 dest_accessor.set(spline(x, y), dest_upperleft); 00238 00239 \endcode 00240 */ 00241 doxygen_overloaded_function(template <...> void rotateImage) 00242 00243 template <int ORDER, class T, 00244 class DestIterator, class DestAccessor> 00245 void rotateImage(SplineImageView<ORDER, T> const & src, 00246 DestIterator id, DestAccessor dest, 00247 double angleInDegree, TinyVector<double, 2> const & center) 00248 { 00249 int w = src.width(); 00250 int h = src.height(); 00251 00252 double angle = angleInDegree*M_PI/180.0; 00253 double c = std::cos(angle); 00254 double s = std::sin(angle); 00255 00256 for(int y = 0; y < h; ++y, ++id.y) 00257 { 00258 typename DestIterator::row_iterator rd = id.rowIterator(); 00259 double sy = (y - center[1])*c - center[0]*s + center[1]; 00260 double sx = -(y - center[1])*s - center[0]*c + center[0]; 00261 for(int x=0; x < w; ++x, ++rd, sx += c, sy += s) 00262 { 00263 if(src.isInside(sx, sy)) 00264 dest.set(src(sx, sy), rd); 00265 } 00266 } 00267 } 00268 00269 template <int ORDER, class T, 00270 class DestIterator, class DestAccessor> 00271 inline void 00272 rotateImage(SplineImageView<ORDER, T> const & src, 00273 pair<DestIterator, DestAccessor> dest, 00274 double angleInDegree, TinyVector<double, 2> const & center) 00275 { 00276 rotateImage(src, dest.first, dest.second, angleInDegree, center); 00277 } 00278 00279 template <int ORDER, class T, 00280 class DestIterator, class DestAccessor> 00281 inline void 00282 rotateImage(SplineImageView<ORDER, T> const & src, 00283 DestIterator id, DestAccessor dest, 00284 double angleInDegree) 00285 { 00286 TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0); 00287 rotateImage(src, id, dest, angleInDegree, center); 00288 } 00289 00290 template <int ORDER, class T, 00291 class DestIterator, class DestAccessor> 00292 inline void 00293 rotateImage(SplineImageView<ORDER, T> const & src, 00294 pair<DestIterator, DestAccessor> dest, 00295 double angleInDegree) 00296 { 00297 TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0); 00298 rotateImage(src, dest.first, dest.second, angleInDegree, center); 00299 } 00300 00301 /********************************************************/ 00302 /* */ 00303 /* affineWarpImage */ 00304 /* */ 00305 /********************************************************/ 00306 00307 /** \brief Warp an image according to an affine transformation. 00308 00309 <b> Declarations:</b> 00310 00311 pass arguments explicitly: 00312 \code 00313 namespace vigra { 00314 template <int ORDER, class T, 00315 class DestIterator, class DestAccessor, 00316 class C> 00317 void affineWarpImage(SplineImageView<ORDER, T> const & src, 00318 DestIterator dul, DestIterator dlr, DestAccessor dest, 00319 MultiArrayView<2, double, C> const & affineMatrix); 00320 } 00321 \endcode 00322 00323 use argument objects in conjunction with \ref ArgumentObjectFactories : 00324 \code 00325 namespace vigra { 00326 template <int ORDER, class T, 00327 class DestIterator, class DestAccessor, 00328 class C> 00329 void affineWarpImage(SplineImageView<ORDER, T> const & src, 00330 triple<DestIterator, DestIterator, DestAccessor> dest, 00331 MultiArrayView<2, double, C> const & affineMatrix); 00332 } 00333 \endcode 00334 00335 The algorithm applies the given \a affineMatrix to the <i>destination coordinates</i> and copies 00336 the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation. 00337 If the resulting coordinate is outside the source image, nothing will be writen at that destination point. 00338 00339 \code 00340 for all dest pixels: 00341 currentSrcCoordinate = affineMatrix * currentDestCoordinate; 00342 if src.isInside(currentSrcCoordinate): 00343 dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value 00344 \endcode 00345 00346 The matrix represent a 2-dimensional affine transform by means of homogeneous coordinates, 00347 i.e. it must be a 3x3 matrix whose last row is (0,0,1). 00348 00349 <b> Usage:</b> 00350 00351 <b>\#include</b> <<a href="affinegeometry_8hxx-source.html">vigra/affinegeometry.hxx</a>><br> 00352 Namespace: vigra 00353 00354 \code 00355 00356 Image src(width, height); 00357 vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src)); 00358 00359 Image dest1(width, height); 00360 00361 // equivalent (up to round-off errors) with 00362 // rotateImage(spline, destImage(dest1), 45.0); 00363 TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0); 00364 affineWarpImage(spline, destImageRange(dest1), rotationMatrix2DDegrees(45.0, center)); 00365 00366 Image dest2(2*width-1, 2*height-1); 00367 00368 // equivalent (up to round-off errors) with 00369 // resizeImageSplineInterpolation(srcImageRange(img), destImageRange(dest2)); 00370 // note that scaleFactor = 0.5, because we must pass the transformation from destination to source 00371 affineWarpImage(spline, destImageRange(dest2), scalingMatrix2D(0.5)); 00372 00373 \endcode 00374 00375 <b> Required Interface:</b> 00376 00377 \code 00378 DestImageIterator dest_upperleft; 00379 00380 double x = ..., y = ...; 00381 00382 if (spline.isInside(x,y)) 00383 dest_accessor.set(spline(x, y), dest_upperleft); 00384 00385 \endcode 00386 00387 <b>See also:</b> Functions to specify affine transformation: \ref translationMatrix2D(), \ref scalingMatrix2D(), 00388 \ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ref rotationMatrix2DDegrees() 00389 */ 00390 doxygen_overloaded_function(template <...> void affineWarpImage) 00391 00392 template <int ORDER, class T, 00393 class DestIterator, class DestAccessor, 00394 class C> 00395 void affineWarpImage(SplineImageView<ORDER, T> const & src, 00396 DestIterator dul, DestIterator dlr, DestAccessor dest, 00397 MultiArrayView<2, double, C> const & affineMatrix) 00398 { 00399 vigra_precondition(rowCount(affineMatrix) == 3 && columnCount(affineMatrix) == 3 && 00400 affineMatrix(2,0) == 0.0 && affineMatrix(2,1) == 0.0 && affineMatrix(2,2) == 1.0, 00401 "affineWarpImage(): matrix doesn't represent an affine transformation with homogeneous 2D coordinates."); 00402 00403 00404 double w = dlr.x - dul.x; 00405 double h = dlr.y - dul.y; 00406 00407 for(double y = 0.0; y < h; ++y, ++dul.y) 00408 { 00409 typename DestIterator::row_iterator rd = dul.rowIterator(); 00410 for(double x=0.0; x < w; ++x, ++rd) 00411 { 00412 double sx = x*affineMatrix(0,0) + y*affineMatrix(0,1) + affineMatrix(0,2); 00413 double sy = x*affineMatrix(1,0) + y*affineMatrix(1,1) + affineMatrix(1,2); 00414 if(src.isInside(sx, sy)) 00415 dest.set(src(sx, sy), rd); 00416 } 00417 } 00418 } 00419 00420 template <int ORDER, class T, 00421 class DestIterator, class DestAccessor, 00422 class C> 00423 inline 00424 void affineWarpImage(SplineImageView<ORDER, T> const & src, 00425 triple<DestIterator, DestIterator, DestAccessor> dest, 00426 MultiArrayView<2, double, C> const & affineMatrix) 00427 { 00428 affineWarpImage(src, dest.first, dest.second, dest.third, affineMatrix); 00429 } 00430 00431 00432 //@} 00433 00434 } // namespace vigra 00435 00436 00437 #endif /* VIGRA_AFFINEGEOMETRY_HXX */
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|