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