[ VIGRA Homepage | Class Index | Function Index | File Index | Main Page ]
![]() |
vigra/tensorutilities.hxx | ![]() |
---|
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2002-2004 by Ullrich Koethe */ 00004 /* Cognitive Systems Group, University of Hamburg, Germany */ 00005 /* */ 00006 /* This file is part of the VIGRA computer vision library. */ 00007 /* ( Version 1.5.0, Dec 07 2006 ) */ 00008 /* The VIGRA Website is */ 00009 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ 00010 /* Please direct questions, bug reports, and contributions to */ 00011 /* koethe@informatik.uni-hamburg.de or */ 00012 /* vigra@kogs1.informatik.uni-hamburg.de */ 00013 /* */ 00014 /* Permission is hereby granted, free of charge, to any person */ 00015 /* obtaining a copy of this software and associated documentation */ 00016 /* files (the "Software"), to deal in the Software without */ 00017 /* restriction, including without limitation the rights to use, */ 00018 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00019 /* sell copies of the Software, and to permit persons to whom the */ 00020 /* Software is furnished to do so, subject to the following */ 00021 /* conditions: */ 00022 /* */ 00023 /* The above copyright notice and this permission notice shall be */ 00024 /* included in all copies or substantial portions of the */ 00025 /* Software. */ 00026 /* */ 00027 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00028 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00029 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00030 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00031 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00032 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00033 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00034 /* OTHER DEALINGS IN THE SOFTWARE. */ 00035 /* */ 00036 /************************************************************************/ 00037 00038 #ifndef VIGRA_TENSORUTILITIES_HXX 00039 #define VIGRA_TENSORUTILITIES_HXX 00040 00041 #include <cmath> 00042 #include "utilities.hxx" 00043 00044 namespace vigra { 00045 00046 /** \addtogroup TensorImaging Tensor Image Processing 00047 */ 00048 //@{ 00049 00050 /********************************************************/ 00051 /* */ 00052 /* vectorToTensor */ 00053 /* */ 00054 /********************************************************/ 00055 00056 /** \brief Calculate the tensor (outer) product of a 2D vector with itself. 00057 00058 This function is useful to transform vector images into a tensor representation 00059 that can be used as input to tensor based processing and analysis functions 00060 (e.g. tensor smoothing). The imput pixel type must be vectors of length 2, whereas 00061 the output must contain vectors of length 3 which will represent the tensor components 00062 in the order t11, t12 (== t21 due to symmetry), t22. 00063 00064 <b>Note:</b> By default, this function negates the second component of the vector 00065 in order to turn a left handed vector (the usual resul of convolution, 00066 e.g. a gradient filter, because <tt>y</tt> runs from top to bottom) 00067 into a right handed tensor (as is required by all tensor function in VIGRA). This 00068 behavior can be switched off by setting <tt>negateComponent2 = false</tt>. 00069 00070 <b> Declarations:</b> 00071 00072 pass arguments explicitly: 00073 \code 00074 namespace vigra { 00075 template <class SrcIterator, class SrcAccessor, 00076 class DestIterator, class DestAccessor> 00077 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00078 DestIterator dul, DestAccessor dest, 00079 bool negateComponent2 = true); 00080 } 00081 \endcode 00082 00083 00084 use argument objects in conjunction with \ref ArgumentObjectFactories: 00085 \code 00086 namespace vigra { 00087 template <class SrcIterator, class SrcAccessor, 00088 class DestIterator, class DestAccessor> 00089 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00090 pair<DestIterator, DestAccessor> d, 00091 bool negateComponent2 = true); 00092 } 00093 \endcode 00094 00095 <b> Usage:</b> 00096 00097 <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>" 00098 00099 \code 00100 FImage img(w,h); 00101 FVector2Image gradient(w,h); 00102 FVector3Image tensor(w,h); 00103 00104 gaussianGradient(srcImageRange(img), destImage(gradient), 2.0); 00105 vectorToTensor(srcImageRange(gradient), destImage(tensor)); 00106 \endcode 00107 00108 */ 00109 template <class SrcIterator, class SrcAccessor, 00110 class DestIterator, class DestAccessor> 00111 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00112 DestIterator dul, DestAccessor dest, 00113 bool negateComponent2) 00114 { 00115 vigra_precondition(src.size(sul) == 2, 00116 "vectorToTensor(): input image must have 2 bands."); 00117 vigra_precondition(dest.size(dul) == 3, 00118 "vectorToTensor(): output image must have 3 bands."); 00119 00120 int w = slr.x - sul.x; 00121 int h = slr.y - sul.y; 00122 00123 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00124 { 00125 typename SrcIterator::row_iterator s = sul.rowIterator(); 00126 typename SrcIterator::row_iterator send = s + w; 00127 typename DestIterator::row_iterator d = dul.rowIterator(); 00128 if(negateComponent2) 00129 { 00130 for(; s < send; ++s, ++d) 00131 { 00132 dest.setComponent(sq(src.getComponent(s, 0)), d, 0); 00133 dest.setComponent(-src.getComponent(s, 0)*src.getComponent(s, 1), d, 1); 00134 // ^ negative sign to turn left-handed into right-handed coordinates 00135 dest.setComponent(sq(src.getComponent(s, 1)), d, 2); 00136 } 00137 } 00138 else 00139 { 00140 for(; s < send; ++s, ++d) 00141 { 00142 dest.setComponent(sq(src.getComponent(s, 0)), d, 0); 00143 dest.setComponent(src.getComponent(s, 0)*src.getComponent(s, 1), d, 1); 00144 dest.setComponent(sq(src.getComponent(s, 1)), d, 2); 00145 } 00146 } 00147 } 00148 } 00149 00150 template <class SrcIterator, class SrcAccessor, 00151 class DestIterator, class DestAccessor> 00152 inline 00153 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00154 DestIterator dul, DestAccessor dest) 00155 { 00156 vectorToTensor(sul, slr, src, dul, dest, true); 00157 } 00158 00159 template <class SrcIterator, class SrcAccessor, 00160 class DestIterator, class DestAccessor> 00161 inline 00162 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00163 pair<DestIterator, DestAccessor> d, 00164 bool negateComponent2) 00165 { 00166 vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateComponent2); 00167 } 00168 00169 template <class SrcIterator, class SrcAccessor, 00170 class DestIterator, class DestAccessor> 00171 inline 00172 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00173 pair<DestIterator, DestAccessor> d) 00174 { 00175 vectorToTensor(s.first, s.second, s.third, d.first, d.second, true); 00176 } 00177 00178 /********************************************************/ 00179 /* */ 00180 /* tensorEigenRepresentation */ 00181 /* */ 00182 /********************************************************/ 00183 00184 /** \brief Calculate eigen representation of a symmetric 2x2 tensor. 00185 00186 This function turns a 3-band image representing the tensor components 00187 t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen 00188 representation e1, e2, and angle, where e1 > e2. The original tensor must be 00189 defined in a right-handed coordinate system, and the angle of the tensor will 00190 then be given in mathematical positive (counter-clockwise) orientation, starting 00191 at the x-axis. 00192 00193 <b> Declarations:</b> 00194 00195 pass arguments explicitly: 00196 \code 00197 namespace vigra { 00198 template <class SrcIterator, class SrcAccessor, 00199 class DestIterator, class DestAccessor> 00200 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00201 DestIterator dul, DestAccessor dest); 00202 } 00203 \endcode 00204 00205 00206 use argument objects in conjunction with \ref ArgumentObjectFactories: 00207 \code 00208 namespace vigra { 00209 template <class SrcIterator, class SrcAccessor, 00210 class DestIterator, class DestAccessor> 00211 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00212 pair<DestIterator, DestAccessor> d); 00213 } 00214 \endcode 00215 00216 <b> Usage:</b> 00217 00218 <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>" 00219 00220 \code 00221 FVector3Image tensor(w,h); 00222 FVector3Image eigen(w,h); 00223 00224 tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen)); 00225 \endcode 00226 00227 */ 00228 template <class SrcIterator, class SrcAccessor, 00229 class DestIterator, class DestAccessor> 00230 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00231 DestIterator dul, DestAccessor dest) 00232 { 00233 vigra_precondition(src.size(sul) == 3, 00234 "tensorEigenRepresentation(): input image must have 3 bands."); 00235 vigra_precondition(dest.size(dul) == 3, 00236 "tensorEigenRepresentation(): output image must have 3 bands."); 00237 00238 int w = slr.x - sul.x; 00239 int h = slr.y - sul.y; 00240 00241 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00242 { 00243 typename SrcIterator::row_iterator s = sul.rowIterator(); 00244 typename SrcIterator::row_iterator send = s + w; 00245 typename DestIterator::row_iterator d = dul.rowIterator(); 00246 for(; s < send; ++s, ++d) 00247 { 00248 typedef typename 00249 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00250 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00251 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00252 TmpType d3 = 2.0 * src.getComponent(s,1); 00253 TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); 00254 00255 dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV 00256 dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV 00257 if(d2==0.0 && d3==0.0) 00258 { 00259 dest.setComponent(0, d, 2); // orientation 00260 } 00261 else 00262 { 00263 dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation 00264 } 00265 } 00266 } 00267 } 00268 00269 template <class SrcIterator, class SrcAccessor, 00270 class DestIterator, class DestAccessor> 00271 inline 00272 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00273 pair<DestIterator, DestAccessor> d) 00274 { 00275 tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second); 00276 } 00277 00278 /********************************************************/ 00279 /* */ 00280 /* tensorTrace */ 00281 /* */ 00282 /********************************************************/ 00283 00284 /** \brief Calculate the trace of a 2x2 tensor. 00285 00286 This function turns a 3-band image representing the tensor components 00287 t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 00288 tensor trace t11 + t22. 00289 00290 <b> Declarations:</b> 00291 00292 pass arguments explicitly: 00293 \code 00294 namespace vigra { 00295 template <class SrcIterator, class SrcAccessor, 00296 class DestIterator, class DestAccessor> 00297 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00298 DestIterator dul, DestAccessor dest); 00299 } 00300 \endcode 00301 00302 00303 use argument objects in conjunction with \ref ArgumentObjectFactories: 00304 \code 00305 namespace vigra { 00306 template <class SrcIterator, class SrcAccessor, 00307 class DestIterator, class DestAccessor> 00308 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00309 pair<DestIterator, DestAccessor> d); 00310 } 00311 \endcode 00312 00313 <b> Usage:</b> 00314 00315 <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>" 00316 00317 \code 00318 FVector3Image tensor(w,h); 00319 FImage trace(w,h); 00320 00321 tensorTrace(srcImageRange(tensor), destImage(trace)); 00322 \endcode 00323 00324 */ 00325 template <class SrcIterator, class SrcAccessor, 00326 class DestIterator, class DestAccessor> 00327 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00328 DestIterator dul, DestAccessor dest) 00329 { 00330 vigra_precondition(src.size(sul) == 3, 00331 "tensorTrace(): input image must have 3 bands."); 00332 00333 int w = slr.x - sul.x; 00334 int h = slr.y - sul.y; 00335 00336 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00337 { 00338 typename SrcIterator::row_iterator s = sul.rowIterator(); 00339 typename SrcIterator::row_iterator send = s + w; 00340 typename DestIterator::row_iterator d = dul.rowIterator(); 00341 for(; s < send; ++s, ++d) 00342 { 00343 dest.set(src.getComponent(s,0) + src.getComponent(s,2), d); 00344 } 00345 } 00346 } 00347 00348 template <class SrcIterator, class SrcAccessor, 00349 class DestIterator, class DestAccessor> 00350 inline 00351 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00352 pair<DestIterator, DestAccessor> d) 00353 { 00354 tensorTrace(s.first, s.second, s.third, d.first, d.second); 00355 } 00356 00357 /********************************************************/ 00358 /* */ 00359 /* tensorToEdgeCorner */ 00360 /* */ 00361 /********************************************************/ 00362 00363 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts. 00364 00365 This function turns a 3-band image representing the tensor components 00366 t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 00367 the tensor's edgeness (difference of the tensor's 00368 eigenvalues) and orientation, and a 1-band image representing its corner part 00369 (equal to the twice the small eigen value). The original tensor must be 00370 positive definite and defined in a right-handed coordinate system (e.g. 00371 the tensor resulting from \ref boundaryTensor()). 00372 00373 <b> Declarations:</b> 00374 00375 pass arguments explicitly: 00376 \code 00377 namespace vigra { 00378 template <class SrcIterator, class SrcAccessor, 00379 class DestIterator1, class DestAccessor1, 00380 class DestIterator2, class DestAccessor2> 00381 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00382 DestIterator1 edgeul, DestAccessor1 edge, 00383 DestIterator2 cornerul, DestAccessor2 corner); 00384 } 00385 \endcode 00386 00387 00388 use argument objects in conjunction with \ref ArgumentObjectFactories: 00389 \code 00390 namespace vigra { 00391 template <class SrcIterator, class SrcAccessor, 00392 class DestIterator1, class DestAccessor1, 00393 class DestIterator2, class DestAccessor2> 00394 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00395 pair<DestIterator1, DestAccessor1> edge, 00396 pair<DestIterator2, DestAccessor2> corner); 00397 } 00398 \endcode 00399 00400 <b> Usage:</b> 00401 00402 <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>" 00403 00404 \code 00405 FVector3Image tensor(w,h); 00406 FVector2Image edgePart(w,h); 00407 FImage cornerPart(w,h); 00408 00409 tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart)); 00410 \endcode 00411 00412 */ 00413 template <class SrcIterator, class SrcAccessor, 00414 class DestIterator1, class DestAccessor1, 00415 class DestIterator2, class DestAccessor2> 00416 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00417 DestIterator1 edgeul, DestAccessor1 edge, 00418 DestIterator2 cornerul, DestAccessor2 corner) 00419 { 00420 vigra_precondition(src.size(sul) == 3, 00421 "tensorToEdgeCorner(): input image must have 3 bands."); 00422 vigra_precondition(edge.size(edgeul) == 2, 00423 "tensorToEdgeCorner(): edge image must have 2 bands."); 00424 00425 int w = slr.x - sul.x; 00426 int h = slr.y - sul.y; 00427 00428 for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y) 00429 { 00430 typename SrcIterator::row_iterator s = sul.rowIterator(); 00431 typename SrcIterator::row_iterator send = s + w; 00432 typename DestIterator1::row_iterator e = edgeul.rowIterator(); 00433 typename DestIterator2::row_iterator c = cornerul.rowIterator(); 00434 for(; s < send; ++s, ++e, ++c) 00435 { 00436 typedef typename 00437 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00438 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00439 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00440 TmpType d3 = 2.0 * src.getComponent(s,1); 00441 TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); 00442 00443 edge.setComponent(d4, e, 0); // edgeness = difference of EVs 00444 if(d2 == 0.0 && d3 == 0.0) 00445 { 00446 edge.setComponent(0.0, e, 1); // orientation 00447 } 00448 else 00449 { 00450 edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation 00451 } 00452 corner.set(d1 - d4, c); // cornerness = 2 * small EV 00453 } 00454 } 00455 } 00456 00457 template <class SrcIterator, class SrcAccessor, 00458 class DestIterator1, class DestAccessor1, 00459 class DestIterator2, class DestAccessor2> 00460 inline 00461 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00462 pair<DestIterator1, DestAccessor1> edge, 00463 pair<DestIterator2, DestAccessor2> corner) 00464 { 00465 tensorToEdgeCorner(s.first, s.second, s.third, 00466 edge.first, edge.second, corner.first, corner.second); 00467 } 00468 00469 //@} 00470 00471 } // namespace vigra 00472 00473 #endif /* VIGRA_TENSORUTILITIES_HXX */
© Ullrich Köthe (koethe@informatik.uni-hamburg.de) |
html generated using doxygen and Python
|