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