00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00020 #include<ImLib3D/ImageStats.hpp>
00021 #include<ImLib3D/TestPatterns.hpp>
00022 #include<ImLib3D/Arithmetic.hpp>
00023 #include<ImLib3D/ConvenienceProcessors.hpp>
00024
00025 namespace IP3D
00026 {
00027 void
00028 RobustAverageAndVariance(const Image3Df &src,double &average,double &variance)
00029 {
00030
00031 IP3D::Median(src,average);
00032
00033
00034 Image3Df diff=src;
00035 diff-=average;
00036 IP3D::Abs(diff,diff);
00037 IP3D::Median(diff,variance);
00038 variance=1.4826*variance;
00039
00040 variance=variance*variance;
00041 }
00042 }
00043
00044 void
00045 ProbabilityDistribution::SetRange(const vector<Value> &samples)
00046 {
00047 vmin=*min_element(samples.begin(),samples.end());
00048 vmax=*max_element(samples.begin(),samples.end());
00049 double grow=(vmax-vmin)*.0001;
00050 if(vmax==vmin){mprintf("ProbabilityDistribution::SetRange: WARNING vmax==vmin==%f\n",vmax);grow=.0001;}
00051 vmin-=grow;
00052 vmax+=grow;
00053 }
00054
00055
00056
00057
00058
00059
00060 ProbabilityDistribution::OtsuClass
00061 ProbabilityDistribution::ComputeClassStats(vector<OtsuClass> &classes,int classNum,vector<int> &indexes)
00062 {
00063 double moment1=0,moment2=0,moment0=0;
00064 int j0=(classNum>0 ? indexes[classNum-1] : 0 );
00065 int j1=(classNum<(int)indexes.size() ? indexes[classNum ] : (int)bins.size());
00066
00067
00068
00069
00070 OtsuClass &old=classes[classNum];
00071
00072 if(old.id==classNum && old.j0==j0 && old.j1==j1)
00073 {
00074 moment0=old.moment0;
00075 moment1=old.moment1;
00076 moment2=old.moment2;
00077 }
00078 else
00079 if(old.id==classNum && old.j0==j0-1 && old.j1==j1)
00080 {
00081 int j=j0-1;
00082 double v=vmin+j*((vmax-vmin)/bins.size());
00083 moment0=old.moment0 - bins[j];
00084 moment1=old.moment1 - v* bins[j];
00085 moment2=old.moment2 - v*v*bins[j];
00086 }
00087 else
00088 if(old.id==classNum && old.j0==j0 && old.j1==j1-1)
00089 {
00090 int j=j1-1;
00091 double v=vmin+j*((vmax-vmin)/bins.size());
00092 moment0=old.moment0 + bins[j];
00093 moment1=old.moment1 + v* bins[j];
00094 moment2=old.moment2 + v*v*bins[j];
00095 }
00096 else
00097 {
00098
00099
00100
00101
00102
00103
00104 for(int j=j0;j<j1;j++)
00105 {
00106 double v=vmin+j*((vmax-vmin)/bins.size());
00107 moment0+= bins[j];
00108 moment1+=v* bins[j];
00109 moment2+=v*v*bins[j];
00110 }
00111 }
00112
00113
00114
00115 old.id=classNum;
00116 old.j0=j0;
00117 old.j1=j1;
00118 old.moment0=moment0;
00119 old.moment1=moment1;
00120 old.moment2=moment2;
00121 OtsuClass res;
00122 res.id=classNum;
00123
00124 res.id=classNum;
00125 res.moment0=moment0;
00126 res.moment1=moment1;
00127 res.moment2=moment2;
00128 res.j0=j0;
00129 res.j1=j1;
00130 return res;
00131 }
00132
00133
00134 void
00135 ProbabilityDistribution::OtsuThreshholds(int nbClasses,vector<double> &res)
00136 {
00137 uint i;
00138 res.assign(nbClasses-1,0);
00139 vector<double> thresholds;
00140 vector<int> indexes;
00141 indexes.assign(nbClasses-1,0);
00142 thresholds.assign(nbClasses-1,0);
00143 double minS2=-1;
00144 Periodic talk(.5);
00145 vector<OtsuClass> classes;
00146 OtsuClass dud;
00147 classes.assign(nbClasses,dud);
00148
00149
00150 while(NextIndex(indexes))
00151 {
00152
00153 for(i=1;i<indexes.size();i++){if(indexes[i]<=indexes[i-1]) break;}
00154 if(i<indexes.size()){continue;}
00155
00156 int dotalk=talk();
00157
00158 for(i=0;i<indexes.size();i++){thresholds[i]=vmin+indexes[i]*((vmax-vmin)/bins.size());}
00159 if(dotalk)
00160 {
00161 mprintf("considering thresholds:");
00162 for(i=0;i<indexes.size();i++){mprintf("%d:%f ",i,thresholds[i]);}
00163 mprintf("\n");
00164 }
00165
00166
00167 double s2=0;
00168 for(int classNum=0;classNum<nbClasses;classNum++)
00169 {
00170
00171 OtsuClass c=ComputeClassStats(classes,classNum,indexes);
00172
00173 if(c.moment0==0){s2=2*minS2+1;break;}
00174
00175 double classProb=c.moment0;
00176 double average =c.moment1/classProb;
00177
00178 double variance =c.moment2/classProb-average*average;
00179
00180
00181 s2+=variance*classProb;
00182 if(dotalk)mprintf("class %d: from %f to %f: classProb:%f average:%f variance:%f contr:%f\n",
00183 classNum,vmin+c.j0*((vmax-vmin)/bins.size()),vmin+c.j1*((vmax-vmin)/bins.size()),
00184 classProb,average,variance,variance*classProb);
00185 }
00186
00187 if(s2<minS2 || minS2<0)
00188 {
00189 minS2=s2;
00190 res=thresholds;
00191 }
00192 if(dotalk)
00193 {
00194 mprintf("TOT S2:%f BEST:%f : ",s2,minS2);
00195 for(uint i=0;i<res.size();i++){mprintf("%d:%f ",i,res[i]);}
00196 mprintf("\n");
00197 }
00198 }
00199 mprintf("OtsuThresholds result:");
00200 for(i=0;i<res.size();i++){mprintf("%d:%f ",i,res[i]);}
00201 mprintf("\n");
00202 }
00203 void
00204 ProbabilityDistribution::ShowWithGnuPlot(const string &label) const
00205 {
00206 vector<double> values(bins.size());
00207 for(uint i=0;i<bins.size();i++)
00208 {
00209 values[i]=(i*(vmax-vmin)/bins.size())+vmin;
00210 }
00211 GnuPlot(values,bins,label,"histogram");
00212 }
00213
00214 void
00215 ProbabilityDistribution::SetWithSamples(const vector<Value> &samples,int nbBins)
00216 {
00217 bins.assign(nbBins,0);
00218 SetRange(samples);
00219 accumulatedSegmentCount = 0;
00220
00221 AccumulateWithSamples(samples);
00222 }
00223
00224 void
00225 ProbabilityDistribution::AccumulateWithSamples(const vector<Value> &samples)
00226 {
00227
00228 for(uint tt=0;tt<bins.size();tt++)
00229 {
00230 bins[tt]*=accumulatedSegmentCount;
00231 }
00232
00233 for(uint i=0;i<samples.size();i++)
00234 {
00235 bins[BinNum(samples[i])]+=1.0;
00236 accumulatedSegmentCount++;
00237 }
00238 for(uint tt=0;tt<bins.size();tt++)
00239 {
00240 bins[tt]/=accumulatedSegmentCount;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249 }
00250
00252 void
00253 ProbabilityDistribution::SetWithSignal(const vector<Value> &samples,int nbBins)
00254 {
00255 bins.assign(nbBins,0);
00256 SetRange(samples);
00257 accumulatedSegmentCount = 0;
00258
00259 AccumulateWithSignal(samples);
00260 }
00261
00262 void
00263 ProbabilityDistribution::AccumulateWithSignal(const vector<Value> &samples)
00264 {
00265
00266 for(uint tt=0;tt<bins.size();tt++)
00267 {
00268 bins[tt]*=accumulatedSegmentCount;
00269 }
00270
00271
00272 for(uint i=0;i<samples.size()-1;i++)
00273 {
00274 Value v0=samples[i];
00275 Value v1=samples[i+1];
00276 Value t=max(v0,v1);
00277 v0=min(v0,v1);
00278 v1=t;
00279
00280 if( BinNum(v0)==BinNum(v1))
00281 {
00282 bins[BinNum(v0)]+=1.0;
00283 }
00284 else
00285 {
00286
00287 double j0=BinPos(v0);
00288 double j1=BinPos(v1);
00289
00290 double dweight=1.0/(j1-j0);
00291 int cj0=(int)ceil(j0);
00292 int fj1=(int)floor(j1);
00293
00294 double dy;
00295
00296 dy=cj0-j0;
00297 bins[(int)j0]+=dy*dweight;
00298
00299 for(int j=cj0;j<fj1;j++)
00300 {
00301 bins[j]+=dweight;
00302 }
00303
00304 dy=j1-fj1;
00305 bins[(int)j1]+=dy*dweight;
00306 }
00307 accumulatedSegmentCount++;
00308 }
00309
00310 for(uint tt=0;tt<bins.size();tt++)
00311 {
00312 bins[tt]/=accumulatedSegmentCount;
00313 }
00314
00315 double totproba=0;
00316 for(uint tt=0;tt<bins.size();tt++)
00317 {
00318 totproba+=bins[tt];
00319 }
00320 mprintf("totproba:%f bins:%d\n",totproba,bins.size());
00321 }
00322
00324 void
00325 ProbabilityDistribution::SetWithImage3D(const Image3Df &image,SetWithImage3DType type,int nbBins)
00326 {
00327 if(type==LINEAR3){SetWithImage3Dlinear3(image,nbBins);return;}
00328 vector<float> samples;
00329 samples.reserve(image.GetNVoxels());
00330 for(Image3Df::const_iteratorFastMasked p=image.begin();p!=image.end();++p)
00331 {
00332 samples.push_back(*p);
00333 }
00334 if(type==LINEAR1){SetWithSignal(samples,nbBins);return;}
00335 if(type==SAMPLES){SetWithSamples(samples,nbBins);return;}
00336 ThrowError("ProbabilityDistribution::SetWithImage3D unknown type:%d\n",type);
00337 }
00338
00340 void
00341 ProbabilityDistribution::AccumulateWithImage3D(const Image3Df &image,SetWithImage3DType type)
00342 {
00343 if(type==LINEAR3){AccumulateImage3Dlinear3(image);return;}
00344 vector<float> samples;
00345 samples.reserve(image.GetNVoxels());
00346 for(Image3Df::const_iteratorFastMasked p=image.begin();p!=image.end();++p)
00347 {
00348 samples.push_back(*p);
00349 }
00350 if(type==LINEAR1){AccumulateWithSignal(samples);return;}
00351 if(type==SAMPLES){AccumulateWithSamples(samples);return;}
00352 ThrowError("ProbabilityDistribution::SetWithImage3D unknown type:%d\n",type);
00353 }
00354
00355
00357 void
00358 ProbabilityDistribution::SetWithImage3Dlinear3(const Image3Df &src,int nbBins)
00359 {
00360 Vect3Di srcSize=src.SizeV();
00361 IP3D::FindMinMax(src,vmin,vmax);
00362 double grow=(vmax-vmin)*.0001;
00363 if(vmax==vmin){mprintf("ProbabilityDistribution::SetWithImage3D: WARNING vmax==vmin==%f\n",vmax);grow=.0001;}
00364 vmin-=grow;
00365 vmax+=grow;
00366 bins.assign(nbBins,0);
00367 accumulatedSegmentCount = 0;
00368
00369 AccumulateImage3Dlinear3(src);
00370 }
00371
00372 void
00373 ProbabilityDistribution::AccumulateImage3Dlinear3(const Image3Df &src)
00374 {
00375 if (bins.size() == 0)
00376 ThrowError("Histogram must be set before accumulating");
00377
00378 Vect3Di srcSize=src.SizeV();
00379 int nbBins = bins.size();
00380
00381
00382 for(uint tt=0;tt<bins.size();tt++)
00383 {
00384 bins[tt]*=accumulatedSegmentCount;
00385 }
00386
00387 int segmentCount=0;
00388 for(int dir=0;dir<3;dir++)
00389 {
00390 int d0=(dir+1)%3;
00391 int d1=(dir+2)%3;
00392 int d2=dir;
00393 float minDSrc=.001*(vmax-vmin)/(double)nbBins;
00394 Vect3Di dpos(0,0,0);dpos(d2)=1;
00395 Vect3Di pos(0,0,0);
00396 for(int x0=0;x0<srcSize(d0);x0++)
00397 {
00398 pos(d0)=x0;
00399 for(int x1=0;x1<srcSize(d1);x1++)
00400 {
00401 pos(d1)=x1;
00402 for(int x2=0;x2<srcSize(d2)-1;x2++)
00403 {
00404 pos(d2)=x2;
00405 Vect3Di pos0=pos;
00406 Vect3Di pos1=pos+dpos;
00407
00408 if(src.properties.mask && !src.Mask()(pos0)){continue;}
00409 if(src.properties.mask && !src.Mask()(pos1)){continue;}
00410 segmentCount++;
00411 float src0=src(pos0);
00412 float src1=src(pos1);
00413
00414
00415
00416
00417
00418 if(src1<src0){swap(src0,src1);}
00419 if(src1-src0<minDSrc){src1=src0+minDSrc;}
00420 int srcBin0=BinNum(src0);
00421 int srcBin1=BinNum(src1);
00422
00423 for(int s=srcBin0;s<=srcBin1;s++)
00424 {
00425
00426
00427
00428
00429 bins[s]+=1.0/(1+srcBin1-srcBin0);
00430 }
00431 }
00432 }
00433 }
00434 }
00435 accumulatedSegmentCount += segmentCount;
00436 for(uint tt=0;tt<bins.size();tt++)
00437 {
00438 bins[tt]/=accumulatedSegmentCount;
00439 }
00440
00441 double totproba=0;
00442 for(uint tt=0;tt<bins.size();tt++)
00443 {
00444 totproba+=bins[tt];
00445 }
00446 mprintf("totproba2:%f bins:%d\n",totproba,bins.size());
00447
00448 }
00449
00450
00452 int
00453 ProbabilityDistribution::ScottsRule(const vector<float>& vals)
00454 {
00455 float N=vals.size();
00456 double av=0;
00457 double var=0;
00458 for (int i=0;i<N;i++)
00459 {
00460 av+=vals[i];
00461 var+=vals[i]*vals[i];
00462 }
00463 av/=N;
00464 var/=(N-1);
00465 var-=N/(N-1)*av*av;
00466
00467 double s=sqrt(var);
00468 double w=3.5*s/pow((double)N, 1/3.0);
00469 float maximum = *max_element(vals.begin(), vals.end());
00470 float minimum = *min_element(vals.begin(), vals.end());
00471 int nBins=(int)((maximum-minimum)/w);
00472 return nBins;
00473 }
00474
00475 void
00476 ProbabilityDistribution::SetBins(float _vmin, float _vmax, int nbBins)
00477 {
00478 if (bins.size() > 0)
00479 bins.clear();
00480 vmin=_vmin;
00481 vmax=_vmax;
00482 bins.assign(nbBins,0);
00483 accumulatedSegmentCount = 0;
00484 }