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

affinegeometry.hxx VIGRA

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 "multi_shape.hxx"
44 
45 #include <cmath>
46 
47 namespace vigra {
48 
49 /** \addtogroup GeometricTransformations
50 */
51 //@{
52 
53 /********************************************************/
54 /* */
55 /* create affine matrices */
56 /* */
57 /********************************************************/
58 
59 /** \brief Create homogeneous matrix representing a 2D translation.
60 
61  For use with \ref affineWarpImage().
62 */
63 inline
64 linalg::TemporaryMatrix<double> translationMatrix2D(TinyVector<double, 2> const & shift)
65 {
66  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
67  ret(0,2) = shift[0];
68  ret(1,2) = shift[1];
69  return ret;
70 }
71 
72 /** \brief Create homogeneous matrix representing a 2D uniform scaling about the coordinate origin.
73 
74  For use with \ref affineWarpImage().
75 */
76 inline
77 linalg::TemporaryMatrix<double> scalingMatrix2D(double scalingFactor)
78 {
79  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
80  ret(0,0) = scalingFactor;
81  ret(1,1) = scalingFactor;
82  return ret;
83 }
84 
85 /** \brief Create homogeneous matrix representing a 2D non-uniform scaling about the coordinate origin.
86 
87  For use with \ref affineWarpImage().
88 */
89 inline
90 linalg::TemporaryMatrix<double> scalingMatrix2D(double sx, double sy)
91 {
92  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
93  ret(0,0) = sx;
94  ret(1,1) = sy;
95  return ret;
96 }
97 
98 /** \brief Create homogeneous matrix representing a 2D shearing.
99 
100  For use with \ref affineWarpImage().
101 */
102 inline
103 linalg::TemporaryMatrix<double> shearMatrix2D(double s01, double s10)
104 {
105  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
106  ret(0,1) = s01;
107  ret(1,0) = s10;
108  return ret;
109 }
110 
111 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin.
112 
113  For use with \ref affineWarpImage(). Angle must be in radians.
114 */
115 inline
116 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle)
117 {
118  linalg::TemporaryMatrix<double> ret(identityMatrix<double>(3));
119  double s = std::sin(angle);
120  double c = std::cos(angle);
121  ret(0,0) = c;
122  ret(1,1) = c;
123  ret(0,1) = -s;
124  ret(1,0) = s;
125  return ret;
126 }
127 
128 /** \brief Create homogeneous matrix representing a 2D rotation about the coordinate origin.
129 
130  For use with \ref affineWarpImage(). Angle must be in degrees.
131 */
132 inline
133 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle)
134 {
135  return rotationMatrix2DRadians(angle*M_PI/180.0);
136 }
137 
138 /** \brief Create homogeneous matrix representing a 2D rotation about the given point.
139 
140  For use with \ref affineWarpImage(). Angle must be in radians.
141 */
142 inline
143 linalg::TemporaryMatrix<double> rotationMatrix2DRadians(double angle, TinyVector<double, 2> const & center)
144 {
145  return translationMatrix2D(center) * rotationMatrix2DRadians(angle) * translationMatrix2D(-center);
146 }
147 
148 /** \brief Create homogeneous matrix representing a 2D rotation about the given point.
149 
150  For use with \ref affineWarpImage(). Angle must be in degrees.
151 */
152 inline
153 linalg::TemporaryMatrix<double> rotationMatrix2DDegrees(double angle, TinyVector<double, 2> const & center)
154 {
155  return rotationMatrix2DRadians(angle*M_PI/180.0, center);
156 }
157 
158 /********************************************************/
159 /* */
160 /* rotateImage */
161 /* */
162 /********************************************************/
163 
164 // documentation is in basicgeometry.hxx
165 template <int ORDER, class T,
166  class DestIterator, class DestAccessor>
167 void rotateImage(SplineImageView<ORDER, T> const & src,
168  DestIterator id, DestAccessor dest,
169  double angleInDegree, TinyVector<double, 2> const & center)
170 {
171  int w = src.width();
172  int h = src.height();
173 
174  double angle = angleInDegree/180.0;
175  double c = cos_pi(angle); // avoid round-off errors for simple rotations
176  double s = sin_pi(angle);
177 
178  for(int y = 0; y < h; ++y, ++id.y)
179  {
180  typename DestIterator::row_iterator rd = id.rowIterator();
181  double sy = (y - center[1])*c - center[0]*s + center[1];
182  double sx = -(y - center[1])*s - center[0]*c + center[0];
183  for(int x=0; x < w; ++x, ++rd, sx += c, sy += s)
184  {
185  if(src.isInside(sx, sy))
186  dest.set(src(sx, sy), rd);
187  }
188  }
189 }
190 
191 template <int ORDER, class T,
192  class DestIterator, class DestAccessor>
193 inline void
194 rotateImage(SplineImageView<ORDER, T> const & src,
195  pair<DestIterator, DestAccessor> dest,
196  double angleInDegree, TinyVector<double, 2> const & center)
197 {
198  rotateImage(src, dest.first, dest.second, angleInDegree, center);
199 }
200 
201 template <int ORDER, class T,
202  class DestIterator, class DestAccessor>
203 inline void
204 rotateImage(SplineImageView<ORDER, T> const & src,
205  DestIterator id, DestAccessor dest,
206  double angleInDegree)
207 {
208  TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0);
209  rotateImage(src, id, dest, angleInDegree, center);
210 }
211 
212 template <int ORDER, class T,
213  class DestIterator, class DestAccessor>
214 inline void
215 rotateImage(SplineImageView<ORDER, T> const & src,
216  pair<DestIterator, DestAccessor> dest,
217  double angleInDegree)
218 {
219  TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0);
220  rotateImage(src, dest.first, dest.second, angleInDegree, center);
221 }
222 
223 template <int ORDER, class T,
224  class T2, class S2>
225 inline void
226 rotateImage(SplineImageView<ORDER, T> const & src,
227  MultiArrayView<2, T2, S2> dest,
228  double angleInDegree, TinyVector<double, 2> const & center)
229 {
230  rotateImage(src, destImage(dest), angleInDegree, center);
231 }
232 
233 template <int ORDER, class T,
234  class T2, class S2>
235 inline void
236 rotateImage(SplineImageView<ORDER, T> const & src,
237  MultiArrayView<2, T2, S2> dest,
238  double angleInDegree)
239 {
240  TinyVector<double, 2> center((src.width()-1.0) / 2.0, (src.height()-1.0) / 2.0);
241  rotateImage(src, destImage(dest), angleInDegree, center);
242 }
243 
244 /********************************************************/
245 /* */
246 /* affineWarpImage */
247 /* */
248 /********************************************************/
249 
250 /** \brief Warp an image according to an affine transformation.
251 
252  <b> Declarations:</b>
253 
254  pass 2D array views:
255  \code
256  namespace vigra {
257  template <int ORDER, class T,
258  class T2, class S2,
259  class C>
260  void
261  affineWarpImage(SplineImageView<ORDER, T> const & src,
262  MultiArrayView<2, T2, S2> dest,
263  MultiArrayView<2, double, C> const & affineMatrix);
264  }
265  \endcode
266 
267  \deprecatedAPI{affineWarpImage}
268  pass \ref ImageIterators and \ref DataAccessors :
269  \code
270  namespace vigra {
271  template <int ORDER, class T,
272  class DestIterator, class DestAccessor,
273  class C>
274  void affineWarpImage(SplineImageView<ORDER, T> const & src,
275  DestIterator dul, DestIterator dlr, DestAccessor dest,
276  MultiArrayView<2, double, C> const & affineMatrix);
277  }
278  \endcode
279  use argument objects in conjunction with \ref ArgumentObjectFactories :
280  \code
281  namespace vigra {
282  template <int ORDER, class T,
283  class DestIterator, class DestAccessor,
284  class C>
285  void affineWarpImage(SplineImageView<ORDER, T> const & src,
286  triple<DestIterator, DestIterator, DestAccessor> dest,
287  MultiArrayView<2, double, C> const & affineMatrix);
288  }
289  \endcode
290  \deprecatedEnd
291 
292  The algorithm applies the given \a affineMatrix to the <i>destination coordinates</i> and copies
293  the image value from the resulting source coordinates, using the given SplineImageView \a src for interpolation.
294  If the resulting coordinate is outside the source image, nothing will be written at that destination point.
295 
296  \code
297  for all dest pixels:
298  currentSrcCoordinate = affineMatrix * currentDestCoordinate;
299  if src.isInside(currentSrcCoordinate):
300  dest[currentDestCoordinate] = src[currentSrcCoordinate]; // copy an interpolated value
301  \endcode
302 
303  The matrix represents a 2-dimensional affine transform by means of homogeneous coordinates,
304  i.e. it must be a 3x3 matrix whose last row is (0,0,1).
305 
306  <b> Usage:</b>
307 
308  <b>\#include</b> <vigra/affinegeometry.hxx><br>
309  Namespace: vigra
310 
311  \code
312  MultiArray<2, float> src(width, height);
313  SplineImageView<3, float> spline(src);
314 
315  MultiArray<2, float> dest1(src.shape());
316 
317  // equivalent (up to round-off errors) to
318  // rotateImage(spline, dest1, 45.0);
319  TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0);
320  affineWarpImage(spline, dest1, rotationMatrix2DDegrees(45.0, center));
321 
322  MultiArray<2, float> dest2(2*width-1, 2*height-1);
323 
324  // equivalent (up to round-off errors) to
325  // resizeImageSplineInterpolation(img, dest2);
326  // note that scaleFactor = 0.5, because we must pass the transformation from destination to source
327  affineWarpImage(spline, dest2, scalingMatrix2D(0.5));
328  \endcode
329 
330  \deprecatedUsage{affineWarpImage}
331  \code
332  FImage src(width, height);
333  SplineImageView<3, Image::value_type> spline(srcImageRange(src));
334 
335  FImage dest1(width, height);
336 
337  // equivalent (up to round-off errors) with
338  // rotateImage(spline, destImage(dest1), 45.0);
339  TinyVector<double, 2> center((width-1.0)/2.0, (height-1.0)/2.0);
340  affineWarpImage(spline, destImageRange(dest1), rotationMatrix2DDegrees(45.0, center));
341 
342  FImage dest2(2*width-1, 2*height-1);
343 
344  // equivalent (up to round-off errors) with
345  // resizeImageSplineInterpolation(srcImageRange(img), destImageRange(dest2));
346  // note that scaleFactor = 0.5, because we must pass the transformation from destination to source
347  affineWarpImage(spline, destImageRange(dest2), scalingMatrix2D(0.5));
348  \endcode
349  <b> Required Interface:</b>
350  \code
351  DestImageIterator dest_upperleft;
352 
353  double x = ..., y = ...;
354 
355  if (spline.isInside(x,y))
356  dest_accessor.set(spline(x, y), dest_upperleft);
357  \endcode
358  \deprecatedEnd
359 
360  <b>See also:</b> Functions to specify affine transformation: \ref translationMatrix2D(), \ref scalingMatrix2D(),
361  \ref shearMatrix2D(), \ref rotationMatrix2DRadians(), \ref rotationMatrix2DDegrees()
362 */
363 doxygen_overloaded_function(template <...> void affineWarpImage)
364 
365 template <int ORDER, class T,
366  class DestIterator, class DestAccessor,
367  class C>
368 void affineWarpImage(SplineImageView<ORDER, T> const & src,
369  DestIterator dul, DestIterator dlr, DestAccessor dest,
370  MultiArrayView<2, double, C> const & affineMatrix)
371 {
372  vigra_precondition(rowCount(affineMatrix) == 3 && columnCount(affineMatrix) == 3 &&
373  affineMatrix(2,0) == 0.0 && affineMatrix(2,1) == 0.0 && affineMatrix(2,2) == 1.0,
374  "affineWarpImage(): matrix doesn't represent an affine transformation with homogeneous 2D coordinates.");
375 
376 
377  double w = dlr.x - dul.x;
378  double h = dlr.y - dul.y;
379 
380  for(double y = 0.0; y < h; ++y, ++dul.y)
381  {
382  typename DestIterator::row_iterator rd = dul.rowIterator();
383  for(double x=0.0; x < w; ++x, ++rd)
384  {
385  double sx = x*affineMatrix(0,0) + y*affineMatrix(0,1) + affineMatrix(0,2);
386  double sy = x*affineMatrix(1,0) + y*affineMatrix(1,1) + affineMatrix(1,2);
387  if(src.isInside(sx, sy))
388  dest.set(src(sx, sy), rd);
389  }
390  }
391 }
392 
393 template <int ORDER, class T,
394  class DestIterator, class DestAccessor,
395  class C>
396 inline void
397 affineWarpImage(SplineImageView<ORDER, T> const & src,
398  triple<DestIterator, DestIterator, DestAccessor> dest,
399  MultiArrayView<2, double, C> const & affineMatrix)
400 {
401  affineWarpImage(src, dest.first, dest.second, dest.third, affineMatrix);
402 }
403 
404 template <int ORDER, class T,
405  class T2, class S2,
406  class C>
407 inline void
408 affineWarpImage(SplineImageView<ORDER, T> const & src,
409  MultiArrayView<2, T2, S2> dest,
410  MultiArrayView<2, double, C> const & affineMatrix)
411 {
412  affineWarpImage(src, destImageRange(dest), affineMatrix);
413 }
414 
415 
416 //@}
417 
418 } // namespace vigra
419 
420 
421 #endif /* VIGRA_AFFINEGEOMETRY_HXX */
linalg::TemporaryMatrix< double > shearMatrix2D(double s01, double s10)
Create homogeneous matrix representing a 2D shearing.
Definition: affinegeometry.hxx:103
REAL sin_pi(REAL x)
sin(pi*x).
Definition: mathutil.hxx:1204
MultiArrayIndex rowCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:671
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
linalg::TemporaryMatrix< double > rotationMatrix2DRadians(double angle)
Create homogeneous matrix representing a 2D rotation about the coordinate origin. ...
Definition: affinegeometry.hxx:116
linalg::TemporaryMatrix< double > rotationMatrix2DDegrees(double angle)
Create homogeneous matrix representing a 2D rotation about the coordinate origin. ...
Definition: affinegeometry.hxx:133
linalg::TemporaryMatrix< double > translationMatrix2D(TinyVector< double, 2 > const &shift)
Create homogeneous matrix representing a 2D translation.
Definition: affinegeometry.hxx:64
REAL cos_pi(REAL x)
cos(pi*x).
Definition: mathutil.hxx:1242
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
MultiArrayIndex columnCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:684
void affineWarpImage(...)
Warp an image according to an affine transformation.
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
linalg::TemporaryMatrix< double > scalingMatrix2D(double scalingFactor)
Create homogeneous matrix representing a 2D uniform scaling about the coordinate origin.
Definition: affinegeometry.hxx:77

© 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.11.1 (Fri May 19 2017)