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

tensorutilities.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 2002-2004 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_TENSORUTILITIES_HXX
37 #define VIGRA_TENSORUTILITIES_HXX
38 
39 #include <cmath>
40 #include "utilities.hxx"
41 #include "mathutil.hxx"
42 
43 namespace vigra {
44 
45 /** \addtogroup TensorImaging Tensor Image Processing
46 */
47 //@{
48 
49 /********************************************************/
50 /* */
51 /* vectorToTensor */
52 /* */
53 /********************************************************/
54 
55 /** \brief Calculate the tensor (outer) product of a 2D vector with itself.
56 
57  This function is useful to transform vector images into a tensor representation
58  that can be used as input to tensor based processing and analysis functions
59  (e.g. tensor smoothing). The input pixel type must be vectors of length 2, whereas
60  the output must contain vectors of length 3 which will represent the tensor components
61  in the order t11, t12 (== t21 due to symmetry), t22.
62 
63  <b>Note:</b> In order to account for the left-handedness of the image coordinate system,
64  the second tensor component (t12) can be negated by setting <tt>negateComponent2 = false</tt>.
65  Angles will then be interpreted counter-clockwise rather than clockwise. By default,
66  this behavior is switched off.
67 
68  <b> Declarations:</b>
69 
70  pass arguments explicitly:
71  \code
72  namespace vigra {
73  template <class SrcIterator, class SrcAccessor,
74  class DestIterator, class DestAccessor>
75  void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
76  DestIterator dul, DestAccessor dest,
77  bool negateComponent2 = false);
78  }
79  \endcode
80 
81 
82  use argument objects in conjunction with \ref ArgumentObjectFactories :
83  \code
84  namespace vigra {
85  template <class SrcIterator, class SrcAccessor,
86  class DestIterator, class DestAccessor>
87  void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
88  pair<DestIterator, DestAccessor> d,
89  bool negateComponent2 = false);
90  }
91  \endcode
92 
93  <b> Usage:</b>
94 
95  <b>\#include</b> <vigra/tensorutilities.hxx>
96 
97  \code
98  FImage img(w,h);
99  FVector2Image gradient(w,h);
100  FVector3Image tensor(w,h);
101 
102  gaussianGradient(srcImageRange(img), destImage(gradient), 2.0);
103  vectorToTensor(srcImageRange(gradient), destImage(tensor));
104  \endcode
105 
106 */
107 doxygen_overloaded_function(template <...> void vectorToTensor)
108 
109 template <class SrcIterator, class SrcAccessor,
110  class DestIterator, class DestAccessor>
111 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
112  DestIterator dul, DestAccessor dest,
113  bool negateComponent2)
114 {
115  vigra_precondition(src.size(sul) == 2,
116  "vectorToTensor(): input image must have 2 bands.");
117  vigra_precondition(dest.size(dul) == 3,
118  "vectorToTensor(): output image must have 3 bands.");
119 
120  int w = slr.x - sul.x;
121  int h = slr.y - sul.y;
122 
123  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
124  {
125  typename SrcIterator::row_iterator s = sul.rowIterator();
126  typename SrcIterator::row_iterator send = s + w;
127  typename DestIterator::row_iterator d = dul.rowIterator();
128  if(negateComponent2)
129  {
130  for(; s < send; ++s, ++d)
131  {
132  dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
133  dest.setComponent(-src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
134  // ^ negative sign to turn left-handed into right-handed coordinates
135  dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
136  }
137  }
138  else
139  {
140  for(; s < send; ++s, ++d)
141  {
142  dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
143  dest.setComponent(src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
144  dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
145  }
146  }
147  }
148 }
149 
150 template <class SrcIterator, class SrcAccessor,
151  class DestIterator, class DestAccessor>
152 inline
153 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
154  DestIterator dul, DestAccessor dest)
155 {
156  vectorToTensor(sul, slr, src, dul, dest, false);
157 }
158 
159 template <class SrcIterator, class SrcAccessor,
160  class DestIterator, class DestAccessor>
161 inline
162 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
163  pair<DestIterator, DestAccessor> d,
164  bool negateComponent2)
165 {
166  vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateComponent2);
167 }
168 
169 template <class SrcIterator, class SrcAccessor,
170  class DestIterator, class DestAccessor>
171 inline
172 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
173  pair<DestIterator, DestAccessor> d)
174 {
175  vectorToTensor(s.first, s.second, s.third, d.first, d.second, false);
176 }
177 
178 /********************************************************/
179 /* */
180 /* tensorEigenRepresentation */
181 /* */
182 /********************************************************/
183 
184 /** \brief Calculate eigen representation of a symmetric 2x2 tensor.
185 
186  This function turns a 3-band image representing the tensor components
187  t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen
188  representation e1, e2, and angle, where e1 > e2. When the tensor is
189  defined in a left-handed coordinate system (the default on images), the angle will
190  then be given in clockwise orientation, starting at the x-axis. Otherwise, it
191  will be given in counter-clockwise orientation.
192 
193  <b> Declarations:</b>
194 
195  pass arguments explicitly:
196  \code
197  namespace vigra {
198  template <class SrcIterator, class SrcAccessor,
199  class DestIterator, class DestAccessor>
200  void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
201  DestIterator dul, DestAccessor dest);
202  }
203  \endcode
204 
205 
206  use argument objects in conjunction with \ref ArgumentObjectFactories :
207  \code
208  namespace vigra {
209  template <class SrcIterator, class SrcAccessor,
210  class DestIterator, class DestAccessor>
211  void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
212  pair<DestIterator, DestAccessor> d);
213  }
214  \endcode
215 
216  <b> Usage:</b>
217 
218  <b>\#include</b> <vigra/tensorutilities.hxx>
219 
220  \code
221  FVector3Image tensor(w,h);
222  FVector3Image eigen(w,h);
223 
224  tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen));
225  \endcode
226 
227 */
228 doxygen_overloaded_function(template <...> void tensorEigenRepresentation)
229 
230 template <class SrcIterator, class SrcAccessor,
231  class DestIterator, class DestAccessor>
232 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
233  DestIterator dul, DestAccessor dest)
234 {
235  vigra_precondition(src.size(sul) == 3,
236  "tensorEigenRepresentation(): input image must have 3 bands.");
237  vigra_precondition(dest.size(dul) == 3,
238  "tensorEigenRepresentation(): output image must have 3 bands.");
239 
240  int w = slr.x - sul.x;
241  int h = slr.y - sul.y;
242 
243  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
244  {
245  typename SrcIterator::row_iterator s = sul.rowIterator();
246  typename SrcIterator::row_iterator send = s + w;
247  typename DestIterator::row_iterator d = dul.rowIterator();
248  for(; s < send; ++s, ++d)
249  {
250  typedef typename
251  NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
252  TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
253  TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
254  TmpType d3 = TmpType(2.0) * src.getComponent(s,1);
255  TmpType d4 = (TmpType)hypot(d2, d3);
256 
257  dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV
258  dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV
259  if(d2==0.0 && d3==0.0)
260  {
261  dest.setComponent(0, d, 2); // orientation
262  }
263  else
264  {
265  dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation
266  }
267  }
268  }
269 }
270 
271 template <class SrcIterator, class SrcAccessor,
272  class DestIterator, class DestAccessor>
273 inline
274 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
275  pair<DestIterator, DestAccessor> d)
276 {
277  tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second);
278 }
279 
280 /********************************************************/
281 /* */
282 /* tensorTrace */
283 /* */
284 /********************************************************/
285 
286 /** \brief Calculate the trace of a 2x2 tensor.
287 
288  This function turns a 3-band image representing the tensor components
289  t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the
290  tensor trace t11 + t22.
291 
292  <b> Declarations:</b>
293 
294  pass arguments explicitly:
295  \code
296  namespace vigra {
297  template <class SrcIterator, class SrcAccessor,
298  class DestIterator, class DestAccessor>
299  void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
300  DestIterator dul, DestAccessor dest);
301  }
302  \endcode
303 
304 
305  use argument objects in conjunction with \ref ArgumentObjectFactories :
306  \code
307  namespace vigra {
308  template <class SrcIterator, class SrcAccessor,
309  class DestIterator, class DestAccessor>
310  void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
311  pair<DestIterator, DestAccessor> d);
312  }
313  \endcode
314 
315  <b> Usage:</b>
316 
317  <b>\#include</b> <vigra/tensorutilities.hxx>
318 
319  \code
320  FVector3Image tensor(w,h);
321  FImage trace(w,h);
322 
323  tensorTrace(srcImageRange(tensor), destImage(trace));
324  \endcode
325 
326 */
327 doxygen_overloaded_function(template <...> void tensorTrace)
328 
329 template <class SrcIterator, class SrcAccessor,
330  class DestIterator, class DestAccessor>
331 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
332  DestIterator dul, DestAccessor dest)
333 {
334  vigra_precondition(src.size(sul) == 3,
335  "tensorTrace(): input image must have 3 bands.");
336 
337  int w = slr.x - sul.x;
338  int h = slr.y - sul.y;
339 
340  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
341  {
342  typename SrcIterator::row_iterator s = sul.rowIterator();
343  typename SrcIterator::row_iterator send = s + w;
344  typename DestIterator::row_iterator d = dul.rowIterator();
345  for(; s < send; ++s, ++d)
346  {
347  dest.set(src.getComponent(s,0) + src.getComponent(s,2), d);
348  }
349  }
350 }
351 
352 template <class SrcIterator, class SrcAccessor,
353  class DestIterator, class DestAccessor>
354 inline
355 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
356  pair<DestIterator, DestAccessor> d)
357 {
358  tensorTrace(s.first, s.second, s.third, d.first, d.second);
359 }
360 
361 /********************************************************/
362 /* */
363 /* tensorToEdgeCorner */
364 /* */
365 /********************************************************/
366 
367 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts.
368 
369  This function turns a 3-band image representing the tensor components
370  t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding
371  the tensor's edgeness (difference of the tensor's
372  eigenvalues) and orientation, and a 1-band image representing its corner part
373  (equal to the twice the small eigen value). The original tensor must be
374  positive definite and defined in a right-handed coordinate system (e.g.
375  the tensor resulting from \ref boundaryTensor()).
376 
377  <b> Declarations:</b>
378 
379  pass arguments explicitly:
380  \code
381  namespace vigra {
382  template <class SrcIterator, class SrcAccessor,
383  class DestIterator1, class DestAccessor1,
384  class DestIterator2, class DestAccessor2>
385  void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
386  DestIterator1 edgeul, DestAccessor1 edge,
387  DestIterator2 cornerul, DestAccessor2 corner);
388  }
389  \endcode
390 
391 
392  use argument objects in conjunction with \ref ArgumentObjectFactories :
393  \code
394  namespace vigra {
395  template <class SrcIterator, class SrcAccessor,
396  class DestIterator1, class DestAccessor1,
397  class DestIterator2, class DestAccessor2>
398  void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
399  pair<DestIterator1, DestAccessor1> edge,
400  pair<DestIterator2, DestAccessor2> corner);
401  }
402  \endcode
403 
404  <b> Usage:</b>
405 
406  <b>\#include</b> <vigra/tensorutilities.hxx>
407 
408  \code
409  FVector3Image tensor(w,h);
410  FVector2Image edgePart(w,h);
411  FImage cornerPart(w,h);
412 
413  tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart));
414  \endcode
415 
416 */
417 doxygen_overloaded_function(template <...> void tensorToEdgeCorner)
418 
419 template <class SrcIterator, class SrcAccessor,
420  class DestIterator1, class DestAccessor1,
421  class DestIterator2, class DestAccessor2>
422 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
423  DestIterator1 edgeul, DestAccessor1 edge,
424  DestIterator2 cornerul, DestAccessor2 corner)
425 {
426  vigra_precondition(src.size(sul) == 3,
427  "tensorToEdgeCorner(): input image must have 3 bands.");
428  vigra_precondition(edge.size(edgeul) == 2,
429  "tensorToEdgeCorner(): edge image must have 2 bands.");
430 
431  int w = slr.x - sul.x;
432  int h = slr.y - sul.y;
433 
434  for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y)
435  {
436  typename SrcIterator::row_iterator s = sul.rowIterator();
437  typename SrcIterator::row_iterator send = s + w;
438  typename DestIterator1::row_iterator e = edgeul.rowIterator();
439  typename DestIterator2::row_iterator c = cornerul.rowIterator();
440  for(; s < send; ++s, ++e, ++c)
441  {
442  typedef typename
443  NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
444  TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
445  TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
446  TmpType d3 = 2.0 * src.getComponent(s,1);
447  TmpType d4 = (TmpType)hypot(d2, d3);
448 
449  edge.setComponent(d4, e, 0); // edgeness = difference of EVs
450  if(d2 == 0.0 && d3 == 0.0)
451  {
452  edge.setComponent(0.0, e, 1); // orientation
453  }
454  else
455  {
456  edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation
457  }
458  corner.set(d1 - d4, c); // cornerness = 2 * small EV
459  }
460  }
461 }
462 
463 template <class SrcIterator, class SrcAccessor,
464  class DestIterator1, class DestAccessor1,
465  class DestIterator2, class DestAccessor2>
466 inline
467 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
468  pair<DestIterator1, DestAccessor1> edge,
469  pair<DestIterator2, DestAccessor2> corner)
470 {
471  tensorToEdgeCorner(s.first, s.second, s.third,
472  edge.first, edge.second, corner.first, corner.second);
473 }
474 
475 //@}
476 
477 } // namespace vigra
478 
479 #endif /* VIGRA_TENSORUTILITIES_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)