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

affinegeometry.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 2005-2006 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_AFFINEGEOMETRY_HXX
37 #define VIGRA_AFFINEGEOMETRY_HXX
38 
39 #include "mathutil.hxx"
40 #include "matrix.hxx"
41 #include "tinyvector.hxx"
42 #include "splineimageview.hxx"
43 #include <cmath>
44 
45 namespace vigra {
46 
47 /** \addtogroup GeometricTransformations Geometric Transformations
48 */
49 //@{
50 
51 /********************************************************/
52 /* */
53 /* create affine matrices */
54 /* */
55 /********************************************************/
56 
57 /** \brief Create homogeneous matrix representing a 2D translation.
58 
59  For use with \ref affineWarpImage().
60 */
61 inline
62 linalg::TemporaryMatrix<double> translationMatrix2D(TinyVector<double, 2> const & shift)
63 {
64  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
65  ret(0,2) = shift[0];
66  ret(1,2) = shift[1];
67  return ret;
68 }
69 
70 /** \brief Create homogeneous matrix representing a 2D uniform scaling about the coordinate origin.
71 
72  For use with \ref affineWarpImage().
73 */
74 inline
75 linalg::TemporaryMatrix<double> scalingMatrix2D(double scalingFactor)
76 {
77  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
78  ret(0,0) = scalingFactor;
79  ret(1,1) = scalingFactor;
80  return ret;
81 }
82 
83 /** \brief Create homogeneous matrix representing a 2D non-uniform scaling about the coordinate origin.
84 
85  For use with \ref affineWarpImage().
86 */
87 inline
88 linalg::TemporaryMatrix<double> scalingMatrix2D(double sx, double sy)
89 {
90  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
91  ret(0,0) = sx;
92  ret(1,1) = sy;
93  return ret;
94 }
95 
96 /** \brief Create homogeneous matrix representing a 2D shearing.
97 
98  For use with \ref affineWarpImage().
99 */
100 inline
101 linalg::TemporaryMatrix<double> shearMatrix2D(double s01, double s10)
102 {
103  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
104  ret(0,1) = s01;
105  ret(1,0) = s10;
106  return ret;
107 }
108 
109 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin.
110 
111  For use with \ref affineWarpImage(). Angle must be in radians.
112 */
113 inline
114 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle)
115 {
116  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
117  double s = std::sin(angle);
118  double c = std::cos(angle);
119  ret(0,0) = c;
120  ret(1,1) = c;
121  ret(0,1) = -s;
122  ret(1,0) = s;
123  return ret;
124 }
125 
126 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin.
127 
128  For use with \ref affineWarpImage(). Angle must be in degrees.
129 */
130 inline
131 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle)
132 {
133  return rotationMatrix2DRadians(angle*M_PI/180.0);
134 }
135 
136 /** \brief Create homogeneous matrix representing a 2D rotation about the given point.
137 
138  For use with \ref affineWarpImage(). Angle must be in radians.
139 */
140 inline
141 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle, TinyVector<double, 2> const & center)
142 {
143  return translationMatrix2D(center) * rotationMatrix2DRadians(angle) * translationMatrix2D(-center);
144 }
145 
146 /** \brief Create homogeneous matrix representing a 2D rotation about the given point.
147 
148  For use with \ref affineWarpImage(). Angle must be in degrees.
149 */
150 inline
151 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle, TinyVector<double, 2> const & center)
152 {
153  return rotationMatrix2DRadians(angle*M_PI/180.0, center);
154 }
155 
156 /********************************************************/
157 /* */
158 /* rotateImage */
159 /* */
160 /********************************************************/
161 
162 /** \brief Rotate image by an arbitrary angle.
163 
164  The algorithm performs a rotation about the given center point (the image center by default)
165  using the given SplineImageView for interpolation. The destination image must have the same size
166  as the source SplineImageView. The rotation is counter-clockwise, and the angle must be given in degrees.
167 
168  <b> Declarations:</b>
169 
170  pass arguments explicitly:
171  \code
172  namespace vigra {
173  // rotate about given center point
174  template <int ORDER, class T,
175  class DestIterator, class DestAccessor>
176  void rotateImage(SplineImageView<ORDER, T> const & src,
177  DestIterator id, DestAccessor dest,
178  double angleInDegree, TinyVector<double, 2> const & center);
179 
180  // rotate about image center
181  template <int ORDER, class T,
182  class DestIterator, class DestAccessor>
183  void
184  rotateImage(SplineImageView<ORDER, T> const & src,
185  DestIterator id, DestAccessor dest,
186  double angleInDegree)
187  }
188  \endcode
189 
190  use argument objects in conjunction with \ref ArgumentObjectFactories :
191  \code
192  namespace vigra {
193  // rotate about given center point
194  template <int ORDER, class T,
195  class DestIterator, class DestAccessor>
196  void
197  rotateImage(SplineImageView<ORDER, T> const & src,
198  pair<DestImageIterator, DestAccessor> dest,
199  double angleInDegree, TinyVector<double, 2> const & center);
200 
201  // rotate about image center
202  template <int ORDER, class T,
203  class DestIterator, class DestAccessor>
204  void
205  rotateImage(SplineImageView<ORDER, T> const & src,
206  pair<DestImageIterator, DestAccessor> dest,
207  double angleInDegree);
208  }
209  \endcode
210 
211  <b> Usage:</b>
212 
213  <b>\#include</b> <vigra/affinegeometry.hxx><br>
214  Namespace: vigra
215 
216  \code
217 
218  Image src(width, height);
219  vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src));
220 
221  Image dest(width, height);
222 
223  vigra::rotateImage(spline, destImage(dest), 38.5);
224 
225  \endcode
226 
227  <b> Required Interface:</b>
228 
229  \code
230  DestImageIterator dest_upperleft;
231 
232  double x = ..., y = ...;
233 
234  if (spline.isInside(x,y))
235  dest_accessor.set(spline(x, y), dest_upperleft);
236 
237  \endcode
238 */
239 doxygen_overloaded_function(template <...> void rotateImage)
240 
241 template <int ORDER, class T,
242  class DestIterator, class DestAccessor>
243 void rotateImage(SplineImageView<ORDER, T> const & src,
244  DestIterator id, DestAccessor dest,
245  double angleInDegree, TinyVector<double, 2> const & center)
246 {
247  int w = src.width();
248  int h = src.height();
249 
250  double angle = angleInDegree*M_PI/180.0;
251  double c = std::cos(angle);
252  double s = std::sin(angle);
253 
254  // avoid round-off errors for simple rotations
255  if(closeAtTolerance(std::fmod(angleInDegree, 45.0), 0.0))
256  {
257  // convert angle into a multiple of pi/4
258  int ai = roundi(angleInDegree / 45.0) % 8;
259  if(ai < 0)
260  ai += 8;
261 
262  static double sqrt2_2 = 0.5*M_SQRT2;
263  static double ss[8] = {0.0, sqrt2_2, 1.0, sqrt2_2, 0.0, -sqrt2_2, -1.0, -sqrt2_2};
264  static double cc[8] = {1.0, sqrt2_2, 0.0, -sqrt2_2, -1.0, -sqrt2_2, 0.0, sqrt2_2};
265 
266  s = ss[ai];
267  c = cc[ai];
268  }
269 
270  for(int y = 0; y < h; ++y, ++id.y)
271  {
272  typename DestIterator::row_iterator rd = id.rowIterator();
273  double sy = (y - center[1])*c - center[0]*s + center[1];
274  double sx = -(y - center[1])*s - center[0]*c + center[0];
275  for(int x=0; x < w; ++x, ++rd, sx += c, sy += s)
276  {
277  if(src.isInside(sx, sy))
278  dest.set(src(sx, sy), rd);
279  }
280  }
281 }
282 
283 template <int ORDER, class T,
284  class DestIterator, class DestAccessor>
285 inline void
286 rotateImage(SplineImageView<ORDER, T> const & src,
287  pair<DestIterator, DestAccessor> dest,
288  double angleInDegree, TinyVector<double, 2> const & center)
289 {
290  rotateImage(src, dest.first, dest.second, angleInDegree, center);
291 }
292 
293 template <int ORDER, class T,
294  class DestIterator, class DestAccessor>
295 inline void
296 rotateImage(SplineImageView<ORDER, T> const & src,
297  DestIterator id, DestAccessor dest,
298  double angleInDegree)
299 {
300  TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0);
301  rotateImage(src, id, dest, angleInDegree, center);
302 }
303 
304 template <int ORDER, class T,
305  class DestIterator, class DestAccessor>
306 inline void
307 rotateImage(SplineImageView<ORDER, T> const & src,
308  pair<DestIterator, DestAccessor> dest,
309  double angleInDegree)
310 {
311  TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0);
312  rotateImage(src, dest.first, dest.second, angleInDegree, center);
313 }
314 
315 /********************************************************/
316 /* */
317 /* affineWarpImage */
318 /* */
319 /********************************************************/
320 
321 /** \brief Warp an image according to an affine transformation.
322 
323  <b> Declarations:</b>
324 
325  pass arguments explicitly:
326  \code
327  namespace vigra {
328  template <int ORDER, class T,
329  class DestIterator, class DestAccessor,
330  class C>
331  void affineWarpImage(SplineImageView<ORDER, T> const & src,
332  DestIterator dul, DestIterator dlr, DestAccessor dest,
333  MultiArrayView<2, double, C> const & affineMatrix);
334  }
335  \endcode
336 
337  use argument objects in conjunction with \ref ArgumentObjectFactories :
338  \code
339  namespace vigra {
340  template <int ORDER, class T,
341  class DestIterator, class DestAccessor,
342  class C>
343  void affineWarpImage(SplineImageView<ORDER, T> const & src,
344  triple<DestIterator, DestIterator, DestAccessor> dest,
345  MultiArrayView<2, double, C> const & affineMatrix);
346  }
347  \endcode
348 
349  The algorithm applies the given \a affineMatrix to the <i>destination coordinates</i> and copies
350  the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation.
351  If the resulting coordinate is outside the source image, nothing will be written at that destination point.
352 
353  \code
354  for all dest pixels:
355  currentSrcCoordinate = affineMatrix * currentDestCoordinate;
356  if src.isInside(currentSrcCoordinate):
357  dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value
358  \endcode
359 
360  The matrix represent a 2-dimensional affine transform by means of homogeneous coordinates,
361  i.e. it must be a 3x3 matrix whose last row is (0,0,1).
362 
363  <b> Usage:</b>
364 
365  <b>\#include</b> <vigra/affinegeometry.hxx><br>
366  Namespace: vigra
367 
368  \code
369 
370  Image src(width, height);
371  vigra::SplineImageView<3, Image::value_type> spline(srcImageRange(src));
372 
373  Image dest1(width, height);
374 
375  // equivalent (up to round-off errors) with
376  // rotateImage(spline, destImage(dest1), 45.0);
377  TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0);
378  affineWarpImage(spline, destImageRange(dest1), rotationMatrix2DDegrees(45.0, center));
379 
380  Image dest2(2*width-1, 2*height-1);
381 
382  // equivalent (up to round-off errors) with
383  // resizeImageSplineInterpolation(srcImageRange(img), destImageRange(dest2));
384  // note that scaleFactor = 0.5, because we must pass the transformation from destination to source
385  affineWarpImage(spline, destImageRange(dest2), scalingMatrix2D(0.5));
386 
387  \endcode
388 
389  <b> Required Interface:</b>
390 
391  \code
392  DestImageIterator dest_upperleft;
393 
394  double x = ..., y = ...;
395 
396  if (spline.isInside(x,y))
397  dest_accessor.set(spline(x, y), dest_upperleft);
398 
399  \endcode
400 
401  <b>See also:</b> Functions to specify affine transformation: \ref translationMatrix2D(), \ref scalingMatrix2D(),
402  \ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ref rotationMatrix2DDegrees()
403 */
404 doxygen_overloaded_function(template <...> void affineWarpImage)
405 
406 template <int ORDER, class T,
407  class DestIterator, class DestAccessor,
408  class C>
409 void affineWarpImage(SplineImageView<ORDER, T> const & src,
410  DestIterator dul, DestIterator dlr, DestAccessor dest,
411  MultiArrayView<2, double, C> const & affineMatrix)
412 {
413  vigra_precondition(rowCount(affineMatrix) == 3 && columnCount(affineMatrix) == 3 &&
414  affineMatrix(2,0) == 0.0 && affineMatrix(2,1) == 0.0 && affineMatrix(2,2) == 1.0,
415  "affineWarpImage(): matrix doesn't represent an affine transformation with homogeneous 2D coordinates.");
416 
417 
418  double w = dlr.x - dul.x;
419  double h = dlr.y - dul.y;
420 
421  for(double y = 0.0; y < h; ++y, ++dul.y)
422  {
423  typename DestIterator::row_iterator rd = dul.rowIterator();
424  for(double x=0.0; x < w; ++x, ++rd)
425  {
426  double sx = x*affineMatrix(0,0) + y*affineMatrix(0,1) + affineMatrix(0,2);
427  double sy = x*affineMatrix(1,0) + y*affineMatrix(1,1) + affineMatrix(1,2);
428  if(src.isInside(sx, sy))
429  dest.set(src(sx, sy), rd);
430  }
431  }
432 }
433 
434 template <int ORDER, class T,
435  class DestIterator, class DestAccessor,
436  class C>
437 inline
438 void affineWarpImage(SplineImageView<ORDER, T> const & src,
439  triple<DestIterator, DestIterator, DestAccessor> dest,
440  MultiArrayView<2, double, C> const & affineMatrix)
441 {
442  affineWarpImage(src, dest.first, dest.second, dest.third, affineMatrix);
443 }
444 
445 
446 //@}
447 
448 } // namespace vigra
449 
450 
451 #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.8.0 (Wed Sep 26 2012)