[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
vigra/tensorutilities.hxx | ![]() |
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2002-2004 by Ullrich Koethe */ 00004 /* */ 00005 /* This file is part of the VIGRA computer vision library. */ 00006 /* The VIGRA Website is */ 00007 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 00008 /* Please direct questions, bug reports, and contributions to */ 00009 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00010 /* vigra@informatik.uni-hamburg.de */ 00011 /* */ 00012 /* Permission is hereby granted, free of charge, to any person */ 00013 /* obtaining a copy of this software and associated documentation */ 00014 /* files (the "Software"), to deal in the Software without */ 00015 /* restriction, including without limitation the rights to use, */ 00016 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00017 /* sell copies of the Software, and to permit persons to whom the */ 00018 /* Software is furnished to do so, subject to the following */ 00019 /* conditions: */ 00020 /* */ 00021 /* The above copyright notice and this permission notice shall be */ 00022 /* included in all copies or substantial portions of the */ 00023 /* Software. */ 00024 /* */ 00025 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00026 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00027 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00028 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00029 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00030 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00031 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00032 /* OTHER DEALINGS IN THE SOFTWARE. */ 00033 /* */ 00034 /************************************************************************/ 00035 00036 #ifndef VIGRA_TENSORUTILITIES_HXX 00037 #define VIGRA_TENSORUTILITIES_HXX 00038 00039 #include <cmath> 00040 #include "utilities.hxx" 00041 #include "mathutil.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 input 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> In order to account for the left-handedness of the image coordinate system, 00064 the second tensor component (t12) can be negated by setting <tt>negateComponent2 = false</tt>. 00065 Angles will then be interpreted counter-clockwise rather than clockwise. By default, 00066 this behavior is switched off. 00067 00068 <b> Declarations:</b> 00069 00070 pass arguments explicitly: 00071 \code 00072 namespace vigra { 00073 template <class SrcIterator, class SrcAccessor, 00074 class DestIterator, class DestAccessor> 00075 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00076 DestIterator dul, DestAccessor dest, 00077 bool negateComponent2 = false); 00078 } 00079 \endcode 00080 00081 00082 use argument objects in conjunction with \ref ArgumentObjectFactories : 00083 \code 00084 namespace vigra { 00085 template <class SrcIterator, class SrcAccessor, 00086 class DestIterator, class DestAccessor> 00087 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00088 pair<DestIterator, DestAccessor> d, 00089 bool negateComponent2 = false); 00090 } 00091 \endcode 00092 00093 <b> Usage:</b> 00094 00095 <b>\#include</b> <vigra/tensorutilities.hxx> 00096 00097 \code 00098 FImage img(w,h); 00099 FVector2Image gradient(w,h); 00100 FVector3Image tensor(w,h); 00101 00102 gaussianGradient(srcImageRange(img), destImage(gradient), 2.0); 00103 vectorToTensor(srcImageRange(gradient), destImage(tensor)); 00104 \endcode 00105 00106 */ 00107 doxygen_overloaded_function(template <...> void vectorToTensor) 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, false); 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, false); 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. When the tensor is 00189 defined in a left-handed coordinate system (the default on images), the angle will 00190 then be given in clockwise orientation, starting at the x-axis. Otherwise, it 00191 will be given in counter-clockwise orientation. 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> <vigra/tensorutilities.hxx> 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 doxygen_overloaded_function(template <...> void tensorEigenRepresentation) 00229 00230 template <class SrcIterator, class SrcAccessor, 00231 class DestIterator, class DestAccessor> 00232 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00233 DestIterator dul, DestAccessor dest) 00234 { 00235 vigra_precondition(src.size(sul) == 3, 00236 "tensorEigenRepresentation(): input image must have 3 bands."); 00237 vigra_precondition(dest.size(dul) == 3, 00238 "tensorEigenRepresentation(): output image must have 3 bands."); 00239 00240 int w = slr.x - sul.x; 00241 int h = slr.y - sul.y; 00242 00243 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00244 { 00245 typename SrcIterator::row_iterator s = sul.rowIterator(); 00246 typename SrcIterator::row_iterator send = s + w; 00247 typename DestIterator::row_iterator d = dul.rowIterator(); 00248 for(; s < send; ++s, ++d) 00249 { 00250 typedef typename 00251 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00252 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00253 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00254 TmpType d3 = TmpType(2.0) * src.getComponent(s,1); 00255 TmpType d4 = (TmpType)hypot(d2, d3); 00256 00257 dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV 00258 dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV 00259 if(d2==0.0 && d3==0.0) 00260 { 00261 dest.setComponent(0, d, 2); // orientation 00262 } 00263 else 00264 { 00265 dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation 00266 } 00267 } 00268 } 00269 } 00270 00271 template <class SrcIterator, class SrcAccessor, 00272 class DestIterator, class DestAccessor> 00273 inline 00274 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00275 pair<DestIterator, DestAccessor> d) 00276 { 00277 tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second); 00278 } 00279 00280 /********************************************************/ 00281 /* */ 00282 /* tensorTrace */ 00283 /* */ 00284 /********************************************************/ 00285 00286 /** \brief Calculate the trace of a 2x2 tensor. 00287 00288 This function turns a 3-band image representing the tensor components 00289 t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 00290 tensor trace t11 + t22. 00291 00292 <b> Declarations:</b> 00293 00294 pass arguments explicitly: 00295 \code 00296 namespace vigra { 00297 template <class SrcIterator, class SrcAccessor, 00298 class DestIterator, class DestAccessor> 00299 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00300 DestIterator dul, DestAccessor dest); 00301 } 00302 \endcode 00303 00304 00305 use argument objects in conjunction with \ref ArgumentObjectFactories : 00306 \code 00307 namespace vigra { 00308 template <class SrcIterator, class SrcAccessor, 00309 class DestIterator, class DestAccessor> 00310 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00311 pair<DestIterator, DestAccessor> d); 00312 } 00313 \endcode 00314 00315 <b> Usage:</b> 00316 00317 <b>\#include</b> <vigra/tensorutilities.hxx> 00318 00319 \code 00320 FVector3Image tensor(w,h); 00321 FImage trace(w,h); 00322 00323 tensorTrace(srcImageRange(tensor), destImage(trace)); 00324 \endcode 00325 00326 */ 00327 doxygen_overloaded_function(template <...> void tensorTrace) 00328 00329 template <class SrcIterator, class SrcAccessor, 00330 class DestIterator, class DestAccessor> 00331 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00332 DestIterator dul, DestAccessor dest) 00333 { 00334 vigra_precondition(src.size(sul) == 3, 00335 "tensorTrace(): input image must have 3 bands."); 00336 00337 int w = slr.x - sul.x; 00338 int h = slr.y - sul.y; 00339 00340 for(int y=0; y<h; ++y, ++sul.y, ++dul.y) 00341 { 00342 typename SrcIterator::row_iterator s = sul.rowIterator(); 00343 typename SrcIterator::row_iterator send = s + w; 00344 typename DestIterator::row_iterator d = dul.rowIterator(); 00345 for(; s < send; ++s, ++d) 00346 { 00347 dest.set(src.getComponent(s,0) + src.getComponent(s,2), d); 00348 } 00349 } 00350 } 00351 00352 template <class SrcIterator, class SrcAccessor, 00353 class DestIterator, class DestAccessor> 00354 inline 00355 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00356 pair<DestIterator, DestAccessor> d) 00357 { 00358 tensorTrace(s.first, s.second, s.third, d.first, d.second); 00359 } 00360 00361 /********************************************************/ 00362 /* */ 00363 /* tensorToEdgeCorner */ 00364 /* */ 00365 /********************************************************/ 00366 00367 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts. 00368 00369 This function turns a 3-band image representing the tensor components 00370 t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 00371 the tensor's edgeness (difference of the tensor's 00372 eigenvalues) and orientation, and a 1-band image representing its corner part 00373 (equal to the twice the small eigen value). The original tensor must be 00374 positive definite and defined in a right-handed coordinate system (e.g. 00375 the tensor resulting from \ref boundaryTensor()). 00376 00377 <b> Declarations:</b> 00378 00379 pass arguments explicitly: 00380 \code 00381 namespace vigra { 00382 template <class SrcIterator, class SrcAccessor, 00383 class DestIterator1, class DestAccessor1, 00384 class DestIterator2, class DestAccessor2> 00385 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00386 DestIterator1 edgeul, DestAccessor1 edge, 00387 DestIterator2 cornerul, DestAccessor2 corner); 00388 } 00389 \endcode 00390 00391 00392 use argument objects in conjunction with \ref ArgumentObjectFactories : 00393 \code 00394 namespace vigra { 00395 template <class SrcIterator, class SrcAccessor, 00396 class DestIterator1, class DestAccessor1, 00397 class DestIterator2, class DestAccessor2> 00398 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00399 pair<DestIterator1, DestAccessor1> edge, 00400 pair<DestIterator2, DestAccessor2> corner); 00401 } 00402 \endcode 00403 00404 <b> Usage:</b> 00405 00406 <b>\#include</b> <vigra/tensorutilities.hxx> 00407 00408 \code 00409 FVector3Image tensor(w,h); 00410 FVector2Image edgePart(w,h); 00411 FImage cornerPart(w,h); 00412 00413 tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart)); 00414 \endcode 00415 00416 */ 00417 doxygen_overloaded_function(template <...> void tensorToEdgeCorner) 00418 00419 template <class SrcIterator, class SrcAccessor, 00420 class DestIterator1, class DestAccessor1, 00421 class DestIterator2, class DestAccessor2> 00422 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00423 DestIterator1 edgeul, DestAccessor1 edge, 00424 DestIterator2 cornerul, DestAccessor2 corner) 00425 { 00426 vigra_precondition(src.size(sul) == 3, 00427 "tensorToEdgeCorner(): input image must have 3 bands."); 00428 vigra_precondition(edge.size(edgeul) == 2, 00429 "tensorToEdgeCorner(): edge image must have 2 bands."); 00430 00431 int w = slr.x - sul.x; 00432 int h = slr.y - sul.y; 00433 00434 for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y) 00435 { 00436 typename SrcIterator::row_iterator s = sul.rowIterator(); 00437 typename SrcIterator::row_iterator send = s + w; 00438 typename DestIterator1::row_iterator e = edgeul.rowIterator(); 00439 typename DestIterator2::row_iterator c = cornerul.rowIterator(); 00440 for(; s < send; ++s, ++e, ++c) 00441 { 00442 typedef typename 00443 NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType; 00444 TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2); 00445 TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2); 00446 TmpType d3 = 2.0 * src.getComponent(s,1); 00447 TmpType d4 = (TmpType)hypot(d2, d3); 00448 00449 edge.setComponent(d4, e, 0); // edgeness = difference of EVs 00450 if(d2 == 0.0 && d3 == 0.0) 00451 { 00452 edge.setComponent(0.0, e, 1); // orientation 00453 } 00454 else 00455 { 00456 edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation 00457 } 00458 corner.set(d1 - d4, c); // cornerness = 2 * small EV 00459 } 00460 } 00461 } 00462 00463 template <class SrcIterator, class SrcAccessor, 00464 class DestIterator1, class DestAccessor1, 00465 class DestIterator2, class DestAccessor2> 00466 inline 00467 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s, 00468 pair<DestIterator1, DestAccessor1> edge, 00469 pair<DestIterator2, DestAccessor2> corner) 00470 { 00471 tensorToEdgeCorner(s.first, s.second, s.third, 00472 edge.first, edge.second, corner.first, corner.second); 00473 } 00474 00475 //@} 00476 00477 } // namespace vigra 00478 00479 #endif /* VIGRA_TENSORUTILITIES_HXX */
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|