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