vigra - vigra/affinegeometry.hxx Source File

[ 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 "multi_shape.hxx"
44
45 #include <cmath>
46
47 namespace vigra {
48
49 /** \addtogroup GeometricTransformations Geometric Transformations
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 */

© 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.10.0 (Thu Jan 8 2015)