[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
vigra/noise_normalization.hxx | ![]() |
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 std::sort(noiseData.begin(), noiseData.end(), SortNoiseByMean()); 00738 00739 ArrayVector<TinyVector<double, 2> > noiseClusters; 00740 00741 noiseVarianceClusteringImpl(noiseData, noiseClusters, 00742 options.cluster_count, options.averaging_quantile); 00743 00744 transformImage(sul, slr, src, dul, dest, Functor(noiseClusters)); 00745 00746 return true; 00747 } 00748 00749 template <class SrcIterator, class SrcAccessor, 00750 class DestIterator, class DestAccessor> 00751 bool 00752 nonparametricNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00753 DestIterator dul, DestAccessor dest, 00754 NoiseNormalizationOptions const & options, 00755 VigraTrueType /* isScalar */) 00756 { 00757 typedef typename SrcAccessor::value_type SrcType; 00758 typedef typename DestAccessor::value_type DestType; 00759 return noiseNormalizationImpl<NonparametricNoiseNormalizationFunctor<SrcType, DestType> > 00760 (sul, slr, src, dul, dest, options); 00761 } 00762 00763 template <class SrcIterator, class SrcAccessor, 00764 class DestIterator, class DestAccessor> 00765 bool 00766 nonparametricNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00767 DestIterator dul, DestAccessor dest, 00768 NoiseNormalizationOptions const & options, 00769 VigraFalseType /* isScalar */) 00770 { 00771 int bands = src.size(sul); 00772 for(int b=0; b<bands; ++b) 00773 { 00774 VectorElementAccessor<SrcAccessor> sband(b, src); 00775 VectorElementAccessor<DestAccessor> dband(b, dest); 00776 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00777 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00778 00779 if(!noiseNormalizationImpl<NonparametricNoiseNormalizationFunctor<SrcType, DestType> > 00780 (sul, slr, sband, dul, dband, options)) 00781 return false; 00782 } 00783 return true; 00784 } 00785 00786 template <class SrcIterator, class SrcAccessor, 00787 class DestIterator, class DestAccessor> 00788 bool 00789 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00790 DestIterator dul, DestAccessor dest, 00791 NoiseNormalizationOptions const & options, 00792 VigraTrueType /* isScalar */) 00793 { 00794 typedef typename SrcAccessor::value_type SrcType; 00795 typedef typename DestAccessor::value_type DestType; 00796 return noiseNormalizationImpl<QuadraticNoiseNormalizationFunctor<SrcType, DestType> > 00797 (sul, slr, src, dul, dest, options); 00798 } 00799 00800 template <class SrcIterator, class SrcAccessor, 00801 class DestIterator, class DestAccessor> 00802 bool 00803 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00804 DestIterator dul, DestAccessor dest, 00805 NoiseNormalizationOptions const & options, 00806 VigraFalseType /* isScalar */) 00807 { 00808 int bands = src.size(sul); 00809 for(int b=0; b<bands; ++b) 00810 { 00811 VectorElementAccessor<SrcAccessor> sband(b, src); 00812 VectorElementAccessor<DestAccessor> dband(b, dest); 00813 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00814 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00815 00816 if(!noiseNormalizationImpl<QuadraticNoiseNormalizationFunctor<SrcType, DestType> > 00817 (sul, slr, sband, dul, dband, options)) 00818 return false; 00819 } 00820 return true; 00821 } 00822 00823 template <class SrcIterator, class SrcAccessor, 00824 class DestIterator, class DestAccessor> 00825 void 00826 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00827 DestIterator dul, DestAccessor dest, 00828 double a0, double a1, double a2, 00829 VigraTrueType /* isScalar */) 00830 { 00831 ArrayVector<TinyVector<double, 2> > noiseClusters; 00832 noiseClusters.push_back(TinyVector<double, 2>(0.0, a0)); 00833 noiseClusters.push_back(TinyVector<double, 2>(1.0, a0 + a1 + a2)); 00834 noiseClusters.push_back(TinyVector<double, 2>(2.0, a0 + 2.0*a1 + 4.0*a2)); 00835 transformImage(sul, slr, src, dul, dest, 00836 QuadraticNoiseNormalizationFunctor<typename SrcAccessor::value_type, 00837 typename DestAccessor::value_type>(noiseClusters)); 00838 } 00839 00840 template <class SrcIterator, class SrcAccessor, 00841 class DestIterator, class DestAccessor> 00842 void 00843 quadraticNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00844 DestIterator dul, DestAccessor dest, 00845 double a0, double a1, double a2, 00846 VigraFalseType /* isScalar */) 00847 { 00848 int bands = src.size(sul); 00849 for(int b=0; b<bands; ++b) 00850 { 00851 VectorElementAccessor<SrcAccessor> sband(b, src); 00852 VectorElementAccessor<DestAccessor> dband(b, dest); 00853 quadraticNoiseNormalizationImpl(sul, slr, sband, dul, dband, a0, a1, a2, VigraTrueType()); 00854 } 00855 } 00856 00857 template <class SrcIterator, class SrcAccessor, 00858 class DestIterator, class DestAccessor> 00859 bool 00860 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00861 DestIterator dul, DestAccessor dest, 00862 NoiseNormalizationOptions const & options, 00863 VigraTrueType /* isScalar */) 00864 { 00865 typedef typename SrcAccessor::value_type SrcType; 00866 typedef typename DestAccessor::value_type DestType; 00867 return noiseNormalizationImpl<LinearNoiseNormalizationFunctor<SrcType, DestType> > 00868 (sul, slr, src, dul, dest, options); 00869 } 00870 00871 template <class SrcIterator, class SrcAccessor, 00872 class DestIterator, class DestAccessor> 00873 bool 00874 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00875 DestIterator dul, DestAccessor dest, 00876 NoiseNormalizationOptions const & options, 00877 VigraFalseType /* isScalar */) 00878 { 00879 int bands = src.size(sul); 00880 for(int b=0; b<bands; ++b) 00881 { 00882 VectorElementAccessor<SrcAccessor> sband(b, src); 00883 VectorElementAccessor<DestAccessor> dband(b, dest); 00884 typedef typename VectorElementAccessor<SrcAccessor>::value_type SrcType; 00885 typedef typename VectorElementAccessor<DestAccessor>::value_type DestType; 00886 00887 if(!noiseNormalizationImpl<LinearNoiseNormalizationFunctor<SrcType, DestType> > 00888 (sul, slr, sband, dul, dband, options)) 00889 return false; 00890 } 00891 return true; 00892 } 00893 00894 template <class SrcIterator, class SrcAccessor, 00895 class DestIterator, class DestAccessor> 00896 void 00897 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00898 DestIterator dul, DestAccessor dest, 00899 double a0, double a1, 00900 VigraTrueType /* isScalar */) 00901 { 00902 ArrayVector<TinyVector<double, 2> > noiseClusters; 00903 noiseClusters.push_back(TinyVector<double, 2>(0.0, a0)); 00904 noiseClusters.push_back(TinyVector<double, 2>(1.0, a0 + a1)); 00905 transformImage(sul, slr, src, dul, dest, 00906 LinearNoiseNormalizationFunctor<typename SrcAccessor::value_type, 00907 typename DestAccessor::value_type>(noiseClusters)); 00908 } 00909 00910 template <class SrcIterator, class SrcAccessor, 00911 class DestIterator, class DestAccessor> 00912 void 00913 linearNoiseNormalizationImpl(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00914 DestIterator dul, DestAccessor dest, 00915 double a0, double a1, 00916 VigraFalseType /* isScalar */) 00917 { 00918 int bands = src.size(sul); 00919 for(int b=0; b<bands; ++b) 00920 { 00921 VectorElementAccessor<SrcAccessor> sband(b, src); 00922 VectorElementAccessor<DestAccessor> dband(b, dest); 00923 linearNoiseNormalizationImpl(sul, slr, sband, dul, dband, a0, a1, VigraTrueType()); 00924 } 00925 } 00926 00927 } // namespace detail 00928 00929 template <bool P> 00930 struct noiseVarianceEstimation_can_only_work_on_scalar_images 00931 : vigra::staticAssert::AssertBool<P> 00932 {}; 00933 00934 /** \addtogroup NoiseNormalization Noise Normalization 00935 Estimate noise with intensity-dependent variance and transform it into additive Gaussian noise. 00936 */ 00937 //@{ 00938 00939 /********************************************************/ 00940 /* */ 00941 /* noiseVarianceEstimation */ 00942 /* */ 00943 /********************************************************/ 00944 00945 /** \brief Determine the noise variance as a function of the image intensity. 00946 00947 This operator applies an algorithm described in 00948 00949 W. Förstner: <i>"Image Preprocessing for Feature Extraction in Digital Intensity, Color and Range Images"</i>, 00950 Proc. Summer School on Data Analysis and the Statistical Foundations of Geomatics, 00951 Lecture Notes in Earth Science, Berlin: Springer, 1999 00952 00953 in order to estimate the noise variance as a function of the image intensity in a robust way, 00954 i.e. so that intensity changes due to edges do not bias the estimate. The source value type 00955 (<TT>SrcAccessor::value_type</TT>) must be a scalar type which is convertible to <tt>double</tt>. 00956 The result is written into the \a result sequence, whose <tt>value_type</tt> must be constructible 00957 from two <tt>double</tt> values. The following options can be set via the \a options object 00958 (see \ref vigra::NoiseNormalizationOptions for details):<br><br> 00959 00960 <tt>useGradient</tt>, <tt>windowRadius</tt>, <tt>noiseEstimationQuantile</tt>, <tt>noiseVarianceInitialGuess</tt> 00961 00962 <b> Declarations:</b> 00963 00964 pass arguments explicitly: 00965 \code 00966 namespace vigra { 00967 template <class SrcIterator, class SrcAccessor, class BackInsertable> 00968 void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00969 BackInsertable & result, 00970 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 00971 } 00972 \endcode 00973 00974 use argument objects in conjunction with \ref ArgumentObjectFactories : 00975 \code 00976 namespace vigra { 00977 template <class SrcIterator, class SrcAccessor, class BackInsertable> 00978 void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00979 BackInsertable & result, 00980 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 00981 } 00982 \endcode 00983 00984 <b> Usage:</b> 00985 00986 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 00987 Namespace: vigra 00988 00989 \code 00990 vigra::BImage src(w,h); 00991 std::vector<vigra::TinyVector<double, 2> > result; 00992 00993 ... 00994 vigra::noiseVarianceEstimation(srcImageRange(src), result, 00995 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0)); 00996 00997 // print the intensity / variance pairs found 00998 for(int k=0; k<result.size(); ++k) 00999 std::cout << "Intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl; 01000 \endcode 01001 01002 <b> Required Interface:</b> 01003 01004 \code 01005 SrcIterator upperleft, lowerright; 01006 SrcAccessor src; 01007 01008 typedef SrcAccessor::value_type SrcType; 01009 typedef NumericTraits<SrcType>::isScalar isScalar; 01010 assert(isScalar::asBool == true); 01011 01012 double value = src(uperleft); 01013 01014 BackInsertable result; 01015 typedef BackInsertable::value_type ResultType; 01016 double intensity, variance; 01017 result.push_back(ResultType(intensity, variance)); 01018 \endcode 01019 */ 01020 doxygen_overloaded_function(template <...> void noiseVarianceEstimation) 01021 01022 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01023 inline 01024 void noiseVarianceEstimation(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01025 BackInsertable & result, 01026 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01027 { 01028 typedef typename BackInsertable::value_type ResultType; 01029 typedef typename SrcAccessor::value_type SrcType; 01030 typedef typename NumericTraits<SrcType>::isScalar isScalar; 01031 01032 VIGRA_STATIC_ASSERT(( 01033 noiseVarianceEstimation_can_only_work_on_scalar_images<(isScalar::asBool)>)); 01034 01035 detail::noiseVarianceEstimationImpl(sul, slr, src, result, options); 01036 } 01037 01038 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01039 inline 01040 void noiseVarianceEstimation(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01041 BackInsertable & result, 01042 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01043 { 01044 noiseVarianceEstimation(src.first, src.second, src.third, result, options); 01045 } 01046 01047 /********************************************************/ 01048 /* */ 01049 /* noiseVarianceClustering */ 01050 /* */ 01051 /********************************************************/ 01052 01053 /** \brief Determine the noise variance as a function of the image intensity and cluster the results. 01054 01055 This operator first calls \ref noiseVarianceEstimation() to obtain a sequence of intensity/variance pairs, 01056 which are then clustered using the median cut algorithm. Then the cluster centers (i.e. average variance vs. 01057 average intensity) are determined and returned in the \a result sequence. 01058 01059 In addition to the options valid for \ref noiseVarianceEstimation(), the following options can be set via 01060 the \a options object (see \ref vigra::NoiseNormalizationOptions for details):<br><br> 01061 01062 <tt>clusterCount</tt>, <tt>averagingQuantile</tt> 01063 01064 <b> Declarations:</b> 01065 01066 pass arguments explicitly: 01067 \code 01068 namespace vigra { 01069 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01070 void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01071 BackInsertable & result, 01072 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01073 } 01074 \endcode 01075 01076 use argument objects in conjunction with \ref ArgumentObjectFactories : 01077 \code 01078 namespace vigra { 01079 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01080 void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01081 BackInsertable & result, 01082 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01083 } 01084 \endcode 01085 01086 <b> Usage:</b> 01087 01088 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01089 Namespace: vigra 01090 01091 \code 01092 vigra::BImage src(w,h); 01093 std::vector<vigra::TinyVector<double, 2> > result; 01094 01095 ... 01096 vigra::noiseVarianceClustering(srcImageRange(src), result, 01097 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01098 clusterCount(15)); 01099 01100 // print the intensity / variance pairs representing the cluster centers 01101 for(int k=0; k<result.size(); ++k) 01102 std::cout << "Cluster: " << k << ", intensity: " << result[k][0] << ", estimated variance: " << result[k][1] << std::endl; 01103 \endcode 01104 01105 <b> Required Interface:</b> 01106 01107 same as \ref noiseVarianceEstimation() 01108 */ 01109 doxygen_overloaded_function(template <...> void noiseVarianceClustering) 01110 01111 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01112 inline 01113 void noiseVarianceClustering(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01114 BackInsertable & result, 01115 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01116 { 01117 ArrayVector<TinyVector<double, 2> > variance; 01118 noiseVarianceEstimation(sul, slr, src, variance, options); 01119 detail::noiseVarianceClusteringImpl(variance, result, options.cluster_count, options.averaging_quantile); 01120 } 01121 01122 template <class SrcIterator, class SrcAccessor, class BackInsertable> 01123 inline 01124 void noiseVarianceClustering(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01125 BackInsertable & result, 01126 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01127 { 01128 noiseVarianceClustering(src.first, src.second, src.third, result, options); 01129 } 01130 01131 /********************************************************/ 01132 /* */ 01133 /* nonparametricNoiseNormalization */ 01134 /* */ 01135 /********************************************************/ 01136 01137 /** \brief Noise normalization by means of an estimated non-parametric noise model. 01138 01139 The original image is assumed to be corrupted by noise whose variance depends on the intensity in an unknown way. 01140 The present functions first calls \ref noiseVarianceClustering() to obtain a sequence of intensity/variance pairs 01141 (cluster centers) which estimate this dependency. The cluster centers are connected into a piecewise linear 01142 function which is the inverted according to the formula derived in 01143 01144 W. Förstner: <i>"Image Preprocessing for Feature Extraction in Digital Intensity, Color and Range Images"</i>, 01145 Proc. Summer School on Data Analysis and the Statistical Foundations of Geomatics, 01146 Lecture Notes in Earth Science, Berlin: Springer, 1999 01147 01148 The inverted formula defines a pixel-wise intensity transformation whose application turns the original image 01149 into one that is corrupted by additive Gaussian noise with unit variance. Most subsequent algorithms will be able 01150 to handle this type of noise much better than the original noise. 01151 01152 RGB and other multiband images will be processed one band at a time. The function returns <tt>true</tt> on success. 01153 Noise normalization will fail if the original image does not contain sufficiently homogeneous regions that 01154 allow robust estimation of the noise variance. 01155 01156 The \a options object may use all options described in \ref vigra::NoiseNormalizationOptions. 01157 01158 <b> Declarations:</b> 01159 01160 pass arguments explicitly: 01161 \code 01162 namespace vigra { 01163 template <class SrcIterator, class SrcAccessor, 01164 class DestIterator, class DestAccessor> 01165 bool nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01166 DestIterator dul, DestAccessor dest, 01167 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01168 } 01169 \endcode 01170 01171 use argument objects in conjunction with \ref ArgumentObjectFactories : 01172 \code 01173 namespace vigra { 01174 template <class SrcIterator, class SrcAccessor, 01175 class DestIterator, class DestAccessor> 01176 bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01177 pair<DestIterator, DestAccessor> dest, 01178 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01179 } 01180 \endcode 01181 01182 <b> Usage:</b> 01183 01184 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01185 Namespace: vigra 01186 01187 \code 01188 vigra::BRGBImage src(w,h), dest(w, h); 01189 01190 ... 01191 vigra::nonparametricNoiseNormalization(srcImageRange(src), destImage(dest), 01192 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01193 clusterCount(15)); 01194 \endcode 01195 01196 <b> Required Interface:</b> 01197 01198 same as \ref noiseVarianceEstimation() 01199 */ 01200 doxygen_overloaded_function(template <...> bool nonparametricNoiseNormalization) 01201 01202 template <class SrcIterator, class SrcAccessor, 01203 class DestIterator, class DestAccessor> 01204 inline bool 01205 nonparametricNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01206 DestIterator dul, DestAccessor dest, 01207 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01208 { 01209 typedef typename SrcAccessor::value_type SrcType; 01210 01211 return detail::nonparametricNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01212 typename NumericTraits<SrcType>::isScalar()); 01213 } 01214 01215 template <class SrcIterator, class SrcAccessor, 01216 class DestIterator, class DestAccessor> 01217 inline 01218 bool nonparametricNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01219 pair<DestIterator, DestAccessor> dest, 01220 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01221 { 01222 return nonparametricNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01223 } 01224 01225 /********************************************************/ 01226 /* */ 01227 /* quadraticNoiseNormalization */ 01228 /* */ 01229 /********************************************************/ 01230 01231 /** \brief Noise normalization by means of an estimated quadratic noise model. 01232 01233 This function works in the same way as \ref nonparametricNoiseNormalization() with the exception of the 01234 model for the dependency between intensity and noise variance: it assumes that this dependency is a 01235 quadratic function rather than a piecewise linear function. If the quadratic model is applicable, it leads 01236 to a somewhat smoother transformation. 01237 01238 <b> Declarations:</b> 01239 01240 pass arguments explicitly: 01241 \code 01242 namespace vigra { 01243 template <class SrcIterator, class SrcAccessor, 01244 class DestIterator, class DestAccessor> 01245 bool quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01246 DestIterator dul, DestAccessor dest, 01247 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01248 } 01249 \endcode 01250 01251 use argument objects in conjunction with \ref ArgumentObjectFactories : 01252 \code 01253 namespace vigra { 01254 template <class SrcIterator, class SrcAccessor, 01255 class DestIterator, class DestAccessor> 01256 bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01257 pair<DestIterator, DestAccessor> dest, 01258 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01259 } 01260 \endcode 01261 01262 <b> Usage:</b> 01263 01264 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01265 Namespace: vigra 01266 01267 \code 01268 vigra::BRGBImage src(w,h), dest(w, h); 01269 01270 ... 01271 vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), 01272 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01273 clusterCount(15)); 01274 \endcode 01275 01276 <b> Required Interface:</b> 01277 01278 same as \ref noiseVarianceEstimation() 01279 */ 01280 doxygen_overloaded_function(template <...> bool quadraticNoiseNormalization) 01281 01282 template <class SrcIterator, class SrcAccessor, 01283 class DestIterator, class DestAccessor> 01284 inline bool 01285 quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01286 DestIterator dul, DestAccessor dest, 01287 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01288 { 01289 typedef typename SrcAccessor::value_type SrcType; 01290 01291 return detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01292 typename NumericTraits<SrcType>::isScalar()); 01293 } 01294 01295 template <class SrcIterator, class SrcAccessor, 01296 class DestIterator, class DestAccessor> 01297 inline 01298 bool quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01299 pair<DestIterator, DestAccessor> dest, 01300 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01301 { 01302 return quadraticNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01303 } 01304 01305 /********************************************************/ 01306 /* */ 01307 /* quadraticNoiseNormalization */ 01308 /* */ 01309 /********************************************************/ 01310 01311 /** \brief Noise normalization by means of a given quadratic noise model. 01312 01313 This function works similar to \ref nonparametricNoiseNormalization() with the exception that the 01314 functional dependency of the noise variance from the intensity is given (by a quadratic function) 01315 rather than estimated: 01316 01317 \code 01318 variance = a0 + a1 * intensity + a2 * sq(intensity) 01319 \endcode 01320 01321 <b> Declarations:</b> 01322 01323 pass arguments explicitly: 01324 \code 01325 namespace vigra { 01326 template <class SrcIterator, class SrcAccessor, 01327 class DestIterator, class DestAccessor> 01328 void quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01329 DestIterator dul, DestAccessor dest, 01330 double a0, double a1, double a2); 01331 } 01332 \endcode 01333 01334 use argument objects in conjunction with \ref ArgumentObjectFactories : 01335 \code 01336 namespace vigra { 01337 template <class SrcIterator, class SrcAccessor, 01338 class DestIterator, class DestAccessor> 01339 void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01340 pair<DestIterator, DestAccessor> dest, 01341 double a0, double a1, double a2); 01342 } 01343 \endcode 01344 01345 <b> Usage:</b> 01346 01347 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01348 Namespace: vigra 01349 01350 \code 01351 vigra::BRGBImage src(w,h), dest(w, h); 01352 01353 ... 01354 vigra::quadraticNoiseNormalization(srcImageRange(src), destImage(dest), 01355 100, 0.02, 1e-6); 01356 \endcode 01357 01358 <b> Required Interface:</b> 01359 01360 The source value type must be convertible to <tt>double</tt> or must be a vector whose elements 01361 are convertible to <tt>double</tt>. Likewise, the destination type must be assignable from <tt>double</tt> 01362 or a vector whose elements are assignable from <tt>double</tt>. 01363 */ 01364 doxygen_overloaded_function(template <...> void quadraticNoiseNormalization) 01365 01366 template <class SrcIterator, class SrcAccessor, 01367 class DestIterator, class DestAccessor> 01368 inline void 01369 quadraticNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01370 DestIterator dul, DestAccessor dest, 01371 double a0, double a1, double a2) 01372 { 01373 typedef typename SrcAccessor::value_type SrcType; 01374 01375 detail::quadraticNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1, a2, 01376 typename NumericTraits<SrcType>::isScalar()); 01377 } 01378 01379 template <class SrcIterator, class SrcAccessor, 01380 class DestIterator, class DestAccessor> 01381 inline 01382 void quadraticNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01383 pair<DestIterator, DestAccessor> dest, 01384 double a0, double a1, double a2) 01385 { 01386 quadraticNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1, a2); 01387 } 01388 01389 /********************************************************/ 01390 /* */ 01391 /* linearNoiseNormalization */ 01392 /* */ 01393 /********************************************************/ 01394 01395 /** \brief Noise normalization by means of an estimated linear noise model. 01396 01397 This function works in the same way as \ref nonparametricNoiseNormalization() with the exception of the 01398 model for the dependency between intensity and noise variance: it assumes that this dependency is a 01399 linear function rather than a piecewise linear function. If the linear model is applicable, it leads 01400 to a very simple transformation which is similar to the familiar gamma correction. 01401 01402 <b> Declarations:</b> 01403 01404 pass arguments explicitly: 01405 \code 01406 namespace vigra { 01407 template <class SrcIterator, class SrcAccessor, 01408 class DestIterator, class DestAccessor> 01409 bool linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01410 DestIterator dul, DestAccessor dest, 01411 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01412 } 01413 \endcode 01414 01415 use argument objects in conjunction with \ref ArgumentObjectFactories : 01416 \code 01417 namespace vigra { 01418 template <class SrcIterator, class SrcAccessor, 01419 class DestIterator, class DestAccessor> 01420 bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01421 pair<DestIterator, DestAccessor> dest, 01422 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()); 01423 } 01424 \endcode 01425 01426 <b> Usage:</b> 01427 01428 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01429 Namespace: vigra 01430 01431 \code 01432 vigra::BRGBImage src(w,h), dest(w, h); 01433 01434 ... 01435 vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), 01436 vigra::NoiseNormalizationOptions().windowRadius(9).noiseVarianceInitialGuess(25.0). 01437 clusterCount(15)); 01438 \endcode 01439 01440 <b> Required Interface:</b> 01441 01442 same as \ref noiseVarianceEstimation() 01443 */ 01444 doxygen_overloaded_function(template <...> bool linearNoiseNormalization) 01445 01446 template <class SrcIterator, class SrcAccessor, 01447 class DestIterator, class DestAccessor> 01448 inline bool 01449 linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01450 DestIterator dul, DestAccessor dest, 01451 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01452 { 01453 typedef typename SrcAccessor::value_type SrcType; 01454 01455 return detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, options, 01456 typename NumericTraits<SrcType>::isScalar()); 01457 } 01458 01459 template <class SrcIterator, class SrcAccessor, 01460 class DestIterator, class DestAccessor> 01461 inline 01462 bool linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01463 pair<DestIterator, DestAccessor> dest, 01464 NoiseNormalizationOptions const & options = NoiseNormalizationOptions()) 01465 { 01466 return linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, options); 01467 } 01468 01469 /********************************************************/ 01470 /* */ 01471 /* linearNoiseNormalization */ 01472 /* */ 01473 /********************************************************/ 01474 01475 /** \brief Noise normalization by means of a given linear noise model. 01476 01477 This function works similar to \ref nonparametricNoiseNormalization() with the exception that the 01478 functional dependency of the noise variance from the intensity is given (as a linear function) 01479 rather than estimated: 01480 01481 \code 01482 variance = a0 + a1 * intensity 01483 \endcode 01484 01485 <b> Declarations:</b> 01486 01487 pass arguments explicitly: 01488 \code 01489 namespace vigra { 01490 template <class SrcIterator, class SrcAccessor, 01491 class DestIterator, class DestAccessor> 01492 void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01493 DestIterator dul, DestAccessor dest, 01494 double a0, double a1); 01495 } 01496 \endcode 01497 01498 use argument objects in conjunction with \ref ArgumentObjectFactories : 01499 \code 01500 namespace vigra { 01501 template <class SrcIterator, class SrcAccessor, 01502 class DestIterator, class DestAccessor> 01503 void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01504 pair<DestIterator, DestAccessor> dest, 01505 double a0, double a1); 01506 } 01507 \endcode 01508 01509 <b> Usage:</b> 01510 01511 <b>\#include</b> <<a href="noise__normalization_8hxx-source.html">vigra/noise_normalization.hxx</a>><br> 01512 Namespace: vigra 01513 01514 \code 01515 vigra::BRGBImage src(w,h), dest(w, h); 01516 01517 ... 01518 vigra::linearNoiseNormalization(srcImageRange(src), destImage(dest), 01519 100, 0.02); 01520 \endcode 01521 01522 <b> Required Interface:</b> 01523 01524 The source value type must be convertible to <tt>double</tt> or must be a vector whose elements 01525 are convertible to <tt>double</tt>. Likewise, the destination type must be assignable from <tt>double</tt> 01526 or a vector whose elements are assignable from <tt>double</tt>. 01527 */ 01528 doxygen_overloaded_function(template <...> void linearNoiseNormalization) 01529 01530 template <class SrcIterator, class SrcAccessor, 01531 class DestIterator, class DestAccessor> 01532 inline 01533 void linearNoiseNormalization(SrcIterator sul, SrcIterator slr, SrcAccessor src, 01534 DestIterator dul, DestAccessor dest, 01535 double a0, double a1) 01536 { 01537 typedef typename SrcAccessor::value_type SrcType; 01538 01539 detail::linearNoiseNormalizationImpl(sul, slr, src, dul, dest, a0, a1, 01540 typename NumericTraits<SrcType>::isScalar()); 01541 } 01542 01543 template <class SrcIterator, class SrcAccessor, 01544 class DestIterator, class DestAccessor> 01545 inline 01546 void linearNoiseNormalization(triple<SrcIterator, SrcIterator, SrcAccessor> src, 01547 pair<DestIterator, DestAccessor> dest, 01548 double a0, double a1) 01549 { 01550 linearNoiseNormalization(src.first, src.second, src.third, dest.first, dest.second, a0, a1); 01551 } 01552 01553 //@} 01554 01555 } // namespace vigra 01556 01557 #endif // VIGRA_NOISE_NORMALIZATION_HXX
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|