Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

Normalization.cpp

Go to the documentation of this file.
00001 /* ImLib3D
00002  * Copyright (c) 2001, ULP-IPB Strasbourg.
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or (at
00007  * your option) any later version.
00008  * 
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  * 
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00020 #include<ImLib3D/Normalization.hpp>
00021 #include<ImLib3D/Arithmetic.hpp>
00022 #include<ImLib3D/ImageStats.hpp>
00023 #include<ImLib3D/Signal1D.hpp>
00024 //  #include<ImLib3D/Display.hpp>
00025 
00026 #include<ImLib3D/Display.hpp>
00027 Signal1Df 
00028 JointHistogram::ConfidenceWeights() const
00029 {
00030     Signal1Df res(nbSrcBins,SrcVal(0),SrcVal(nbSrcBins));
00031     for(int i=0;i<nbSrcBins;i++){res[i]=GetSrcBinTotalProba(i);}
00032     return res;
00033 }
00034 
00035 Signal1Df 
00036 JointHistogram::SmoothAndExtend(const Signal1Df &src,const Signal1Df &weights,double smoothSigma,double outlierSigma)
00037 {
00038     Signal1Df res=src;
00039     // first compute reliable but imprecise curve
00040     // then refine curve, using  outlier downweighting 
00041     for(int iter=0;iter<2;iter++)
00042     {
00043         double sigma;
00044         if(iter==0){sigma=smoothSigma*5;}
00045         if(iter==1){sigma=smoothSigma;}
00046         
00047         // predicts values from neighboring tangents, using weights
00048         // and using gaussian smoothing
00049         for(int x=0;x<res.Size();x++)
00050         {
00051             double s=0;
00052             double totcoef=0;
00053             for(int x0=0;x0<res.Size()-1;x0++)
00054             {
00055                 int x1=x0+1;
00056                 if(x0<0 || x1>=res.Size()){continue;}
00057                 // tangent
00058                 double dx=(x-.5*(x0+x1));
00059                 double dy=src[x1]-src[x0];
00060                 if(dy<0){continue;}
00061                 // confidence weights
00062                 double w=min(weights[x0],weights[x1]);
00063                 // gaussian smoothing
00064                 double coef=exp(-dx*dx/(2*sigma*sigma));
00065                 double predictedValue=dy*(float)(x-x0)/(float)(x1-x0) + src[x0];
00066                 // outlier downweighting
00067                 double reweight=1;
00068                 if(iter>0)
00069                 {
00070                     double error=predictedValue-res[x];
00071                     reweight=exp(-error*error/(2*outlierSigma*outlierSigma));
00072                 }
00073                 double finalCoef=w*reweight*coef;
00074                 //              printf("*** x0:%d x1:%d coef:%f w:%f predictedValue:%f reweight:%f finalCoef:%f\n",x0,x1,coef,w,predictedValue,reweight,finalCoef);
00075                 s+=finalCoef*predictedValue;
00076                 totcoef+=finalCoef;
00077             }
00078             //          printf("*** x:%d s:%f totcoef:%f\n",x,s,totcoef);
00079             res[x]=(totcoef>0 ? s/totcoef : 0);
00080         }
00081         //      res.GnuPlot();
00082     }
00083 
00084     // impose increasing function, starting at max confidence
00085     float wmax=-1;
00086     int wxmax=-1;
00087     for(int x=0;x<weights.Size();x++){if(weights[x]>wmax){wmax=weights[x];wxmax=x;}}
00088 
00089     for(int x=wxmax+1;x<weights.Size();x++){res[x]=max(res[x],res[x-1]);}
00090     for(int x=wxmax-1;x>=0            ;x--){res[x]=min(res[x],res[x+1]);}
00091 
00092     // smooth result
00093     res.Smooth(2);
00094     res.Smooth(1);
00095 
00096     return res;
00097 }
00098 
00099 void
00100 IP3D::NormalizeAverage(const Image3Df& src,const Image3Df& ref,Image3Df& res)
00101 {
00102     double avRef,varRef;
00103     IP3D::AverageAndVariance(ref,avRef,varRef);
00104     double avSrc,varSrc;
00105     IP3D::AverageAndVariance(src,avSrc,varSrc);
00106     printf("src:%f\n",avSrc);
00107     res=src;
00108     res+=(avRef-avSrc);
00109 }
00110 
00111 void
00112 IP3D::NormalizeAverageAndVariance(const Image3Df& src,const Image3Df& ref,Image3Df& res)
00113 {
00114     double avRef,varRef;
00115     IP3D::AverageAndVariance(ref,avRef,varRef);
00116     double avSrc,varSrc;
00117 //  double avRes,varRes;
00118     IP3D::AverageAndVariance(src,avSrc,varSrc);
00119     printf("src:%f %f\n",avSrc,varSrc);
00120     if(varSrc==0){fprintf(stderr,"WARNING: NormalizeAverageAndVariance: sourceimage variance is 0 (image is constant), just normalizing averge\n");varSrc=1;}
00121     res=src;
00122     res-=avSrc;
00123     res*=sqrt(varRef/varSrc);
00124     res+=avRef;
00125 
00126 }
00127 
00128 // **************************************************************************************
00129 // **************************************************************************************
00130 // **************************************************************************************
00131 
00132 void 
00133 JointHistogram::AddDisplayGrid()
00134 {
00135     // add "grid" for visu
00136     if(!histogramImage.HasMask()){histogramImage.AddMask();}
00137     histogramImage.Mask().Fill(0);
00138     double ddSrc=pow(10.0,floor(log10(srcMax-srcMin)));
00139     double ddRef=pow(10.0,floor(log10(refMax-refMin)));
00140     for(Mask3D::iteratorXYZ p=histogramImage.Mask().begin();p!=histogramImage.Mask().end();++p)
00141     {
00142         double xx=srcMin+p.x*(srcMax-srcMin)/(double)nbSrcBins;
00143         double yy=refMin+p.y*(refMax-refMin)/(double)nbRefBins;
00144         double xx1=srcMin+(p.x+1)*(srcMax-srcMin)/(double)nbSrcBins;
00145         double yy1=refMin+(p.y+1)*(refMax-refMin)/(double)nbRefBins;
00146         if(floor(xx/ddSrc)!=floor(xx1/ddSrc))
00147         {
00148             if(p.y==0){mprintf("grid x:%f\n",xx);}
00149             *p=1;
00150         }
00151         if(floor(yy/ddRef)!=floor(yy1/ddRef))
00152         {
00153             if(p.x==0){mprintf("grid y:%f\n",yy);}
00154             *p=1;
00155         }
00156     }
00157 }
00158 
00159 float 
00160 JointHistogram::GetSrcBinTotalProba(int x) const
00161 {
00162     float res=0;
00163     for(int y=0;y<nbRefBins;y++){res+=histogramImage(x,y,0);}
00164     return res;
00165 }
00167 Signal1Df 
00168 JointHistogram::MedianTransferFct() const 
00169 {
00170     Signal1Df res(nbSrcBins,SrcVal(0),SrcVal(nbSrcBins));
00171     for(int x=0;x<nbSrcBins;x++)
00172     {
00173         double tot=0;
00174         int y;
00175         double avg=0;
00176         for(y=0;y<nbRefBins;y++)
00177         {
00178             tot+=histogramImage(x,y,0);
00179             avg+=y*histogramImage(x,y,0);
00180         }
00181         printf("tot %d:%f\n",x,tot);
00182         avg/=tot;
00183         double sum=0;
00184         int ly=0;
00185         for(y=0;y<nbRefBins;y++)
00186         {
00187             sum+=histogramImage(x,y,0);
00188             if(sum>tot/1.9999999)
00189             {
00190                 if(ly==y-1)
00191                 {
00192                     double ls=sum-histogramImage(x,y,0);
00193                     double ymiddle=(y-ly)*(0.5-ls/tot)/(sum/tot-ls/tot)+ly;                 
00194                     printf("tot:%f sum:%f y:%d ly:%d ls:%f ymiddle:%f(%f) avg:%f(%f)\n",tot,sum,y,ly,ls,ymiddle,RefVal(ymiddle),avg,RefVal(avg));
00195                     res[x]=RefVal(ymiddle);                 
00196                 }
00197                 else
00198                 {
00199                     double ymiddle=(y+ly)/2.0;
00200                     printf("tot:%f sum:%f y:%d ly:%d ymiddle:%f\n",tot,sum,y,ly,ymiddle);
00201                     res[x]=RefVal(ymiddle);
00202                 }
00203                 break;
00204             }
00205             if(histogramImage(x,y,0)){ly=y;}
00206         }
00207     }
00208     return res;
00209 }
00210 
00212 Signal1Df 
00213 JointHistogram::MaximumProbabilityTransferFct() const
00214 {
00215     Signal1Df res(nbSrcBins,SrcVal(0),SrcVal(nbSrcBins));
00216     for(int x=0;x<nbSrcBins;x++)
00217     {
00218         Signal1Df proba0(nbRefBins,RefVal(0),RefVal(nbRefBins));
00219         for(int y=0;y<nbRefBins;y++)
00220         {
00221             proba0[y]=histogramImage(x,y,0);
00222         }
00223         int supersample=10;
00224         Signal1Df proba(nbRefBins*supersample,RefVal(0),RefVal(nbRefBins));
00225         for(int y=0;y<proba.Size();y++)
00226         {
00227             proba[y]=proba0(proba.ISampleToX(y));
00228         }
00229         proba.Smooth(2*supersample);
00230         proba.Smooth(2*supersample);
00231         proba.Smooth(2*supersample);
00232         double maxv=-1;
00233         int ymax=-1;
00234         for(int y=0;y<proba.Size();y++)
00235         {
00236             if(proba[y]>maxv){ymax=y;maxv=proba[y];}
00237         }
00238         // affine result with quadratic approx (not very usefull, just usefull if supersample is low)
00239 //          if(ymax>0 && ymax<proba.Size()-1)
00240 //          {
00241 //              float dy0=proba[ymax-1]-proba[ymax];
00242 //              float dy1=proba[ymax+1]-proba[ymax];
00243 //              float qymax=.5*((dy0-dy1)/(dy0+dy1))+ymax;
00244 //              float x0=proba.GetSupport().first;
00245 //              float x1=proba.GetSupport().second;
00246 //              res[x]=qymax*(x1-x0)/proba.Size()+x0;
00247 //          }
00248 //          else
00249         {
00250             res[x]=proba.ISampleToX(ymax);
00251         }
00252     }
00253     return res;
00254 }
00255 
00256 
00257 void 
00258 JointHistogram::ComputeFromIndependentSamples(const Image3Df &src,const Image3Df &ref)
00259 {
00260     // make joint histogram
00261     for(Image3Df::const_iteratorXYZ p=src.begin();p!=src.end();++p)
00262     {
00263         if(src.HasMask() && !src.Mask(p.Pos())){continue;}
00264         if(ref.HasMask() && !ref.Mask(p.Pos())){continue;}
00265         histogramImage(SSrcBin(*p),SRefBin(ref(p.Pos())),0)+=1;
00266     }
00267 }
00268 void 
00269 JointHistogram::ComputeFromDirectionalLinearInterpolation(const Image3Df &src,const Image3Df &ref,int dir)
00270 {
00271     // make joint histogram
00272     Vect3Di srcSize=src.SizeV();
00273     int d0=(dir+1)%3;
00274     int d1=(dir+2)%3;
00275     int d2=dir;
00276 //  float minDSrc=.001*(srcMax-srcMin)/(double)nbSrcBins;
00277 //  float minDRef=.001*(refMax-refMin)/(double)nbRefBins;
00278     Vect3Di dpos(0,0,0);dpos(d2)=1;
00279     Vect3Di pos(0,0,0);
00280     for(int x0=0;x0<srcSize(d0);x0++)
00281     {
00282         pos(d0)=x0;
00283         for(int x1=0;x1<srcSize(d1);x1++)
00284         {
00285             pos(d1)=x1;
00286             for(int x2=0;x2<srcSize(d2)-1;x2++)
00287             {
00288                 pos(d2)=x2;
00289                 Vect3Di pos0=pos;
00290                 Vect3Di pos1=pos+dpos;
00291                 // intenisty of src from pos0 to pos1 goes from src0 to src1
00292                 // while intensity of ref goes from ref0 to ref1
00293 
00294                 // skip if we're on unmasked
00295                 if( (src.HasMask() && ( !src.Mask(pos0) || !src.Mask(pos1))) ||
00296                     (ref.HasMask() && ( !ref.Mask(pos0) || !ref.Mask(pos1)))   )  {continue;}
00297                 float src0=src(pos0);
00298                 float ref0=ref(pos0);
00299                 float src1=src(pos1);
00300                 float ref1=ref(pos1);
00301 //              pos0.Show("pos0:","   ");
00302 //              pos1.Show("pos1:","\n");
00303 //              printf("src0:%f ref0:%f    src1:%f ref1:%f\n",src0,ref0,src1,ref1);
00304                 // draw line of value 1/linesize in histogramImage between these two positions
00305                 {
00306                     Vect3Df p0(SrcBinF(src0),RefBinF(ref0),0);
00307                     Vect3Df p1(SrcBinF(src1),RefBinF(ref1),0);
00308                     Vect3Df dP=p1-p0;
00309                     int dir=dP.MaxAbsCoord();
00310                     bool incr=dP(dir)>0;
00311                     dP/=fabs(dP(dir));
00312                     int linesize=0;
00313                     for(Vect3Df p=p0;(incr? p(dir)<p1(dir) : p(dir)>p1(dir));p+=dP)
00314                     {
00315                         linesize++;
00316                     }
00317                     for(Vect3Df p=p0;(incr? p(dir)<p1(dir) : p(dir)>p1(dir));p+=dP)
00318                     {
00319                         if(histogramImage.IsInside(rint(p))){histogramImage(rint(p))+=1.0/linesize;}
00320                     }
00321                 }
00322             }
00323         }
00324     }
00325 }
00326 
00327 JointHistogram::JointHistogram(const string &filename):
00328     histogramImage(filename)
00329 {
00330     nbSrcBins=histogramImage.Property<int>("nbSrcBins");
00331     nbRefBins=histogramImage.Property<int>("nbRefBins");
00332     srcMin=histogramImage.Property<double>("srcMin");
00333     srcMax=histogramImage.Property<double>("srcMax");
00334     refMin=histogramImage.Property<double>("refMin");
00335     refMax=histogramImage.Property<double>("refMax");
00336     printf("nbSrcBins:%d nbRefBins:%d srcMin:%f srcMax:%f refMin:%f refMax:%f\n",
00337            nbSrcBins, nbRefBins, srcMin, srcMax, refMin, refMax);
00338 }
00339 JointHistogram::JointHistogram(const Image3Df &src,const Image3Df &ref,int _nbSrcBins,int _nbRefBins):
00340     nbSrcBins(_nbSrcBins),nbRefBins(_nbRefBins),histogramImage(_nbSrcBins,_nbRefBins,1)     
00341 {
00342     histogramImage.Fill(0);
00343     // find ranges/ bounds
00344     FindRanges(src,ref);
00345 
00346 //      ComputeFromIndependentSamples(src,ref);
00347     ComputeFromDirectionalLinearInterpolation(src,ref,0);
00348     ComputeFromDirectionalLinearInterpolation(src,ref,1);
00349     ComputeFromDirectionalLinearInterpolation(src,ref,2);
00350     histogramImage*=1/3.0;
00351 }
00352 
00353 void 
00354 JointHistogram::FindRanges(const Image3Df& src, const Image3Df &ref)
00355 {
00356     vector<float> srcValues;
00357     vector<float> refValues;
00358     srcValues.reserve(src.GetNVoxels());
00359     refValues.reserve(ref.GetNVoxels());
00360     for(Image3Df::const_iteratorXYZ p=src.begin();p!=src.end();++p)
00361     {
00362         if(src.HasMask() && !src.Mask(p.Pos())){continue;}
00363         if(ref.HasMask() && !ref.Mask(p.Pos())){continue;}
00364         srcValues.push_back(*p);
00365         refValues.push_back(ref(p.Pos()));
00366     }
00367 
00368     // ProbabilityDistribution uses bins, which might not be reliable enough 
00369 
00370     // use nth_element to find histogram range (this is much faster than sorting)
00371     vector<float>::iterator pnth;
00372     pnth=srcValues.begin()+(size_t)floor(.005*srcValues.size());
00373     nth_element(srcValues.begin(),pnth,srcValues.end());
00374     srcMin=*pnth;
00375     pnth=srcValues.begin()+min(srcValues.size()-1,(size_t)ceil(.995*srcValues.size()));
00376     nth_element(srcValues.begin(),pnth,srcValues.end());
00377     srcMax=*pnth;
00378     float d=srcMax-srcMin;
00379     srcMin-=d*.3;
00380     srcMax+=d*.3;
00381 
00382     pnth=refValues.begin()+(size_t)floor(.005*refValues.size());
00383     nth_element(refValues.begin(),pnth,refValues.end());
00384     refMin=*pnth;
00385     pnth=refValues.begin()+min(refValues.size()-1,(size_t)ceil(.995*refValues.size()));
00386     nth_element(refValues.begin(),pnth,refValues.end());
00387     refMax=*pnth;
00388     d=refMax-refMin;
00389     refMin-=d*.6;
00390     refMax+=d*.6;
00391 
00392     histogramImage.AddProperty("srcMin",srcMin);
00393     histogramImage.AddProperty("srcMax",srcMax);
00394     histogramImage.AddProperty("refMin",refMin);
00395     histogramImage.AddProperty("refMax",refMax);
00396     histogramImage.AddProperty("nbSrcBins",nbSrcBins);
00397     histogramImage.AddProperty("nbRefBins",nbRefBins);
00398 
00399     histogramImage.AddSupport(Vect3Df(srcMin,refMin,0),Vect3Df(srcMax,refMax,1));
00400     mprintf("JointHistogram srcMin:%f srcMax:%f refMin:%f refMax:%f\n",srcMin,srcMax,refMin,refMax);
00401 }
00402 
00403 // **************************************************************************************
00404 // **************************************************************************************
00405 void
00406 IP3D::NormalizeJointHistogram(const Image3Df& src0,const Image3Df& ref,Image3Df& res,int nbSrcBins,int nbRefBins)
00407 {
00408     Image3Df src;
00409     IP3D::NormalizeAverageAndVariance(src0,ref,src);
00410     // compute joint histo
00411     JointHistogram joint(src,ref,nbSrcBins,nbRefBins);
00412     // compute transfer fct
00413     Signal1Df transferFct=JointHistogram::SmoothAndExtend(joint.MaximumProbabilityTransferFct(),
00414                                                           joint.ConfidenceWeights(),
00415                                                           joint.nbSrcBins/50.0,
00416                                                           (joint.refMax-joint.refMin)/25);
00417 
00418     // apply transfer fct
00419     // single transfer fct on src image only
00420     res=src;
00421     for(Image3Df::iteratorFast p=res.begin();p!=res.end();++p)
00422     {
00423         *p=transferFct(*p);
00424     }
00425 }
00426 
00427 
00428 
00429 // **************************************************************************************
00430 void
00431 IP3D::ComputeJointHistogramImage(const Image3Df& src0,const Image3Df& ref,Image3Df& res,int drawTransferFunction,int nbSrcBins,int nbRefBins)
00432 {
00433     Image3Df src;
00434     IP3D::NormalizeAverageAndVariance(src0,ref,src);
00435     JointHistogram joint(src,ref,nbSrcBins,nbRefBins);
00436 
00437     Signal1Df transferFct;
00438     if(drawTransferFunction==1)
00439     {
00440         transferFct=joint.BestFitTransferFct();
00441     }
00442     if(drawTransferFunction==2)
00443     {
00444         transferFct=JointHistogram::SmoothAndExtend(joint.MaximumProbabilityTransferFct(),
00445                                                               joint.ConfidenceWeights(),
00446                                                               joint.nbSrcBins/50.0,
00447                                                               (joint.refMax-joint.refMin)/25);
00448     }
00449     if(drawTransferFunction>0)
00450     {
00451         for(int x=0;x<joint.histogramImage.Width();x++)
00452         {
00453             joint.histogramImage(x,joint.SRefBin(transferFct(joint.SrcVal(x))),0)=-10;
00454         }
00455     }
00456     res=joint.histogramImage;
00457 }
00458 
00459 
00460 // **************************************************************************************
00461 // **************************************************************************************
00462 // **************************************************************************************
00463 // **************************************************************************************
00464 // #include<gsl/gsl_version.h>
00465 // #if GSL_VERSION="1.1.1"
00466 // Signal1Df 
00467 // JointHistogram::BestFitTransferFct(double smoothingCoef,bool allowDecreasing) const
00468 // {
00469 //  ThrowError("JointHistogram::BestFitTransferFct requires at least gsl 1.2 ... not compiled");
00470 // }
00471 // #else
00472 #include<gsl/gsl_multimin.h>
00473 
00474 class IntensityTransferFctFitter
00475 {
00476     const JointHistogram &joint;
00477     double smoothingCoef,decreasingCoef;
00478     Signal1Df central;
00479     Signal1Df confidenceWeights;
00480     double totalWeight;
00481     double refImageVariance;
00482 public:
00483     void SetDecreasingCoef(double _decreasingCoef){decreasingCoef=_decreasingCoef;}
00484     //  transfer function is linear by parts
00485     float TransferFctValue(const vector<double> &values,int xpos)
00486     {
00487         // just test with linear
00488         float pos=values.size()*xpos/(float)joint.nbSrcBins;
00489         int p0=min((int)values.size()-2,max(0,(int)floor(pos)));
00490         int p1=p0+1;
00491         return (pos-p0)*values[p1]+(p1-pos)*values[p0];
00492     }
00493     void Filter(const vector<double> &src,const vector<double> &filter,vector<double> &res)
00494     {
00495         if((filter.size()%2)==0){ThrowError("filter size must bue unpair");}
00496         res.resize(src.size());
00497         for(uint i=0;i<src.size();i++)
00498         {
00499             int center=(filter.size()-1)/2;
00500             // i+j-center>=0  => j>=center-i
00501             int jmin=max(center-(int)i,0);
00502             // i+j-center<=s-1  => j<s-1+center-i
00503             int jmax=min(((int)src.size())-1+center-(int)i,(int)filter.size()-1);               
00504             double total=0;
00505             double totalc=0;
00506             for(int j=jmin;j<=jmax;j++)
00507             {
00508                 total+=filter[j]*src[i+j-center];
00509                 totalc+=filter[j];
00510             }
00511             res[i]=total/totalc;
00512         }
00513     }
00514     // error of fit
00515     double TotalError(const vector<double> &values)
00516     {
00517         bool talk=false;//(rand()%000)==0;
00518         // precompute transfer fct values
00519         vector<double> splineYPos(joint.nbSrcBins);
00520         for(int x=0;x<joint.nbSrcBins;x++)
00521         {
00522             splineYPos[x]=TransferFctValue(values,x);
00523         }
00524         // compute error due to joint histogram
00525         double errorJointHistogram=0;
00526         vector<float> debugDisplayImageError;
00527         for(int x=0;x<joint.nbSrcBins;x++)
00528         {
00529             double d=joint.RefVal(splineYPos[x])-central[x];
00530             errorJointHistogram+=confidenceWeights[x]*(d*d);
00531             if(talk){debugDisplayImageError.push_back(confidenceWeights[x]*(d*d));}
00532         }
00533         if(talk){GnuPlot(debugDisplayImageError,"image error");}
00534         errorJointHistogram/=refImageVariance*totalWeight;
00535         // compute smoothness error 
00536         double errorSmoothness=0;
00537         {
00538             // trasnfer fct is a linear interpolated: (delta convoluted by 1st degree spline)
00539             // second derivative of 1st degree spline is
00540             vector<double> secondDeriv(values.size()-2);
00541             for(uint i=1;i<values.size()-1;i++)
00542             {
00543                 secondDeriv[i-1]=values[i+1]-2*values[i]+values[i-1];
00544             }
00545             // smooth out secondDeriv
00546             vector<double> smoothed0;
00547             {
00548                 double filter00[] =  {1,3,4,3,1};
00549                 vector<double> filter0(filter00, filter00+sizeof(filter00)/sizeof(double));
00550                 Filter(secondDeriv,filter0,smoothed0);
00551             }
00552             // smooth out secondDeriv
00553             vector<double> smoothed1;
00554             {
00555                 double filter10[] = {1,2,3,4,5,6,5,4,3,2,1};
00556                 vector<double> filter1(filter10, filter10+sizeof(filter10)/sizeof(double));
00557                 Filter(secondDeriv,filter1,smoothed1);
00558             }
00559 
00560             if(talk)
00561             {
00562                 GnuPlot(values,"transfer function values");
00563                 GnuPlot(secondDeriv,"secondDeriv");
00564                 GnuPlot(smoothed0,"smoothed0");
00565                 GnuPlot(smoothed1,"smoothed1");
00566                 printf("print\n");
00567             }
00568             // we dont want largeScaleSmoothnessCoef to be very strong, because
00569             // it introduces a bias on correct results
00570             // now compute error
00571             for(uint i=0;i<secondDeriv.size();i++)
00572             {
00573                 errorSmoothness+=
00574                     //                  secondDeriv[i]*secondDeriv[i]*.0005+
00575                     smoothed0  [i]*smoothed0[i]+
00576                     smoothed1  [i]*smoothed1[i]*.2;
00577                     
00578             }
00579         }
00580         errorSmoothness*=40.0/(double)(joint.nbRefBins*joint.nbRefBins*values.size());
00581         // compute decreasing error 
00582         double errorDecreasing=0;
00583         for(uint i=0;i<values.size()-1;i++)
00584         {
00585             errorDecreasing+=max(0.0,-(values[i+1]-values[i]));
00586         }
00587         errorDecreasing*=.0001;
00588         return errorJointHistogram+smoothingCoef*errorSmoothness+decreasingCoef*errorDecreasing;
00589     }
00590 
00591     IntensityTransferFctFitter(const JointHistogram &_joint,double _smoothingCoef=1,double _decreasingCoef=0):
00592         joint(_joint),
00593         smoothingCoef(_smoothingCoef),
00594         decreasingCoef(_decreasingCoef)
00595     {
00596         central=joint.MaximumProbabilityTransferFct();
00597         confidenceWeights=joint.ConfidenceWeights();
00598         // debug : display central 
00599 //          {
00600 //              Image3Df tmp=joint.histogramImage;
00601 //              for(int x=0;x<tmp.Width();x++)
00602 //              {
00603 //                  tmp(x,joint.SRefBin(central[x]),0)=-10;
00604 //                  printf("%f:%f ",central.ISampleToX(x),central[x]);
00605 //              }       
00606 //              printf("\n");
00607 //              tmp.WriteToFile("central.im3D");
00608 //          }
00609         // ref image variance
00610         refImageVariance=0;
00611         totalWeight=0;
00612         double refImageAverage=0;
00613         for(Image3Df::const_iteratorXYZ p=joint.histogramImage.begin();p!=joint.histogramImage.end();++p)
00614         {
00615             totalWeight+=*p;
00616             refImageVariance+=(*p)*joint.RefVal(p.y)*joint.RefVal(p.y);
00617             refImageAverage+=(*p)*joint.RefVal(p.y);
00618         }
00619         refImageAverage/=totalWeight;
00620         refImageVariance=(refImageVariance/totalWeight)-refImageAverage;
00621         printf("refImageAverage:%f refImageVariance:%f stddev:%f\n",refImageAverage,refImageVariance,sqrt(refImageVariance));
00622     }
00623 
00624 };
00625 vector<double>
00626 MakeSTLVector(const gsl_vector *v)
00627 {
00628     vector<double> values(v->size);
00629     for(uint i=0;i<values.size();i++){values[i]=gsl_vector_get(v, i);}
00630     return values;
00631 }
00632 gsl_vector *
00633 MakeGSLVector(const vector<double> &src)
00634 {
00635     gsl_vector *res = gsl_vector_alloc (src.size());  
00636     for(uint i=0;i<src.size();i++)
00637     {
00638         gsl_vector_set (res, i, src[i]);
00639     }
00640     return res;
00641 }
00642 
00643 double
00644 GSLMinimizationFunction (const gsl_vector *v, void *params)
00645 {
00646     return ((IntensityTransferFctFitter *)params)->TotalError(MakeSTLVector(v));
00647 }
00648 
00649 int
00650 FitIntensityTransferFctUsingGSLMinimization(IntensityTransferFctFitter &intensityTransferFctFitter,vector<double> &values0)
00651 {
00652     gsl_vector *values=MakeGSLVector(values0);
00653 
00654     // Initial vertex size vector  (??)
00655     gsl_vector *ss;
00656     ss = gsl_vector_alloc (values->size);
00657     gsl_vector_set_all (ss, 1.0);
00658 
00659 
00660     // initialize function
00661     gsl_multimin_function minex_func;
00662     {
00663         minex_func.f = &GSLMinimizationFunction;
00664         minex_func.n = values->size;
00665         minex_func.params = (void *)&intensityTransferFctFitter;
00666     }
00667 
00668     // initialize minimizer
00669     gsl_multimin_fminimizer *minimizer = 
00670         minimizer = gsl_multimin_fminimizer_alloc (gsl_multimin_fminimizer_nmsimplex, values->size);
00671     gsl_multimin_fminimizer_set (minimizer, &minex_func, values, ss);
00672 
00673 
00674     // iterate minimizations
00675     int rval = GSL_CONTINUE;
00676     int status = GSL_SUCCESS;
00677     double ssval;
00678     size_t iter = 0;
00679     while (rval == GSL_CONTINUE)
00680     {
00681         iter++;
00682         status = gsl_multimin_fminimizer_iterate(minimizer);
00683       
00684         if (status) 
00685         break;
00686 
00687         rval = gsl_multimin_test_size (gsl_multimin_fminimizer_size (minimizer),
00688                                        1e-2);
00689         ssval = gsl_multimin_fminimizer_size (minimizer);
00690 
00691         if (rval == GSL_SUCCESS) 
00692         {
00693             printf ("converged to minimum at\n");
00694 
00695             printf("iter %4d : ", iter);
00696             for (uint i = 0; i < values->size; i++)
00697             {
00698             printf ("%5.2f ", gsl_vector_get (minimizer->x, i));
00699             }
00700             printf("f() = %-10.10f ssize = %.3f\n", minimizer->fval, ssval);
00701         }
00702     }
00703     // cleanup 
00704     values0=MakeSTLVector(minimizer->x);
00705     gsl_vector_free(values);
00706     gsl_vector_free(ss);
00707     gsl_multimin_fminimizer_free (minimizer);
00708     return status;
00709 }
00710 
00711 Signal1Df 
00712 JointHistogram::BestFitTransferFct(double smoothingCoef,bool allowDecreasing) const
00713 {
00714     IntensityTransferFctFitter intensityTransferFctFitter(*this);
00715 
00716     // Starting point (identity transfer fct)
00717     vector<double> values(40);
00718     for(uint i=0;i<values.size();i++)
00719     {
00720         values[i]=(nbRefBins*i)/(float)values.size();
00721     }
00722     // if decreasing is not allow. iteratively fit
00723     // while progressively increasing decreasingCoef
00724     for(double decreasingCoef=.0001;decreasingCoef<1000000;decreasingCoef*=4)
00725     {
00726         if(!allowDecreasing){intensityTransferFctFitter.SetDecreasingCoef(decreasingCoef);}
00727         FitIntensityTransferFctUsingGSLMinimization(intensityTransferFctFitter,values);
00728         // check if decreasing
00729         bool decreasing=false;
00730         for(uint i=0;i<values.size()-1;i++)
00731         {
00732             if(values[i+1]<values[i]){decreasing=true;break;}
00733         }
00734         if(allowDecreasing || !decreasing){break;}
00735     }
00736     // compute final results from fitted values
00737     Signal1Df res(nbSrcBins,SrcVal(0),SrcVal(nbSrcBins));
00738     for(int i=0;i<res.Size();i++)
00739     {
00740         res[i]=RefVal(intensityTransferFctFitter.TransferFctValue(values,i));
00741     }
00742     return res;
00743 }

Generated on Fri Jun 17 13:36:06 2005 for ImLib3D by  doxygen 1.4.2