vigra - vigra/affinegeometry.hxx Source File

[ 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> <vigra/affinegeometry.hxx><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 written 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> <vigra/affinegeometry.hxx><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.9.0 (Tue Nov 6 2012)