[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 1998-2006 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 00037 #ifndef VIGRA_NOISE_NORMALIZATION_HXX 00038 #define VIGRA_NOISE_NORMALIZATION_HXX 00039 00040 #include "utilities.hxx" 00041 #include "tinyvector.hxx" 00042 #include "stdimage.hxx" 00043 #include "transformimage.hxx" 00044 #include "combineimages.hxx" 00045 #include "localminmax.hxx" 00046 #include "functorexpression.hxx" 00047 #include "numerictraits.hxx" 00048 #include "separableconvolution.hxx" 00049 #include "linear_solve.hxx" 00050 #include "array_vector.hxx" 00051 #include "static_assert.hxx" 00052 #include <algorithm> 00053 00054 namespace vigra { 00055 00056 /** \addtogroup NoiseNormalization Noise Normalization 00057 Estimate noise with intensity-dependent variance and transform it into additive Gaussian noise. 00058 */ 00059 //@{ 00060 00061 /********************************************************/ 00062 /* */ 00063 /* NoiseNormalizationOptions */ 00064 /* */ 00065 /********************************************************/ 00066 00067 /** \brief Pass options to one of the noise normalization functions. 00068 00069 <tt>NoiseNormalizationOptions</tt> is an argument object that holds various optional 00070 parameters used by the noise normalization functions. If a parameter is not explicitly 00071 set, a suitable default will be used. 00072 00073 <b> Usage:</b> 00074 00075 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 00076 Namespace: vigra 00077 00078 \code 00079 vigra::BImage src(w,h); 00080 std::vector<vigra::TinyVector<double, 2> > result; 00081 00082 ... 00083 vigra::noiseVarianceEstimation(srcImageRange(src), result, 00084 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0)); 00085 \endcode 00086 */ 00087 class NoiseNormalizationOptions 00088 { 00089 public: 00090 00091 /** Initialize all options with default values. 00092 */ 00093 NoiseNormalizationOptions() 00094 : window_radius(6), 00095 cluster_count(10), 00096 noise_estimation_quantile(1.5), 00097 averaging_quantile(0.8), 00098 noise_variance_initial_guess(10.0), 00099 use_gradient(true) 00100 {} 00101 00102 /** Select the noise estimation algorithm. 00103 00104 If \a r is <tt>true</tt>, use the gradient-based noise estimator according to Förstner (default). 00105 Otherwise, use an algorithm that uses the intensity values directly. 00106 */ 00107 NoiseNormalizationOptions & useGradient(bool r) 00108 { 00109 use_gradient = r; 00110 return *this; 00111 } 00112 00113 /** Set the window radius for a single noise estimate. 00114 Every window of the given size gives raise to one intensity/variance pair.<br> 00115 Default: 6 pixels 00116 */ 00117 NoiseNormalizationOptions & windowRadius(unsigned int r) 00118 { 00119 vigra_precondition(r > 0, 00120 "NoiseNormalizationOptions: window radius must be > 0."); 00121 window_radius = r; 00122 return *this; 00123 } 00124 00125 /** Set the number of clusters for non-parametric noise normalization. 00126 The intensity/variance pairs found are grouped into clusters before the noise 00127 normalization transform is computed.<br> 00128 Default: 10 clusters 00129 */ 00130 NoiseNormalizationOptions & clusterCount(unsigned int c) 00131 { 00132 vigra_precondition(c > 0, 00133 "NoiseNormalizationOptions: cluster count must be > 0."); 00134 cluster_count = c; 00135 return *this; 00136 } 00137 00138 /** Set the quantile for cluster averaging. 00139 After clustering, the cluster center (i.e. average noise variance as a function of the average 00140 intensity in the cluster) is computed using only the cluster members whose estimated variance 00141 is below \a quantile times the maximum variance in the cluster.<br> 00142 Default: 0.8<br> 00143 Precondition: 0 < \a quantile <= 1.0 00144 */ 00145 NoiseNormalizationOptions & averagingQuantile(double quantile) 00146 { 00147 vigra_precondition(quantile > 0.0 && quantile <= 1.0, 00148 "NoiseNormalizationOptions: averaging quantile must be between 0 and 1."); 00149 averaging_quantile = quantile; 00150 return *this; 00151 } 00152 00153 /** Set the operating range of the robust noise estimator. 00154 Intensity changes that are larger than \a quantile times the current estimate of the noise variance 00155 are ignored by the robust noise estimator.<br> 00156 Default: 1.5<br> 00157 Precondition: 0 < \a quantile 00158 */ 00159 NoiseNormalizationOptions & noiseEstimationQuantile(double quantile) 00160 { 00161 vigra_precondition(quantile > 0.0, 00162 "NoiseNormalizationOptions: noise estimation quantile must be > 0."); 00163 noise_estimation_quantile = quantile; 00164 return *this; 00165 } 00166 00167 /** Set the initial estimate of the noise variance. 00168 Robust noise variance estimation is an iterative procedure starting at the given value.<br> 00169 Default: 10.0<br> 00170 Precondition: 0 < \a quess 00171 */ 00172 NoiseNormalizationOptions & noiseVarianceInitialGuess(double guess) 00173 { 00174 vigra_precondition(guess > 0.0, 00175 "NoiseNormalizationOptions: noise variance initial guess must be > 0."); 00176 noise_variance_initial_guess = guess; 00177 return *this; 00178 } 00179 00180 unsigned int window_radius, cluster_count; 00181 double noise_estimation_quantile, averaging_quantile, noise_variance_initial_guess; 00182 bool use_gradient; 00183 }; 00184 00185 //@} 00186 00187 template <class ArgumentType, class ResultType> 00188 class NonparametricNoiseNormalizationFunctor 00189 { 00190 struct Segment 00191 { 00192 double lower, a, b, shift; 00193 }; 00194 00195 ArrayVector<Segment> segments_; 00196 00197 template <class T> 00198 double exec(unsigned int k, T t) const 00199 { 00200 if(segments_[k].a == 0.0) 00201 { 00202 return t / VIGRA_CSTD::sqrt(segments_[k].b); 00203 } 00204 else 00205 { 00206 return 2.0 / segments_[k].a * VIGRA_CSTD::sqrt(std::max(0.0, segments_[k].a * t + segments_[k].b)); 00207 } 00208 } 00209 00210 public: 00211 typedef ArgumentType argument_type; 00212 typedef ResultType result_type; 00213 00214 template <class Vector> 00215 NonparametricNoiseNormalizationFunctor(Vector const & clusters) 00216 : segments_(clusters.size()-1) 00217 { 00218 for(unsigned int k = 0; k<segments_.size(); ++k) 00219 { 00220 segments_[k].lower = clusters[k][0]; 00221 segments_[k].a = (clusters[k+1][1] - clusters[k][1]) / (clusters[k+1][0] - clusters[k][0]); 00222 segments_[k].b = clusters[k][1] - segments_[k].a * clusters[k][0]; 00223 // FIXME: set a to zero if it is very small 00224 // - determine what 'very small' means 00225 // - shouldn't the two formulas (for a == 0, a != 0) be equal in the limit a -> 0 ? 00226 00227 if(k == 0) 00228 { 00229 segments_[k].shift = segments_[k].lower - exec(k, segments_[k].lower); 00230 } 00231 else 00232 { 00233 segments_[k].shift = exec(k-1, segments_[k].lower) - exec(k, segments_[k].lower) + segments_[k-1].shift; 00234 } 00235 } 00236 } 00237 00238 result_type operator()(argument_type t) const 00239 { 00240 // find the segment 00241 unsigned int k = 0; 00242 for(; k < segments_.size(); ++k) 00243 if(t < segments_[k].lower) 00244 break; 00245 if(k > 0) 00246 --k; 00247 return detail::RequiresExplicitCast<ResultType>::cast(exec(k, t) + segments_[k].shift); 00248 } 00249 }; 00250 00251 template <class ArgumentType, class ResultType> 00252 class QuadraticNoiseNormalizationFunctor 00253 { 00254 double a, b, c, d, f, o; 00255 00256 void init(double ia, double ib, double ic, double xmin) 00257 { 00258 a = ia; 00259 b = ib; 00260 c = ic; 00261 d = VIGRA_CSTD::sqrt(VIGRA_CSTD::fabs(c)); 00262 if(c > 0.0) 00263 { 00264 o = VIGRA_CSTD::log(VIGRA_CSTD::fabs((2.0*c*xmin + b)/d + 2*VIGRA_CSTD::sqrt(c*sq(xmin) +b*xmin + a)))/d; 00265 f = 0.0; 00266 } 00267 else 00268 { 00269 f = VIGRA_CSTD::sqrt(b*b - 4.0*a*c); 00270 o = -VIGRA_CSTD::asin((2.0*c*xmin+b)/f)/d; 00271 } 00272 } 00273 00274 public: 00275 typedef ArgumentType argument_type; 00276 typedef ResultType result_type; 00277 00278 template <class Vector> 00279 QuadraticNoiseNormalizationFunctor(Vector const & clusters) 00280 { 00281 double xmin = NumericTraits<double>::max(); 00282 Matrix<double> m(3,3), r(3, 1), l(3, 1); 00283 for(unsigned int k = 0; k<clusters.size(); ++k) 00284 { 00285 l(0,0) = 1.0; 00286 l(1,0) = clusters[k][0]; 00287 l(2,0) = sq(clusters[k][0]); 00288 m += outer(l); 00289 r += clusters[k][1]*l; 00290 if(clusters[k][0] < xmin) 00291 xmin = clusters[k][0]; 00292 } 00293 00294 linearSolve(m, r, l); 00295 init(l(0,0), l(1,0), l(2,0), xmin); 00296 } 00297 00298 result_type operator()(argument_type t) const 00299 { 00300 double r; 00301 if(c > 0.0) 00302 r = VIGRA_CSTD::log(VIGRA_CSTD::fabs((2.0*c*t + b)/d + 2.0*VIGRA_CSTD::sqrt(c*t*t +b*t + a)))/d-o; 00303 else 00304 r = -VIGRA_CSTD::asin((2.0*c*t+b)/f)/d-o; 00305 return detail::RequiresExplicitCast<ResultType>::cast(r); 00306 } 00307 }; 00308 00309 template <class ArgumentType, class ResultType> 00310 class LinearNoiseNormalizationFunctor 00311 { 00312 double a, b, o; 00313 00314 void init(double ia, double ib, double xmin) 00315 { 00316 a = ia; 00317 b = ib; 00318 if(b != 0.0) 00319 { 00320 o = xmin - 2.0 / b * VIGRA_CSTD::sqrt(a + b * xmin); 00321 } 00322 else 00323 { 00324 o = xmin - xmin / VIGRA_CSTD::sqrt(a); 00325 } 00326 } 00327 00328 public: 00329 typedef ArgumentType argument_type; 00330 typedef ResultType result_type; 00331 00332 template <class Vector> 00333 LinearNoiseNormalizationFunctor(Vector const & clusters) 00334 { 00335 double xmin = NumericTraits<double>::max(); 00336 Matrix<double> m(2,2), r(2, 1), l(2, 1); 00337 for(unsigned int k = 0; k<clusters.size(); ++k) 00338 { 00339 l(0,0) = 1.0; 00340 l(1,0) = clusters[k][0]; 00341 m += outer(l); 00342 r += clusters[k][1]*l; 00343 if(clusters[k][0] < xmin) 00344 xmin = clusters[k][0]; 00345 } 00346 00347 linearSolve(m, r, l); 00348 init(l(0,0), l(1,0), xmin); 00349 } 00350 00351 result_type operator()(argument_type t) const 00352 { 00353 double r; 00354 if(b != 0.0) 00355 r = 2.0 / b * VIGRA_CSTD::sqrt(a + b*t) + o; 00356 else 00357 r = t / VIGRA_CSTD::sqrt(a) + o; 00358 return detail::RequiresExplicitCast<ResultType>::cast(r); 00359 } 00360 }; 00361 00362 #define VIGRA_NoiseNormalizationFunctor(name, type, size) \ 00363 template <class ResultType> \ 00364 class name<type, ResultType> \ 00365 { \ 00366 ResultType lut_[size]; \ 00367 \ 00368 public: \ 00369 typedef type argument_type; \ 00370 typedef ResultType result_type; \ 00371 \ 00372 template <class Vector> \ 00373 name(Vector const & clusters) \ 00374 { \ 00375 name<double, ResultType> f(clusters); \ 00376 \ 00377 for(unsigned int k = 0; k < size; ++k) \ 00378 { \ 00379 lut_[k] = f(k); \ 00380 } \ 00381 } \ 00382 \ 00383 result_type operator()(argument_type t) const \ 00384 { \ 00385 return lut_[t]; \ 00386 } \ 00387 }; 00388 00389 VIGRA_NoiseNormalizationFunctor(NonparametricNoiseNormalizationFunctor, UInt8, 256) 00390 VIGRA_NoiseNormalizationFunctor(NonparametricNoiseNormalizationFunctor, UInt16, 65536) 00391 VIGRA_NoiseNormalizationFunctor(QuadraticNoiseNormalizationFunctor, UInt8, 256) 00392 VIGRA_NoiseNormalizationFunctor(QuadraticNoiseNormalizationFunctor, UInt16, 65536) 00393 VIGRA_NoiseNormalizationFunctor(LinearNoiseNormalizationFunctor, UInt8, 256) 00394 VIGRA_NoiseNormalizationFunctor(LinearNoiseNormalizationFunctor, UInt16, 65536) 00395 00396 #undef VIGRA_NoiseNormalizationFunctor 00397 00398 namespace detail { 00399 00400 template <class SrcIterator, class SrcAcessor, 00401 class GradIterator> 00402 bool 00403 iterativeNoiseEstimationChi2(SrcIterator s, SrcAcessor src, GradIterator g, 00404 double & mean, double & variance, 00405 double robustnessThreshold, int windowRadius) 00406 { 00407 double l2 = sq(robustnessThreshold); 00408 double countThreshold = 1.0 - VIGRA_CSTD::exp(-l2); 00409 double f = (1.0 - VIGRA_CSTD::exp(-l2)) / (1.0 - (1.0 + l2)*VIGRA_CSTD::exp(-l2)); 00410 00411 Diff2D ul(-windowRadius, -windowRadius); 00412 int r2 = sq(windowRadius); 00413 00414 for(int iter=0; iter<100 ; ++iter) // maximum iteration 100 only for terminating 00415 // if something is wrong 00416 { 00417 double sum=0.0; 00418 double gsum=0.0; 00419 unsigned int count = 0; 00420 unsigned int tcount = 0; 00421 00422 SrcIterator siy = s + ul; 00423 GradIterator giy = g + ul; 00424 for(int y=-windowRadius; y <= windowRadius; y++, ++siy.y, ++giy.y) 00425 { 00426 typename SrcIterator::row_iterator six = siy.rowIterator(); 00427 typename GradIterator::row_iterator gix = giy.rowIterator(); 00428 for(int x=-windowRadius; x <= windowRadius; x++, ++six, ++gix) 00429 { 00430 if (sq(x) + sq(y) > r2) 00431 continue; 00432 00433 ++tcount; 00434 if (*gix < l2*variance) 00435 { 00436 sum += src(six); 00437 gsum += *gix; 00438 ++count; 00439 } 00440 } 00441 } 00442 if (count==0) // not homogeneous enough 00443 return false; 00444 00445 double oldvariance = variance; 00446 variance= f * gsum / count; 00447 mean = sum / count; 00448 00449 if ( closeAtTolerance(oldvariance - variance, 0.0, 1e-10)) 00450 return (count >= tcount * countThreshold / 2.0); // sufficiently many valid points 00451 } 00452 return false; // no convergence 00453 } 00454 00455 template <class SrcIterator, class SrcAcessor, 00456 class GradIterator> 00457 bool 00458 iterativeNoiseEstimationGauss(SrcIterator s, SrcAcessor src, GradIterator, 00459 double & mean, double & variance, 00460 double robustnessThreshold, int windowRadius) 00461 { 00462 double l2 = sq(robustnessThreshold); 00463 double countThreshold = erf(VIGRA_CSTD::sqrt(0.5 * l2)); 00464 double f = countThreshold / (countThreshold - VIGRA_CSTD::sqrt(2.0/M_PI*l2)*VIGRA_CSTD::exp(-l2/2.0)); 00465 00466 mean = src(s); 00467 00468 Diff2D ul(-windowRadius, -windowRadius); 00469 int r2 = sq(windowRadius); 00470 00471 for(int iter=0; iter<100 ; ++iter) // maximum iteration 100 only for terminating 00472 // if something is wrong 00473 { 00474 double sum = 0.0; 00475 double sum2 = 0.0; 00476 unsigned int count = 0; 00477 unsigned int tcount = 0; 00478 00479 SrcIterator siy = s + ul; 00480 for(int y=-windowRadius; y <= windowRadius; y++, ++siy.y) 00481 { 00482 typename SrcIterator::row_iterator six = siy.rowIterator(); 00483 for(int x=-windowRadius; x <= windowRadius; x++, ++six) 00484 { 00485 if (sq(x) + sq(y) > r2) 00486 continue; 00487 00488 ++tcount; 00489 if (sq(src(six) - mean) < l2*variance) 00490 { 00491 sum += src(six); 00492 sum2 += sq(src(six)); 00493 ++count; 00494 } 00495 } 00496 } 00497 if (count==0) // not homogeneous enough 00498 return false; 00499 00500 double oldmean = mean; 00501 double oldvariance = variance; 00502 mean = sum / count; 00503 variance= f * (sum2 / count - sq(mean)); 00504 00505 if ( closeAtTolerance(oldmean - mean, 0.0, 1e-10) && 00506 closeAtTolerance(oldvariance - variance, 0.0, 1e-10)) 00507 return (count >= tcount * countThreshold / 2.0); // sufficiently many valid points 00508 } 00509 return false; // no convergence 00510 } 00511 00512 00513 template <class SrcIterator, class SrcAccessor, 00514 class DestIterator, class DestAccessor> 00515 void 00516 symmetricDifferenceSquaredMagnitude( 00517 SrcIterator sul, SrcIterator slr, SrcAccessor src, 00518 DestIterator dul, DestAccessor dest) 00519 { 00520 using namespace functor; 00521 int w = slr.x - sul.x; 00522 int h = slr.y - sul.y; 00523 00524 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType; 00525 typedef BasicImage<TmpType> TmpImage; 00526 00527 Kernel1D<double> mask; 00528 mask.initSymmetricGradient(); 00529 mask.setBorderTreatment(BORDER_TREATMENT_REFLECT); 00530 00531 TmpImage dx(w, h), dy(w, h); 00532 separableConvolveX(srcIterRange(sul, slr, src), destImage(dx), kernel1d(mask)); 00533 separableConvolveY(srcIterRange(sul, slr, src), destImage(dy), kernel1d(mask)); 00534 combineTwoImages(srcImageRange(dx), srcImage(dy), destIter(dul, dest), Arg1()*Arg1() + Arg2()*Arg2()); 00535 } 00536 00537 template <class SrcIterator, class SrcAccessor, 00538 class DestIterator, class DestAccessor> 00539 void 00540 findHomogeneousRegionsFoerstner( 00541 SrcIterator sul, SrcIterator slr, SrcAccessor src, 00542 DestIterator dul, DestAccessor dest, 00543 unsigned int windowRadius = 6, double homogeneityThreshold = 40.0) 00544 { 00545 using namespace vigra::functor; 00546 int w = slr.x - sul.x; 00547 int h = slr.y - sul.y; 00548 00549 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType; 00550 typedef BasicImage<TmpType> TmpImage; 00551 00552 BImage btmp(w, h); 00553 transformImage(srcIterRange(sul, slr, src), destImage(btmp), 00554 ifThenElse(Arg1() <= Param(homogeneityThreshold), Param(1), Param(0))); 00555 00556 // Erosion 00557 discErosion(srcImageRange(btmp), destIter(dul, dest), windowRadius); 00558 } 00559 00560 template <class SrcIterator, class SrcAccessor, 00561 class DestIterator, class DestAccessor> 00562 void 00563 findHomogeneousRegions( 00564 SrcIterator sul, SrcIterator slr, SrcAccessor src, 00565 DestIterator dul, DestAccessor dest) 00566 { 00567 localMinima(sul, slr, src, dul, dest); 00568 } 00569 00570 template <class Vector1, class Vector2> 00571 void noiseVarianceListMedianCut(Vector1 const & noise, Vector2 & clusters, 00572 unsigned int maxClusterCount) 00573 { 00574 typedef typename Vector2::value_type Result; 00575 00576 clusters.push_back(Result(0, noise.size())); 00577 00578 while(clusters.size() <= maxClusterCount) 00579 { 00580 // find biggest cluster 00581 unsigned int kMax = 0; 00582 double diffMax = 0.0; 00583 for(unsigned int k=0; k < clusters.size(); ++k) 00584 { 00585 double diff = noise[clusters[k][1]-1][0] - noise[clusters[k][0]][0]; 00586 if(diff > diffMax) 00587 { 00588 diffMax = diff; 00589 kMax = k; 00590 } 00591 } 00592 00593 if(diffMax == 0.0) 00594 return; // all clusters have only one value 00595 00596 unsigned int k1 = clusters[kMax][0], 00597 k2 = clusters[kMax][1]; 00598 unsigned int kSplit = k1 + (k2 - k1) / 2; 00599 clusters[kMax][1] = kSplit; 00600 clusters.push_back(Result(kSplit, k2)); 00601 } 00602 } 00603 00604 struct SortNoiseByMean 00605 { 00606 template <class T> 00607 bool operator()(T const & l, T const & r) const 00608 { 00609 return l[0] < r[0]; 00610 } 00611 }; 00612 00613 struct SortNoiseByVariance 00614 { 00615 template <class T> 00616 bool operator()(T const & l, T const & r) const 00617 { 00618 return l[1] < r[1]; 00619 } 00620 }; 00621 00622 template <class Vector1, class Vector2, class Vector3> 00623 void noiseVarianceClusterAveraging(Vector1 & noise, Vector2 & clusters, 00624 Vector3 & result, double quantile) 00625 { 00626 typedef typename Vector1::iterator Iter; 00627 typedef typename Vector3::value_type Result; 00628 00629 for(unsigned int k=0; k<clusters.size(); ++k) 00630 { 00631 Iter i1 = noise.begin() + clusters[k][0]; 00632 Iter i2 = noise.begin() + clusters[k][1]; 00633 00634 std::sort(i1, i2, SortNoiseByVariance()); 00635 00636 std::size_t size = static_cast<std::size_t>(VIGRA_CSTD::ceil(quantile*(i2 - i1))); 00637 if(static_cast<std::size_t>(i2 - i1) < size) 00638 size = i2 - i1; 00639 if(size < 1) 00640 size = 1; 00641 i2 = i1 + size; 00642 00643 double mean = 0.0, 00644 variance = 0.0; 00645 for(; i1 < i2; ++i1) 00646 { 00647 mean += (*i1)[0]; 00648 variance += (*i1)[1]; 00649 } 00650 00651 result.push_back(Result(mean / size, variance / size)); 00652 } 00653 } 00654 00655 template <class SrcIterator, class SrcAccessor, class BackInsertable> 00656 void noiseVarianceEstimationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00657 BackInsertable & result, 00658 NoiseNormalizationOptions const & options) 00659 { 00660 typedef typename BackInsertable::value_type ResultType; 00661 00662 unsigned int w = slr.x - sul.x; 00663 unsigned int h = slr.y - sul.y; 00664 00665 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType; 00666 typedef BasicImage<TmpType> TmpImage; 00667 00668 TmpImage gradient(w, h); 00669 symmetricDifferenceSquaredMagnitude(sul, slr, src, gradient.upperLeft(), gradient.accessor()); 00670 00671 BImage homogeneous(w, h); 00672 findHomogeneousRegions(gradient.upperLeft(), gradient.lowerRight(), gradient.accessor(), 00673 homogeneous.upperLeft(), homogeneous.accessor()); 00674 00675 // Generate noise of each of the remaining pixels == centers of homogenous areas (border is not used) 00676 unsigned int windowRadius = options.window_radius; 00677 for(unsigned int y=windowRadius; y<h-windowRadius; ++y) 00678 { 00679 for(unsigned int x=windowRadius; x<w-windowRadius; ++x) 00680 { 00681 if (! homogeneous(x, y)) 00682 continue; 00683 00684 Diff2D center(x, y); 00685 double mean = 0.0, variance = options.noise_variance_initial_guess; 00686 00687 bool success; 00688 00689 if(options.use_gradient) 00690 { 00691 success = iterativeNoiseEstimationChi2(sul + center, src, 00692 gradient.upperLeft() + center, mean, variance, 00693 options.noise_estimation_quantile, windowRadius); 00694 } 00695 else 00696 { 00697 success = iterativeNoiseEstimationGauss(sul + center, src, 00698 gradient.upperLeft() + center, mean, variance, 00699 options.noise_estimation_quantile, windowRadius); 00700 } 00701 if (success) 00702 { 00703 result.push_back(ResultType(mean, variance)); 00704 } 00705 } 00706 } 00707 } 00708 00709 template <class Vector, class BackInsertable> 00710 void noiseVarianceClusteringImpl(Vector & noise, BackInsertable & result, 00711 unsigned int clusterCount, double quantile) 00712 { 00713 std::sort(noise.begin(), noise.end(), detail::SortNoiseByMean()); 00714 00715 ArrayVector<TinyVector<unsigned int, 2> > clusters; 00716 detail::noiseVarianceListMedianCut(noise, clusters, clusterCount); 00717 00718 std::sort(clusters.begin(), clusters.end(), detail::SortNoiseByMean()); 00719 00720 detail::noiseVarianceClusterAveraging(noise, clusters, result, quantile); 00721 } 00722 00723 template <class Functor, 00724 class SrcIterator, class SrcAccessor, 00725 class DestIterator, class DestAccessor> 00726 bool 00727 noiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00728 DestIterator dul, DestAccessor dest, 00729 NoiseNormalizationOptions const & options) 00730 { 00731 ArrayVector<TinyVector<double, 2> > noiseData; 00732 noiseVarianceEstimationImpl(sul, slr, src, noiseData, options); 00733 00734 if(noiseData.size() < 10) 00735 return false; 00736 00737 ArrayVector<TinyVector<double, 2> > noiseClusters; 00738 00739 noiseVarianceClusteringImpl(noiseData, noiseClusters, 00740 options.cluster_count, options.averaging_quantile); 00741 00742 transformImage(sul, slr, src, dul, dest, Functor(noiseClusters)); 00743 00744 return true; 00745 } 00746 00747 template <class SrcIterator, class SrcAccessor, 00748 class DestIterator, class DestAccessor> 00749 bool 00750 nonparametricNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00751 DestIterator dul, DestAccessor dest, 00752 NoiseNormalizationOptions const & options, 00753 VigraTrueType /* isScalar */) 00754 { 00755 typedef typename SrcAccessor::value_type SrcType; 00756 typedef typename DestAccessor::value_type DestType; 00757 return noiseNormalizationImpl<NonparametricNoiseNormalizationFunctor<SrcType, DestType> > 00758 (sul, slr, src, dul, dest, options); 00759 } 00760 00761 template <class SrcIterator, class SrcAccessor, 00762 class DestIterator, class DestAccessor> 00763 bool 00764 nonparametricNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00765 DestIterator dul, DestAccessor dest, 00766 NoiseNormalizationOptions const & options, 00767 VigraFalseType /* isScalar */) 00768 { 00769 int bands = src.size(sul); 00770 for(int b=0; b<bands; ++b) 00771 { 00772 VectorElementAccessor<SrcAccessor> sband(b, src); 00773 VectorElementAccessor<DestAccessor> dband(b, dest); 00774 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00775 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00776 00777 if(!noiseNormalizationImpl<NonparametricNoiseNormalizationFunctor<SrcType, DestType> > 00778 (sul, slr, sband, dul, dband, options)) 00779 return false; 00780 } 00781 return true; 00782 } 00783 00784 template <class SrcIterator, class SrcAccessor, 00785 class DestIterator, class DestAccessor> 00786 bool 00787 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00788 DestIterator dul, DestAccessor dest, 00789 NoiseNormalizationOptions const & options, 00790 VigraTrueType /* isScalar */) 00791 { 00792 typedef typename SrcAccessor::value_type SrcType; 00793 typedef typename DestAccessor::value_type DestType; 00794 return noiseNormalizationImpl<QuadraticNoiseNormalizationFunctor<SrcType, DestType> > 00795 (sul, slr, src, dul, dest, options); 00796 } 00797 00798 template <class SrcIterator, class SrcAccessor, 00799 class DestIterator, class DestAccessor> 00800 bool 00801 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00802 DestIterator dul, DestAccessor dest, 00803 NoiseNormalizationOptions const & options, 00804 VigraFalseType /* isScalar */) 00805 { 00806 int bands = src.size(sul); 00807 for(int b=0; b<bands; ++b) 00808 { 00809 VectorElementAccessor<SrcAccessor> sband(b, src); 00810 VectorElementAccessor<DestAccessor> dband(b, dest); 00811 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00812 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00813 00814 if(!noiseNormalizationImpl<QuadraticNoiseNormalizationFunctor<SrcType, DestType> > 00815 (sul, slr, sband, dul, dband, options)) 00816 return false; 00817 } 00818 return true; 00819 } 00820 00821 template <class SrcIterator, class SrcAccessor, 00822 class DestIterator, class DestAccessor> 00823 void 00824 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00825 DestIterator dul, DestAccessor dest, 00826 double a0, double a1, double a2, 00827 VigraTrueType /* isScalar */) 00828 { 00829 ArrayVector<TinyVector<double, 2> > noiseClusters; 00830 noiseClusters.push_back(TinyVector<double, 2>(0.0, a0)); 00831 noiseClusters.push_back(TinyVector<double, 2>(1.0, a0 + a1 + a2)); 00832 noiseClusters.push_back(TinyVector<double, 2>(2.0, a0 + 2.0*a1 + 4.0*a2)); 00833 transformImage(sul, slr, src, dul, dest, 00834 QuadraticNoiseNormalizationFunctor<typename SrcAccessor::value_type, 00835 typename DestAccessor::value_type>(noiseClusters)); 00836 } 00837 00838 template <class SrcIterator, class SrcAccessor, 00839 class DestIterator, class DestAccessor> 00840 void 00841 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00842 DestIterator dul, DestAccessor dest, 00843 double a0, double a1, double a2, 00844 VigraFalseType /* isScalar */) 00845 { 00846 int bands = src.size(sul); 00847 for(int b=0; b<bands; ++b) 00848 { 00849 VectorElementAccessor<SrcAccessor> sband(b, src); 00850 VectorElementAccessor<DestAccessor> dband(b, dest); 00851 quadraticNoiseNormalizationImpl(sul, slr, sband, dul, dband, a0, a1, a2, VigraTrueType()); 00852 } 00853 } 00854 00855 template <class SrcIterator, class SrcAccessor, 00856 class DestIterator, class DestAccessor> 00857 bool 00858 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00859 DestIterator dul, DestAccessor dest, 00860 NoiseNormalizationOptions const & options, 00861 VigraTrueType /* isScalar */) 00862 { 00863 typedef typename SrcAccessor::value_type SrcType; 00864 typedef typename DestAccessor::value_type DestType; 00865 return noiseNormalizationImpl<LinearNoiseNormalizationFunctor<SrcType, DestType> > 00866 (sul, slr, src, dul, dest, options); 00867 } 00868 00869 template <class SrcIterator, class SrcAccessor, 00870 class DestIterator, class DestAccessor> 00871 bool 00872 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00873 DestIterator dul, DestAccessor dest, 00874 NoiseNormalizationOptions const & options, 00875 VigraFalseType /* isScalar */) 00876 { 00877 int bands = src.size(sul); 00878 for(int b=0; b<bands; ++b) 00879 { 00880 VectorElementAccessor<SrcAccessor> sband(b, src); 00881 VectorElementAccessor<DestAccessor> dband(b, dest); 00882 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00883 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00884 00885 if(!noiseNormalizationImpl<LinearNoiseNormalizationFunctor<SrcType, DestType> > 00886 (sul, slr, sband, dul, dband, options)) 00887 return false; 00888 } 00889 return true; 00890 } 00891 00892 template <class SrcIterator, class SrcAccessor, 00893 class DestIterator, class DestAccessor> 00894 void 00895 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00896 DestIterator dul, DestAccessor dest, 00897 double a0, double a1, 00898 VigraTrueType /* isScalar */) 00899 { 00900 ArrayVector<TinyVector<double, 2> > noiseClusters; 00901 noiseClusters.push_back(TinyVector<double, 2>(0.0, a0)); 00902 noiseClusters.push_back(TinyVector<double, 2>(1.0, a0 + a1)); 00903 transformImage(sul, slr, src, dul, dest, 00904 LinearNoiseNormalizationFunctor<typename SrcAccessor::value_type, 00905 typename DestAccessor::value_type>(noiseClusters)); 00906 } 00907 00908 template <class SrcIterator, class SrcAccessor, 00909 class DestIterator, class DestAccessor> 00910 void 00911 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00912 DestIterator dul, DestAccessor dest, 00913 double a0, double a1, 00914 VigraFalseType /* isScalar */) 00915 { 00916 int bands = src.size(sul); 00917 for(int b=0; b<bands; ++b) 00918 { 00919 VectorElementAccessor<SrcAccessor> sband(b, src); 00920 VectorElementAccessor<DestAccessor> dband(b, dest); 00921 linearNoiseNormalizationImpl(sul, slr, sband, dul, dband, a0, a1, VigraTrueType()); 00922 } 00923 } 00924 00925 } // namespace detail 00926 00927 template <bool P> 00928 struct noiseVarianceEstimation_can_only_work_on_scalar_images 00929 : vigra::staticAssert::AssertBool<P> 00930 {}; 00931 00932 /** \addtogroup NoiseNormalization Noise Normalization 00933 Estimate noise with intensity-dependent variance and transform it into additive Gaussian noise. 00934 */ 00935 //@{ 00936 00937 /********************************************************/ 00938 /* */ 00939 /* noiseVarianceEstimation */ 00940 /* */ 00941 /********************************************************/ 00942 00943 /** \brief Determine the noise variance as a function of the image intensity. 00944 00945 This operator applies an algorithm described in 00946 00947 W. Förstner: <i>"Image Preprocessing for Feature Extraction in Digital Intensity, Color and Range Images"</i>, 00948 Proc. Summer School on Data Analysis and the Statistical Foundations of Geomatics, 00949 Lecture Notes in Earth Science, Berlin: Springer, 1999 00950 00951 in order to estimate the noise variance as a function of the image intensity in a robust way, 00952 i.e. so that intensity changes due to edges do not bias the estimate. The source value type 00953 (<TT>SrcAccessor::value_type</TT>) must be a scalar type which is convertible to <tt>double</tt>. 00954 The result is written into the \a result sequence, whose <tt>value_type</tt> must be constructible 00955 from two <tt>double</tt> values. The following options can be set via the \a options object 00956 (see \ref vigra::NoiseNormalizationOptions for details):<br><br> 00957 00958 <tt>useGradient</tt>, <tt>windowRadius</tt>, <tt>noiseEstimationQuantile</tt>, <tt>noiseVarianceInitialGuess</tt> 00959 00960 <b> Declarations:</b> 00961 00962 pass arguments explicitly: 00963 \code 00964 namespace vigra { 00965 template <class SrcIterator, class SrcAccessor, class BackInsertable> 00966 void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00967 BackInsertable & result, 00968 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 00969 } 00970 \endcode 00971 00972 use argument objects in conjunction with \ref ArgumentObjectFactories : 00973 \code 00974 namespace vigra { 00975 template <class SrcIterator, class SrcAccessor, class BackInsertable> 00976 void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00977 BackInsertable & result, 00978 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 00979 } 00980 \endcode 00981 00982 <b> Usage:</b> 00983 00984 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 00985 Namespace: vigra 00986 00987 \code 00988 vigra::BImage src(w,h); 00989 std::vector<vigra::TinyVector<double, 2> > result; 00990 00991 ... 00992 vigra::noiseVarianceEstimation(srcImageRange(src), result, 00993 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0)); 00994 00995 // print the intensity / variance pairs found 00996 for(int k=0; k<result.size(); ++k) 00997 std::cout << "Intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl; 00998 \endcode 00999 01000 <b> Required Interface:</b> 01001 01002 \code 01003 SrcIterator upperleft, lowerright; 01004 SrcAccessor src; 01005 01006 typedef SrcAccessor::value_type SrcType; 01007 typedef NumericTraits<SrcType>::isScalar isScalar; 01008 assert(isScalar::asBool == true); 01009 01010 double value = src(uperleft); 01011 01012 BackInsertable result; 01013 typedef BackInsertable::value_type ResultType; 01014 double intensity, variance; 01015 result.push_back(ResultType(intensity, variance)); 01016 \endcode 01017 */ 01018 doxygen_overloaded_function(template <...> void noiseVarianceEstimation) 01019 01020 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01021 inline 01022 void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01023 BackInsertable & result, 01024 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01025 { 01026 typedef typename BackInsertable::value_type ResultType; 01027 typedef typename SrcAccessor::value_type SrcType; 01028 typedef typename NumericTraits<SrcType>::isScalar isScalar; 01029 01030 VIGRA_STATIC_ASSERT(( 01031 noiseVarianceEstimation_can_only_work_on_scalar_images<(isScalar::asBool)>)); 01032 01033 detail::noiseVarianceEstimationImpl(sul, slr, src, result, options); 01034 } 01035 01036 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01037 inline 01038 void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01039 BackInsertable & result, 01040 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01041 { 01042 noiseVarianceEstimation(src.first, src.second, src.third, result, options); 01043 } 01044 01045 /********************************************************/ 01046 /* */ 01047 /* noiseVarianceClustering */ 01048 /* */ 01049 /********************************************************/ 01050 01051 /** \brief Determine the noise variance as a function of the image intensity and cluster the results. 01052 01053 This operator first calls \ref noiseVarianceEstimation() to obtain a sequence of intensity/variance pairs, 01054 which are then clustered using the median cut algorithm. Then the cluster centers (i.e. average variance vs. 01055 average intensity) are determined and returned in the \a result sequence. 01056 01057 In addition to the options valid for \ref noiseVarianceEstimation(), the following options can be set via 01058 the \a options object (see \ref vigra::NoiseNormalizationOptions for details):<br><br> 01059 01060 <tt>clusterCount</tt>, <tt>averagingQuantile</tt> 01061 01062 <b> Declarations:</b> 01063 01064 pass arguments explicitly: 01065 \code 01066 namespace vigra { 01067 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01068 void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01069 BackInsertable & result, 01070 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01071 } 01072 \endcode 01073 01074 use argument objects in conjunction with \ref ArgumentObjectFactories : 01075 \code 01076 namespace vigra { 01077 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01078 void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01079 BackInsertable & result, 01080 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01081 } 01082 \endcode 01083 01084 <b> Usage:</b> 01085 01086 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01087 Namespace: vigra 01088 01089 \code 01090 vigra::BImage src(w,h); 01091 std::vector<vigra::TinyVector<double, 2> > result; 01092 01093 ... 01094 vigra::noiseVarianceClustering(srcImageRange(src), result, 01095 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01096 clusterCount(15)); 01097 01098 // print the intensity / variance pairs representing the cluster centers 01099 for(int k=0; k<result.size(); ++k) 01100 std::cout << "Cluster: " << k << ", intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl; 01101 \endcode 01102 01103 <b> Required Interface:</b> 01104 01105 same as \ref noiseVarianceEstimation() 01106 */ 01107 doxygen_overloaded_function(template <...> void noiseVarianceClustering) 01108 01109 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01110 inline 01111 void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01112 BackInsertable & result, 01113 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01114 { 01115 ArrayVector<TinyVector<double, 2> > variance; 01116 noiseVarianceEstimation(sul, slr, src, variance, options); 01117 detail::noiseVarianceClusteringImpl(variance, result, options.cluster_count, options.averaging_quantile); 01118 } 01119 01120 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01121 inline 01122 void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01123 BackInsertable & result, 01124 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01125 { 01126 noiseVarianceClustering(src.first, src.second, src.third, result, options); 01127 } 01128 01129 /********************************************************/ 01130 /* */ 01131 /* nonparametricNoiseNormalization */ 01132 /* */ 01133 /********************************************************/ 01134 01135 /** \brief Noise normalization by means of an estimated non-parametric noise model. 01136 01137 The original image is assumed to be corrupted by noise whose variance depends on the intensity in an unknown way. 01138 The present functions first calls \ref noiseVarianceClustering() to obtain a sequence of intensity/variance pairs 01139 (cluster centers) which estimate this dependency. The cluster centers are connected into a piecewise linear 01140 function which is the inverted according to the formula derived in 01141 01142 W. Förstner: <i>"Image Preprocessing for Feature Extraction in Digital Intensity, Color and Range Images"</i>, 01143 Proc. Summer School on Data Analysis and the Statistical Foundations of Geomatics, 01144 Lecture Notes in Earth Science, Berlin: Springer, 1999 01145 01146 The inverted formula defines a pixel-wise intensity transformation whose application turns the original image 01147 into one that is corrupted by additive Gaussian noise with unit variance. Most subsequent algorithms will be able 01148 to handle this type of noise much better than the original noise. 01149 01150 RGB and other multiband images will be processed one band at a time. The function returns <tt>true</tt> on success. 01151 Noise normalization will fail if the original image does not contain sufficiently homogeneous regions that 01152 allow robust estimation of the noise variance. 01153 01154 The \a options object may use all options described in \ref vigra::NoiseNormalizationOptions. 01155 01156 <b> Declarations:</b> 01157 01158 pass arguments explicitly: 01159 \code 01160 namespace vigra { 01161 template <class SrcIterator, class SrcAccessor, 01162 class DestIterator, class DestAccessor> 01163 bool nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01164 DestIterator dul, DestAccessor dest, 01165 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01166 } 01167 \endcode 01168 01169 use argument objects in conjunction with \ref ArgumentObjectFactories : 01170 \code 01171 namespace vigra { 01172 template <class SrcIterator, class SrcAccessor, 01173 class DestIterator, class DestAccessor> 01174 bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01175 pair<DestIterator, DestAccessor> dest, 01176 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01177 } 01178 \endcode 01179 01180 <b> Usage:</b> 01181 01182 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01183 Namespace: vigra 01184 01185 \code 01186 vigra::BRGBImage src(w,h), dest(w, h); 01187 01188 ... 01189 vigra::nonparametricNoiseNormalization(srcImageRange(src), destImage(dest), 01190 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01191 clusterCount(15)); 01192 \endcode 01193 01194 <b> Required Interface:</b> 01195 01196 same as \ref noiseVarianceEstimation() 01197 */ 01198 doxygen_overloaded_function(template <...> bool nonparametricNoiseNormalization) 01199 01200 template <class SrcIterator, class SrcAccessor, 01201 class DestIterator, class DestAccessor> 01202 inline bool 01203 nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01204 DestIterator dul, DestAccessor dest, 01205 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01206 { 01207 typedef typename SrcAccessor::value_type SrcType; 01208 01209 return detail::nonparametricNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01210 typename NumericTraits<SrcType>::isScalar()); 01211 } 01212 01213 template <class SrcIterator, class SrcAccessor, 01214 class DestIterator, class DestAccessor> 01215 inline 01216 bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01217 pair<DestIterator, DestAccessor> dest, 01218 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01219 { 01220 return nonparametricNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01221 } 01222 01223 /********************************************************/ 01224 /* */ 01225 /* quadraticNoiseNormalization */ 01226 /* */ 01227 /********************************************************/ 01228 01229 /** \brief Noise normalization by means of an estimated quadratic noise model. 01230 01231 This function works in the same way as \ref nonparametricNoiseNormalization() with the exception of the 01232 model for the dependency between intensity and noise variance: it assumes that this dependency is a 01233 quadratic function rather than a piecewise linear function. If the quadratic model is applicable, it leads 01234 to a somewhat smoother transformation. 01235 01236 <b> Declarations:</b> 01237 01238 pass arguments explicitly: 01239 \code 01240 namespace vigra { 01241 template <class SrcIterator, class SrcAccessor, 01242 class DestIterator, class DestAccessor> 01243 bool quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01244 DestIterator dul, DestAccessor dest, 01245 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01246 } 01247 \endcode 01248 01249 use argument objects in conjunction with \ref ArgumentObjectFactories : 01250 \code 01251 namespace vigra { 01252 template <class SrcIterator, class SrcAccessor, 01253 class DestIterator, class DestAccessor> 01254 bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01255 pair<DestIterator, DestAccessor> dest, 01256 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01257 } 01258 \endcode 01259 01260 <b> Usage:</b> 01261 01262 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01263 Namespace: vigra 01264 01265 \code 01266 vigra::BRGBImage src(w,h), dest(w, h); 01267 01268 ... 01269 vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), 01270 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01271 clusterCount(15)); 01272 \endcode 01273 01274 <b> Required Interface:</b> 01275 01276 same as \ref noiseVarianceEstimation() 01277 */ 01278 doxygen_overloaded_function(template <...> bool quadraticNoiseNormalization) 01279 01280 template <class SrcIterator, class SrcAccessor, 01281 class DestIterator, class DestAccessor> 01282 inline bool 01283 quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01284 DestIterator dul, DestAccessor dest, 01285 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01286 { 01287 typedef typename SrcAccessor::value_type SrcType; 01288 01289 return detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01290 typename NumericTraits<SrcType>::isScalar()); 01291 } 01292 01293 template <class SrcIterator, class SrcAccessor, 01294 class DestIterator, class DestAccessor> 01295 inline 01296 bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01297 pair<DestIterator, DestAccessor> dest, 01298 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01299 { 01300 return quadraticNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01301 } 01302 01303 /********************************************************/ 01304 /* */ 01305 /* quadraticNoiseNormalization */ 01306 /* */ 01307 /********************************************************/ 01308 01309 /** \brief Noise normalization by means of a given quadratic noise model. 01310 01311 This function works similar to \ref nonparametricNoiseNormalization() with the exception that the 01312 functional dependency of the noise variance from the intensity is given (by a quadratic function) 01313 rather than estimated: 01314 01315 \code 01316 variance = a0 + a1 * intensity + a2 * sq(intensity) 01317 \endcode 01318 01319 <b> Declarations:</b> 01320 01321 pass arguments explicitly: 01322 \code 01323 namespace vigra { 01324 template <class SrcIterator, class SrcAccessor, 01325 class DestIterator, class DestAccessor> 01326 void quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01327 DestIterator dul, DestAccessor dest, 01328 double a0, double a1, double a2); 01329 } 01330 \endcode 01331 01332 use argument objects in conjunction with \ref ArgumentObjectFactories : 01333 \code 01334 namespace vigra { 01335 template <class SrcIterator, class SrcAccessor, 01336 class DestIterator, class DestAccessor> 01337 void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01338 pair<DestIterator, DestAccessor> dest, 01339 double a0, double a1, double a2); 01340 } 01341 \endcode 01342 01343 <b> Usage:</b> 01344 01345 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01346 Namespace: vigra 01347 01348 \code 01349 vigra::BRGBImage src(w,h), dest(w, h); 01350 01351 ... 01352 vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), 01353 100, 0.02, 1e-6); 01354 \endcode 01355 01356 <b> Required Interface:</b> 01357 01358 The source value type must be convertible to <tt>double</tt> or must be a vector whose elements 01359 are convertible to <tt>double</tt>. Likewise, the destination type must be assignable from <tt>double</tt> 01360 or a vector whose elements are assignable from <tt>double</tt>. 01361 */ 01362 doxygen_overloaded_function(template <...> void quadraticNoiseNormalization) 01363 01364 template <class SrcIterator, class SrcAccessor, 01365 class DestIterator, class DestAccessor> 01366 inline void 01367 quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01368 DestIterator dul, DestAccessor dest, 01369 double a0, double a1, double a2) 01370 { 01371 typedef typename SrcAccessor::value_type SrcType; 01372 01373 detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1, a2, 01374 typename NumericTraits<SrcType>::isScalar()); 01375 } 01376 01377 template <class SrcIterator, class SrcAccessor, 01378 class DestIterator, class DestAccessor> 01379 inline 01380 void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01381 pair<DestIterator, DestAccessor> dest, 01382 double a0, double a1, double a2) 01383 { 01384 quadraticNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1, a2); 01385 } 01386 01387 /********************************************************/ 01388 /* */ 01389 /* linearNoiseNormalization */ 01390 /* */ 01391 /********************************************************/ 01392 01393 /** \brief Noise normalization by means of an estimated linear noise model. 01394 01395 This function works in the same way as \ref nonparametricNoiseNormalization() with the exception of the 01396 model for the dependency between intensity and noise variance: it assumes that this dependency is a 01397 linear function rather than a piecewise linear function. If the linear model is applicable, it leads 01398 to a very simple transformation which is similar to the familiar gamma correction. 01399 01400 <b> Declarations:</b> 01401 01402 pass arguments explicitly: 01403 \code 01404 namespace vigra { 01405 template <class SrcIterator, class SrcAccessor, 01406 class DestIterator, class DestAccessor> 01407 bool linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01408 DestIterator dul, DestAccessor dest, 01409 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01410 } 01411 \endcode 01412 01413 use argument objects in conjunction with \ref ArgumentObjectFactories : 01414 \code 01415 namespace vigra { 01416 template <class SrcIterator, class SrcAccessor, 01417 class DestIterator, class DestAccessor> 01418 bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01419 pair<DestIterator, DestAccessor> dest, 01420 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01421 } 01422 \endcode 01423 01424 <b> Usage:</b> 01425 01426 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01427 Namespace: vigra 01428 01429 \code 01430 vigra::BRGBImage src(w,h), dest(w, h); 01431 01432 ... 01433 vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), 01434 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01435 clusterCount(15)); 01436 \endcode 01437 01438 <b> Required Interface:</b> 01439 01440 same as \ref noiseVarianceEstimation() 01441 */ 01442 doxygen_overloaded_function(template <...> bool linearNoiseNormalization) 01443 01444 template <class SrcIterator, class SrcAccessor, 01445 class DestIterator, class DestAccessor> 01446 inline bool 01447 linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01448 DestIterator dul, DestAccessor dest, 01449 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01450 { 01451 typedef typename SrcAccessor::value_type SrcType; 01452 01453 return detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01454 typename NumericTraits<SrcType>::isScalar()); 01455 } 01456 01457 template <class SrcIterator, class SrcAccessor, 01458 class DestIterator, class DestAccessor> 01459 inline 01460 bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01461 pair<DestIterator, DestAccessor> dest, 01462 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01463 { 01464 return linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01465 } 01466 01467 /********************************************************/ 01468 /* */ 01469 /* linearNoiseNormalization */ 01470 /* */ 01471 /********************************************************/ 01472 01473 /** \brief Noise normalization by means of a given linear noise model. 01474 01475 This function works similar to \ref nonparametricNoiseNormalization() with the exception that the 01476 functional dependency of the noise variance from the intensity is given (as a linear function) 01477 rather than estimated: 01478 01479 \code 01480 variance = a0 + a1 * intensity 01481 \endcode 01482 01483 <b> Declarations:</b> 01484 01485 pass arguments explicitly: 01486 \code 01487 namespace vigra { 01488 template <class SrcIterator, class SrcAccessor, 01489 class DestIterator, class DestAccessor> 01490 void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01491 DestIterator dul, DestAccessor dest, 01492 double a0, double a1); 01493 } 01494 \endcode 01495 01496 use argument objects in conjunction with \ref ArgumentObjectFactories : 01497 \code 01498 namespace vigra { 01499 template <class SrcIterator, class SrcAccessor, 01500 class DestIterator, class DestAccessor> 01501 void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01502 pair<DestIterator, DestAccessor> dest, 01503 double a0, double a1); 01504 } 01505 \endcode 01506 01507 <b> Usage:</b> 01508 01509 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01510 Namespace: vigra 01511 01512 \code 01513 vigra::BRGBImage src(w,h), dest(w, h); 01514 01515 ... 01516 vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), 01517 100, 0.02); 01518 \endcode 01519 01520 <b> Required Interface:</b> 01521 01522 The source value type must be convertible to <tt>double</tt> or must be a vector whose elements 01523 are convertible to <tt>double</tt>. Likewise, the destination type must be assignable from <tt>double</tt> 01524 or a vector whose elements are assignable from <tt>double</tt>. 01525 */ 01526 doxygen_overloaded_function(template <...> void linearNoiseNormalization) 01527 01528 template <class SrcIterator, class SrcAccessor, 01529 class DestIterator, class DestAccessor> 01530 inline 01531 void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01532 DestIterator dul, DestAccessor dest, 01533 double a0, double a1) 01534 { 01535 typedef typename SrcAccessor::value_type SrcType; 01536 01537 detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1, 01538 typename NumericTraits<SrcType>::isScalar()); 01539 } 01540 01541 template <class SrcIterator, class SrcAccessor, 01542 class DestIterator, class DestAccessor> 01543 inline 01544 void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01545 pair<DestIterator, DestAccessor> dest, 01546 double a0, double a1) 01547 { 01548 linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1); 01549 } 01550 01551 //@} 01552 01553 } // namespace vigra 01554 01555 #endif // VIGRA_NOISE_NORMALIZATION_HXX
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|