diff --git a/modules/img/alg/src/stat.cc b/modules/img/alg/src/stat.cc index 8f43ca399e47fb9e6dac913624bd2ab020c4ec9e..2a9427abbaea05fdc290d0642ed6918ea6b455dd 100644 --- a/modules/img/alg/src/stat.cc +++ b/modules/img/alg/src/stat.cc @@ -41,11 +41,27 @@ template <typename T, class D> void StatBase::VisitState(const ImageStateImpl<T,D>& isi) { sum_=0.0; - Real sum2=0.0,sum3=0.0,sum4=0.0; + mean_=0.0; + Real n = static_cast<Real>(isi.GetSize().GetVol()); - Vec3 sumcenter(0.0,0.0,0.0); + if(n==0.0){ + var_=0.0; + std_dev_=0.0; + min_=0.0; + max_=0.0; + maxpos_=Point(0,0,0), + minpos_=Point(0,0,0), + rms_=0.0; + skewness_=0.0; + kurtosis_=0.0; + center_of_mass_=Vec3(0.0,0.0,0.0); + return; + } - if(n==0.0) return; + Real sum2=0.0; + Vec3 sumcenter(0.0,0.0,0.0); + Real current_n=1.0; + Real m2=0.0,m3=0.0,m4=0.0; ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0)); ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0)); min_ = std::numeric_limits<Real>::max(); @@ -58,18 +74,23 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi) for(int j=0;j<he;++j) { for(int k=0;k<de;++k) { Real val=Val2Val<T,Real>(isi.Value(Index(i,j,k))); - Real oval=val; + Real delta = val - mean_; + Real delta_n = delta / current_n; + Real delta_n2 = delta_n * delta_n; + Real term = delta * delta_n * (current_n-1); + + mean_ += delta_n; + m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3; + m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2; + m2 += term; + ValIndex vi(val,Point(i,j,k)); minindex=std::min<ValIndex>(vi,minindex); maxindex=std::max<ValIndex>(vi,maxindex); sumcenter+=Vec3(i,j,k)*val; sum_+=val; - val*=oval; - sum2+=val; - val*=oval; - sum3+=val; - val*=oval; - sum4+=val; + sum2+=val*val; + current_n+=1; } } } @@ -77,16 +98,15 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi) max_=maxindex.first; minpos_=minindex.second+isi.GetExtent().GetStart(); maxpos_=maxindex.second+isi.GetExtent().GetStart(); - mean_ = sum_/n; - var_=sum2/n-mean_*mean_; + var_=m2/n; std_dev_=sqrt(var_); rms_=sqrt(sum2/n); - if(std_dev_>0.0){ - skewness_=sqrt(n)*(sum3-3.0*mean_*sum2+3.0*mean_*mean_*sum_ -n*mean_*mean_*mean_)/(std_dev_*std_dev_*std_dev_); - kurtosis_= n*(sum4-4.0*sum3*mean_+6.0*sum2*mean_*mean_-4.0*sum_*mean_*mean_*mean_+n*mean_*mean_*mean_*mean_)/(var_*var_)-3.0; - }else{ + if(m2<1e20){ skewness_=0.0; - kurtosis_=0.0; + kurtosis_= 0.0; + }else{ + skewness_=m3/sqrt(m2*m2*m2); + kurtosis_= (n*m4) / (m2*m2) - 3.0; } if(sum_!=0.0){ center_of_mass_=sumcenter/sum_+isi.GetExtent().GetStart().ToVec3(); @@ -98,46 +118,65 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi) void StatBase::VisitFunction(const Function& fnc) { sum_=0.0; - Real sum2=0.0,sum3=0.0,sum4=0.0; - ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0)); - ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0)); - Real n = (Real)(fnc.GetSize().GetVol()); - Vec3 sumcenter(0.0,0.0,0.0); + mean_=0.0; - if(n==0.0) return; + Real n = (Real)(fnc.GetSize().GetVol()); + if(n==0.0){ + var_=0.0; + std_dev_=0.0; + min_=0.0; + max_=0.0; + maxpos_=Point(0,0,0), + minpos_=Point(0,0,0), + rms_=0.0; + skewness_=0.0; + kurtosis_=0.0; + center_of_mass_=Vec3(0.0,0.0,0.0); + return; + } + Real sum2=0.0; + Vec3 sumcenter(0.0,0.0,0.0); + Real current_n=1.0; + Real m2=0.0,m3=0.0,m4=0.0; + ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0)); + ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0)); min_ = std::numeric_limits<Real>::max(); max_ = -std::numeric_limits<Real>::max(); for(ExtentIterator it(fnc.GetExtent());!it.AtEnd(); ++it) { Real val=fnc.GetReal(it); - Real oval=val; + Real delta = val - mean_; + Real delta_n = delta / current_n; + Real delta_n2 = delta_n * delta_n; + Real term = delta * delta_n * (current_n-1); + + mean_ += delta_n; + m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3; + m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2; + m2 += term; + ValIndex vi(val,it); minindex=std::min<ValIndex>(vi,minindex); maxindex=std::max<ValIndex>(vi,maxindex); sumcenter+=Point(it).ToVec3()*val; sum_+=val; - val*=oval; - sum2+=val; - val*=oval; - sum3+=val; - val*=oval; - sum4+=val; + sum2+=val*val; + current_n+=1; } min_=minindex.first; max_=maxindex.first; minpos_=minindex.second; maxpos_=maxindex.second; - mean_ = sum_/n; - var_=sum2/n-mean_*mean_; + var_=m2/n; std_dev_=sqrt(var_); rms_=sqrt(sum2/n); - if(std_dev_>0.0){ - skewness_=sqrt(n)*(sum3-3*mean_*sum2+3*mean_*mean_*sum_-n*mean_*mean_*mean_)/(std_dev_*std_dev_*std_dev_); - kurtosis_= n*(sum4-4*sum3*mean_+6*sum2*mean_*mean_-4*sum_*mean_*mean_*mean_+n*mean_*mean_*mean_*mean_)/(var_*var_)-3; - }else{ + if(m2<1e20){ skewness_=0.0; - kurtosis_=0.0; + kurtosis_= 0.0; + }else{ + skewness_=m3/sqrt(m2*m2*m2); + kurtosis_= (n*m4) / (m2*m2) - 3.0; } if(sum_!=0.0){ center_of_mass_=sumcenter/sum_; diff --git a/modules/img/alg/src/stat.hh b/modules/img/alg/src/stat.hh index 82757dc728e0fb8225055284eed646eeb7ac983f..450ffc3528de44dd2eb0df9d1d9cb7fbd2dc3de7 100644 --- a/modules/img/alg/src/stat.hh +++ b/modules/img/alg/src/stat.hh @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // This file is part of the OpenStructure project <www.openstructure.org> // -// Copyright (C) 2008-2011 by the OpenStructure authors +// Copyright (C) 2008-2010 by the OpenStructure authors // Copyright (C) 2003-2010 by the IPLT authors // // This library is free software; you can redistribute it and/or modify it under @@ -39,6 +39,11 @@ namespace ost { namespace img { namespace alg { Since this algorithm is implemented as a combined image stage visitor and algorithm, the main workhorse is this class StatBase, which will act as the parent class of the actual algorithm class, Stat + + Mean value, variance and standard deviation are calculated based on the one pass algorithm by Welford et al.: + B. P. Welford (1962)."Note on a method for calculating corrected sums of squares and products". Technometrics 4(3):419–420 + The calculation of the higher order central moments is implemented according to Terriberry: + Terriberry, Timothy B. (2007), Computing Higher-Order Moments Online (http://people.xiph.org/~tterribe/notes/homs.html) */ class DLLEXPORT_IMG_ALG StatBase