[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

vigra/noise_normalization.hxx VIGRA

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&ouml;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&ouml;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&ouml;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)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.7.0 (20 Apr 2010)