[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

vigra/affinegeometry.hxx
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)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.7.0 (Thu Aug 25 2011)