[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
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.6.0, Aug 13 2008 ) */ 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 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00012 /* vigra@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 doxygen_overloaded_function(template <...> void vectorToTensor) 00110 00111 template <class SrcIterator, class SrcAccessor, 00112 class DestIterator, class DestAccessor> 00113 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00114 DestIterator dul, DestAccessor dest, 00115 bool negateComponent2) 00116 { 00117 vigra_precondition(src.size(sul) == 2, 00118 "vectorToTensor(): input image must have 2 bands."); 00119 vigra_precondition(dest.size(dul) == 3, 00120 "vectorToTensor(): output image must have 3 bands."); 00121 00122 int w = slr.x - sul.x; 00123 int h = slr.y - sul.y; 00124 00125 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00126 { 00127 typename SrcIterator::row_iterator s = sul.rowIterator(); 00128 typename SrcIterator::row_iterator send = s + w; 00129 typename DestIterator::row_iterator d = dul.rowIterator(); 00130 if(negateComponent2) 00131 { 00132 for(; s < send; ++s, ++d) 00133 { 00134 dest.setComponent(sq(src.getComponent(s, 0)), d, 0); 00135 dest.setComponent(-src.getComponent(s, 0)*src.getComponent(s, 1), d, 1); 00136 // ^ negative sign to turn left-handed into right-handed coordinates 00137 dest.setComponent(sq(src.getComponent(s, 1)), d, 2); 00138 } 00139 } 00140 else 00141 { 00142 for(; s < send; ++s, ++d) 00143 { 00144 dest.setComponent(sq(src.getComponent(s, 0)), d, 0); 00145 dest.setComponent(src.getComponent(s, 0)*src.getComponent(s, 1), d, 1); 00146 dest.setComponent(sq(src.getComponent(s, 1)), d, 2); 00147 } 00148 } 00149 } 00150 } 00151 00152 template <class SrcIterator, class SrcAccessor, 00153 class DestIterator, class DestAccessor> 00154 inline 00155 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00156 DestIterator dul, DestAccessor dest) 00157 { 00158 vectorToTensor(sul, slr, src, dul, dest, true); 00159 } 00160 00161 template <class SrcIterator, class SrcAccessor, 00162 class DestIterator, class DestAccessor> 00163 inline 00164 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00165 pair<DestIterator, DestAccessor> d, 00166 bool negateComponent2) 00167 { 00168 vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateComponent2); 00169 } 00170 00171 template <class SrcIterator, class SrcAccessor, 00172 class DestIterator, class DestAccessor> 00173 inline 00174 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00175 pair<DestIterator, DestAccessor> d) 00176 { 00177 vectorToTensor(s.first, s.second, s.third, d.first, d.second, true); 00178 } 00179 00180 /********************************************************/ 00181 /* */ 00182 /* tensorEigenRepresentation */ 00183 /* */ 00184 /********************************************************/ 00185 00186 /** \brief Calculate eigen representation of a symmetric 2x2 tensor. 00187 00188 This function turns a 3-band image representing the tensor components 00189 t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen 00190 representation e1, e2, and angle, where e1 > e2. The original tensor must be 00191 defined in a right-handed coordinate system, and the angle of the tensor will 00192 then be given in mathematical positive (counter-clockwise) orientation, starting 00193 at the x-axis. 00194 00195 <b> Declarations:</b> 00196 00197 pass arguments explicitly: 00198 \code 00199 namespace vigra { 00200 template <class SrcIterator, class SrcAccessor, 00201 class DestIterator, class DestAccessor> 00202 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00203 DestIterator dul, DestAccessor dest); 00204 } 00205 \endcode 00206 00207 00208 use argument objects in conjunction with \ref ArgumentObjectFactories : 00209 \code 00210 namespace vigra { 00211 template <class SrcIterator, class SrcAccessor, 00212 class DestIterator, class DestAccessor> 00213 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00214 pair<DestIterator, DestAccessor> d); 00215 } 00216 \endcode 00217 00218 <b> Usage:</b> 00219 00220 <b>\#include</b> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>> 00221 00222 \code 00223 FVector3Image tensor(w,h); 00224 FVector3Image eigen(w,h); 00225 00226 tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen)); 00227 \endcode 00228 00229 */ 00230 doxygen_overloaded_function(template <...> void tensorEigenRepresentation) 00231 00232 template <class SrcIterator, class SrcAccessor, 00233 class DestIterator, class DestAccessor> 00234 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00235 DestIterator dul, DestAccessor dest) 00236 { 00237 vigra_precondition(src.size(sul) == 3, 00238 "tensorEigenRepresentation(): input image must have 3 bands."); 00239 vigra_precondition(dest.size(dul) == 3, 00240 "tensorEigenRepresentation(): output image must have 3 bands."); 00241 00242 int w = slr.x - sul.x; 00243 int h = slr.y - sul.y; 00244 00245 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00246 { 00247 typename SrcIterator::row_iterator s = sul.rowIterator(); 00248 typename SrcIterator::row_iterator send = s + w; 00249 typename DestIterator::row_iterator d = dul.rowIterator(); 00250 for(; s < send; ++s, ++d) 00251 { 00252 typedef typename 00253 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00254 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00255 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00256 TmpType d3 = 2.0 * src.getComponent(s,1); 00257 TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); 00258 00259 dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV 00260 dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV 00261 if(d2==0.0 && d3==0.0) 00262 { 00263 dest.setComponent(0, d, 2); // orientation 00264 } 00265 else 00266 { 00267 dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation 00268 } 00269 } 00270 } 00271 } 00272 00273 template <class SrcIterator, class SrcAccessor, 00274 class DestIterator, class DestAccessor> 00275 inline 00276 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00277 pair<DestIterator, DestAccessor> d) 00278 { 00279 tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second); 00280 } 00281 00282 /********************************************************/ 00283 /* */ 00284 /* tensorTrace */ 00285 /* */ 00286 /********************************************************/ 00287 00288 /** \brief Calculate the trace of a 2x2 tensor. 00289 00290 This function turns a 3-band image representing the tensor components 00291 t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 00292 tensor trace t11 + t22. 00293 00294 <b> Declarations:</b> 00295 00296 pass arguments explicitly: 00297 \code 00298 namespace vigra { 00299 template <class SrcIterator, class SrcAccessor, 00300 class DestIterator, class DestAccessor> 00301 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00302 DestIterator dul, DestAccessor dest); 00303 } 00304 \endcode 00305 00306 00307 use argument objects in conjunction with \ref ArgumentObjectFactories : 00308 \code 00309 namespace vigra { 00310 template <class SrcIterator, class SrcAccessor, 00311 class DestIterator, class DestAccessor> 00312 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00313 pair<DestIterator, DestAccessor> d); 00314 } 00315 \endcode 00316 00317 <b> Usage:</b> 00318 00319 <b>\#include</b> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>> 00320 00321 \code 00322 FVector3Image tensor(w,h); 00323 FImage trace(w,h); 00324 00325 tensorTrace(srcImageRange(tensor), destImage(trace)); 00326 \endcode 00327 00328 */ 00329 doxygen_overloaded_function(template <...> void tensorTrace) 00330 00331 template <class SrcIterator, class SrcAccessor, 00332 class DestIterator, class DestAccessor> 00333 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00334 DestIterator dul, DestAccessor dest) 00335 { 00336 vigra_precondition(src.size(sul) == 3, 00337 "tensorTrace(): input image must have 3 bands."); 00338 00339 int w = slr.x - sul.x; 00340 int h = slr.y - sul.y; 00341 00342 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00343 { 00344 typename SrcIterator::row_iterator s = sul.rowIterator(); 00345 typename SrcIterator::row_iterator send = s + w; 00346 typename DestIterator::row_iterator d = dul.rowIterator(); 00347 for(; s < send; ++s, ++d) 00348 { 00349 dest.set(src.getComponent(s,0) + src.getComponent(s,2), d); 00350 } 00351 } 00352 } 00353 00354 template <class SrcIterator, class SrcAccessor, 00355 class DestIterator, class DestAccessor> 00356 inline 00357 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00358 pair<DestIterator, DestAccessor> d) 00359 { 00360 tensorTrace(s.first, s.second, s.third, d.first, d.second); 00361 } 00362 00363 /********************************************************/ 00364 /* */ 00365 /* tensorToEdgeCorner */ 00366 /* */ 00367 /********************************************************/ 00368 00369 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts. 00370 00371 This function turns a 3-band image representing the tensor components 00372 t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 00373 the tensor's edgeness (difference of the tensor's 00374 eigenvalues) and orientation, and a 1-band image representing its corner part 00375 (equal to the twice the small eigen value). The original tensor must be 00376 positive definite and defined in a right-handed coordinate system (e.g. 00377 the tensor resulting from \ref boundaryTensor()). 00378 00379 <b> Declarations:</b> 00380 00381 pass arguments explicitly: 00382 \code 00383 namespace vigra { 00384 template <class SrcIterator, class SrcAccessor, 00385 class DestIterator1, class DestAccessor1, 00386 class DestIterator2, class DestAccessor2> 00387 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00388 DestIterator1 edgeul, DestAccessor1 edge, 00389 DestIterator2 cornerul, DestAccessor2 corner); 00390 } 00391 \endcode 00392 00393 00394 use argument objects in conjunction with \ref ArgumentObjectFactories : 00395 \code 00396 namespace vigra { 00397 template <class SrcIterator, class SrcAccessor, 00398 class DestIterator1, class DestAccessor1, 00399 class DestIterator2, class DestAccessor2> 00400 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00401 pair<DestIterator1, DestAccessor1> edge, 00402 pair<DestIterator2, DestAccessor2> corner); 00403 } 00404 \endcode 00405 00406 <b> Usage:</b> 00407 00408 <b>\#include</b> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>> 00409 00410 \code 00411 FVector3Image tensor(w,h); 00412 FVector2Image edgePart(w,h); 00413 FImage cornerPart(w,h); 00414 00415 tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart)); 00416 \endcode 00417 00418 */ 00419 doxygen_overloaded_function(template <...> void tensorToEdgeCorner) 00420 00421 template <class SrcIterator, class SrcAccessor, 00422 class DestIterator1, class DestAccessor1, 00423 class DestIterator2, class DestAccessor2> 00424 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00425 DestIterator1 edgeul, DestAccessor1 edge, 00426 DestIterator2 cornerul, DestAccessor2 corner) 00427 { 00428 vigra_precondition(src.size(sul) == 3, 00429 "tensorToEdgeCorner(): input image must have 3 bands."); 00430 vigra_precondition(edge.size(edgeul) == 2, 00431 "tensorToEdgeCorner(): edge image must have 2 bands."); 00432 00433 int w = slr.x - sul.x; 00434 int h = slr.y - sul.y; 00435 00436 for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y) 00437 { 00438 typename SrcIterator::row_iterator s = sul.rowIterator(); 00439 typename SrcIterator::row_iterator send = s + w; 00440 typename DestIterator1::row_iterator e = edgeul.rowIterator(); 00441 typename DestIterator2::row_iterator c = cornerul.rowIterator(); 00442 for(; s < send; ++s, ++e, ++c) 00443 { 00444 typedef typename 00445 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00446 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00447 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00448 TmpType d3 = 2.0 * src.getComponent(s,1); 00449 TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3)); 00450 00451 edge.setComponent(d4, e, 0); // edgeness = difference of EVs 00452 if(d2 == 0.0 && d3 == 0.0) 00453 { 00454 edge.setComponent(0.0, e, 1); // orientation 00455 } 00456 else 00457 { 00458 edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation 00459 } 00460 corner.set(d1 - d4, c); // cornerness = 2 * small EV 00461 } 00462 } 00463 } 00464 00465 template <class SrcIterator, class SrcAccessor, 00466 class DestIterator1, class DestAccessor1, 00467 class DestIterator2, class DestAccessor2> 00468 inline 00469 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00470 pair<DestIterator1, DestAccessor1> edge, 00471 pair<DestIterator2, DestAccessor2> corner) 00472 { 00473 tensorToEdgeCorner(s.first, s.second, s.third, 00474 edge.first, edge.second, corner.first, corner.second); 00475 } 00476 00477 //@} 00478 00479 } // namespace vigra 00480 00481 #endif /* VIGRA_TENSORUTILITIES_HXX */
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|