[ 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
47namespace 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*/
63inline
64linalg::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*/
76inline
77linalg::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*/
89inline
90linalg::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*/
102inline
103linalg::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*/
115inline
116linalg::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*/
132inline
133linalg::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*/
142inline
143linalg::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*/
152inline
153linalg::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
165template <int ORDER, class T,
166 class DestIterator, class DestAccessor>
167void 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
191template <int ORDER, class T,
192 class DestIterator, class DestAccessor>
193inline void
194rotateImage(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
201template <int ORDER, class T,
202 class DestIterator, class DestAccessor>
203inline void
204rotateImage(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
212template <int ORDER, class T,
213 class DestIterator, class DestAccessor>
214inline void
215rotateImage(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
223template <int ORDER, class T,
224 class T2, class S2>
225inline void
226rotateImage(SplineImageView<ORDER, T> const & src,
228 double angleInDegree, TinyVector<double, 2> const & center)
229{
230 rotateImage(src, destImage(dest), angleInDegree, center);
231}
232
233template <int ORDER, class T,
234 class T2, class S2>
235inline void
236rotateImage(SplineImageView<ORDER, T> const & src,
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*/
363doxygen_overloaded_function(template <...> void affineWarpImage)
364
365template <int ORDER, class T,
366 class DestIterator, class DestAccessor,
367 class C>
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
393template <int ORDER, class T,
394 class DestIterator, class DestAccessor,
395 class C>
396inline void
397affineWarpImage(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
404template <int ORDER, class T,
405 class T2, class S2,
406 class C>
407inline void
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 */
Base class for, and view to, MultiArray.
Definition multi_array.hxx:705
Create a continuous view onto a discrete image using splines.
Definition splineimageview.hxx:100
bool isInside(double x, double y) const
Definition splineimageview.hxx:487
Class for fixed size vectors.
Definition tinyvector.hxx:1008
void identityMatrix(MultiArrayView< 2, T, C > &r)
Definition matrix.hxx:845
MultiArrayIndex columnCount(const MultiArrayView< 2, T, C > &x)
Definition matrix.hxx:684
linalg::TemporaryMatrix< double > scalingMatrix2D(double scalingFactor)
Create homogeneous matrix representing a 2D uniform scaling about the coordinate origin.
Definition affinegeometry.hxx:77
linalg::TemporaryMatrix< double > rotationMatrix2DDegrees(double angle)
Create homogeneous matrix representing a 2D rotation about the coordinate origin.
Definition affinegeometry.hxx:133
REAL cos_pi(REAL x)
cos(pi*x).
Definition mathutil.hxx:1242
REAL sin_pi(REAL x)
sin(pi*x).
Definition mathutil.hxx:1204
linalg::TemporaryMatrix< double > rotationMatrix2DRadians(double angle)
Create homogeneous matrix representing a 2D rotation about the coordinate origin.
Definition affinegeometry.hxx:116
linalg::TemporaryMatrix< double > shearMatrix2D(double s01, double s10)
Create homogeneous matrix representing a 2D shearing.
Definition affinegeometry.hxx:103
linalg::TemporaryMatrix< double > translationMatrix2D(TinyVector< double, 2 > const &shift)
Create homogeneous matrix representing a 2D translation.
Definition affinegeometry.hxx:64
MultiArrayIndex rowCount(const MultiArrayView< 2, T, C > &x)
Definition matrix.hxx:671
void affineWarpImage(...)
Warp an image according to an affine transformation.

© 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.12.1 (Thu Feb 27 2025)