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

polynomial_registration.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2007-2013 by Benjamin Seppke */
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_POLYNOMIAL_REGISTRATION_HXX
37 #define VIGRA_POLYNOMIAL_REGISTRATION_HXX
38
39 #include "mathutil.hxx"
40 #include "matrix.hxx"
41 #include "linear_solve.hxx"
42 #include "tinyvector.hxx"
43 #include "splineimageview.hxx"
44
45 namespace vigra
46 {
47
48 /** \addtogroup Registration Image Registration
49 */
50 //@{
51
52 /**
53 * Iterative function for determinination of the polynom weights:
54 *
55 * Example: order=2, x, y
56 * ----->
57 * [1,
58 * x, y,
59 * x^2, x*y, y^2]
60 *
61 * This function is needed, because the polynomial transformation Matrix
62 * has the the same number of rows. the target position is then determined
63 * by multiplying each x- and y-transformation result value with the
64 * corresponding weight for the current x- and y-coordinate, given by this
65 * function.
66 */
67 std::vector<double> polynomialWarpWeights(double x, double y, unsigned int polynom_order)
68 {
69 unsigned int poly_count = (polynom_order+1)*(polynom_order+2)/2;
70
71 std::vector<double> weights(poly_count);
72
73 unsigned int weight_idx=0;
74
75 for (unsigned int order=0; order<=polynom_order; order++)
76 {
77 for(unsigned int i=0; i<=order; i++, weight_idx++)
78 {
79 weights[weight_idx] = pow(x,(double)order-i)*pow(y,(double)i);
80 }
81 }
82 return weights;
83 }
84
85 /********************************************************/
86 /* */
87 /* polynomialMatrix2DFromCorrespondingPoints */
88 /* */
89 /********************************************************/
90
91 /** \brief Create polynomial matrix of a certain degree that maps corresponding points onto each other.
92
93 For use with \ref polynomialWarpImage() of same degree.
94
95 Since polynoms are usually non-linear functions, a special semantics is embedded to define
96 a matrix here. Each matrix consist of two rows, containing x- and y-factors of the polynom.
97
98 The meaning of the matrix is explained at the example of a polynom of 2nd order:
99
100 First Row = [a_x b_x c_x d_x e_x f_x]
101 Second Row = [a_y b_y c_y d_y e_y f_y]
102
103 The transformed coordinate p'=[x' y'] of a position p=[x y] is then:
104
105 x' = a_x + b_x*x + c_x*y + d_x*x^2 + e_x*x*y + f_x*y^2
106 y' = a_y + b_y*x + c_y*y + d_y*x^2 + e_y*x*y + f_y*y^2
107
108 Note that the order of the polynom's factors is directly influenced by the
109 \ref polynomialWarpWeights() function and follows the intuitive scheme.
110 */
111 template <int PolynomOrder,
112 class SrcPointIterator,
113 class DestPointIterator>
114 linalg::TemporaryMatrix<double>
115 polynomialMatrix2DFromCorrespondingPoints(SrcPointIterator s, SrcPointIterator s_end,
116 DestPointIterator d)
117 {
118 int point_count = s_end - s;
119 int poly_count = (PolynomOrder+1)*(PolynomOrder+2)/2;
120
121 vigra::Matrix<double> A(point_count,poly_count), b1(point_count,1), res1(poly_count,1), b2(point_count,1), res2(poly_count,1);
122 std::vector<double> weights;
123
124 for (int i =0; i<point_count; ++i, ++s, ++d)
125 {
126 weights = polynomialWarpWeights((*d)[0], (*d)[1], PolynomOrder);
127
128 for(int c=0; c<poly_count; c++)
129 {
130 A(i,c) = weights[c];
131 }
132
133 b1(i,0)=(*s)[0];b2(i,0)=(*s)[1];
134 }
135
136 if(!vigra::linearSolve( A, b1, res1 ) || !vigra::linearSolve( A, b2, res2 ))
137 vigra_fail("polynomialMatrix2DFromCorrespondingPoints(): singular solution matrix.");
138
139 vigra::Matrix<double> res(poly_count,2);
140
141 for(int c=0; c<poly_count; c++)
142 {
143 res(c,0) = res1(c,0);
144 res(c,1) = res2(c,0);
145 }
146
147 return res;
148 }
149
150
151 /********************************************************/
152 /* */
153 /* polynomialWarpImage */
154 /* */
155 /********************************************************/
156
157 /** \brief Warp an image according to an polynomial transformation.
158
159 To get more information about the structure of the matrix,
160 see \ref polynomialMatrix2DFromCorrespondingPoints().
161
162 <b>\#include</b> <vigra/polynomial_registration.hxx><br>
163 Namespace: vigra
164
165 pass 2D array views:
166 \code
167 namespace vigra {
168 template <int ORDER, class T,
169 class T2, class S2,
170 class C>
171 void
172 polynomialWarpImage(SplineImageView<ORDER, T> const & src,
173 MultiArrayView<2, T2, S2> dest,
174 MultiArrayView<2, double, C> const & polynomialMatrix);
175 }
176 \endcode
177
178 \deprecatedAPI{polynomialWarpImage}
179
180 pass arguments explicitly:
181 \code
182 namespace vigra {
183 template <int ORDER, class T,
184 class DestIterator, class DestAccessor,
185 class C>
186 void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
187 DestIterator dul, DestIterator dlr, DestAccessor dest,
188 MultiArrayView<2, double, C> const & polynomialMatrix);
189 }
190 \endcode
191
192 use argument objects in conjunction with \ref ArgumentObjectFactories :
193 \code
194 namespace vigra {
195 template <int ORDER, class T,
196 class DestIterator, class DestAccessor,
197 class C>
198 void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
199 triple<DestIterator, DestIterator, DestAccessor> dest,
200 MultiArrayView<2, double, C> const & polynomialMatrix);
201 }
202 \endcode
203 \deprecatedEnd
204 */
205 doxygen_overloaded_function(template <...> void polynomialWarpImage)
206
207 template <int PolynomOrder,
208 int ORDER, class T,
209 class DestIterator, class DestAccessor,
210 class C>
211 void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
212 DestIterator dul, DestIterator dlr, DestAccessor dest,
213 MultiArrayView<2, double, C> const & polynomialMatrix)
214 {
215 int poly_count = (PolynomOrder+1)*(PolynomOrder+2)/2;
216
217 vigra_precondition(rowCount(polynomialMatrix) == poly_count && columnCount(polynomialMatrix) == 2,
218 "polynomialWarpImage(): matrix doesn't represent a polynomial transformation of given degreee in 2D coordinates.");
219
220 double w = dlr.x - dul.x;
221 double h = dlr.y - dul.y;
222
223 std::vector<double> weights(poly_count);
224
225 for(double y = 0.0; y < h; ++y, ++dul.y)
226 {
227 typename DestIterator::row_iterator rd = dul.rowIterator();
228 for(double x=0.0; x < w; ++x, ++rd)
229 {
230 weights = polynomialWarpWeights(x,y, PolynomOrder);
231
232 double sx=0;
233 double sy=0;
234
235 for(int c=0; c<poly_count; c++)
236 {
237 sx += weights[c]*polynomialMatrix(c,0);
238 sy += weights[c]*polynomialMatrix(c,1);
239 }
240
241 if(src.isInside(sx, sy))
242 dest.set(src(sx, sy), rd);
243 }
244 }
245 }
246
247 template <int PolynomOrder,
248 int ORDER, class T,
249 class DestIterator, class DestAccessor,
250 class C>
251 inline
252 void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
253 triple<DestIterator, DestIterator, DestAccessor> dest,
254 MultiArrayView<2, double, C> const & polynomialMatrix)
255 {
256 polynomialWarpImage<PolynomOrder>(src, dest.first, dest.second, dest.third, polynomialMatrix);
257 }
258
259
260 template <int PolynomOrder,
261 int ORDER, class T,
262 class T2, class S2,
263 class C>
264 inline
265 void polynomialWarpImage(SplineImageView<ORDER, T> const & src,
266 MultiArrayView<2, T2, S2> dest,
267 MultiArrayView<2, double, C> const & polynomialMatrix)
268 {
269 polynomialWarpImage<PolynomOrder>(src, destImageRange(dest), polynomialMatrix);
270 }
271
272
273 //@}
274
275 } // namespace vigra
276
277
278 #endif /* VIGRA_POLYNOMIAL_REGISTRATION_HXX */
vigra::linalg::rowCount
MultiArrayIndex rowCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:671
vigra::polynomialWarpWeights
std::vector< double > polynomialWarpWeights(double x, double y, unsigned int polynom_order)
Definition: polynomial_registration.hxx:67
vigra::doxygen_overloaded_function
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
vigra::linalg::columnCount
MultiArrayIndex columnCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:684
vigra::polynomialMatrix2DFromCorrespondingPoints
linalg::TemporaryMatrix< double > polynomialMatrix2DFromCorrespondingPoints(SrcPointIterator s, SrcPointIterator s_end, DestPointIterator d)
Create polynomial matrix of a certain degree that maps corresponding points onto each other...
Definition: polynomial_registration.hxx:115
vigra::polynomialWarpImage
void polynomialWarpImage(...)
Warp an image according to an polynomial transformation.
vigra::linalg::linearSolve
bool linearSolve(...)

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