source: trunk/src/ATrous/atrous_2d_reconstruct.cc @ 1322

Last change on this file since 1322 was 1026, checked in by MatthewWhiting, 12 years ago

A couple of important fixes for the reconstruction. One is to fix #154, making sure the min & max scales are applied appropriately. Second is to add a new parameter
reconConvergence, which takes the previously hard-coded convergence criterion and makes it available to be altered. Documentation is updated for this parameter as well.

File size: 11.0 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// atrous_2d_reconstruct.cc: 2-dimensional wavelet reconstruction.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
[3]28#include <iostream>
29#include <iomanip>
30#include <math.h>
[393]31#include <duchamp/duchamp.hh>
32#include <duchamp/param.hh>
33#include <duchamp/ATrous/atrous.hh>
34#include <duchamp/ATrous/filter.hh>
35#include <duchamp/Utils/utils.hh>
36#include <duchamp/Utils/feedback.hh>
37#include <duchamp/Utils/Statistics.hh>
[190]38using Statistics::madfmToSigma;
[3]39
[378]40namespace duchamp
[3]41{
[86]42
[887]43  void atrous2DReconstruct(size_t &xdim, size_t &ydim, float *&input, float *&output, Param &par)
[378]44  {
[528]45    ///  A routine that uses the a trous wavelet method to reconstruct a
46    ///   2-dimensional image.
47    ///
48    ///  If there are no non-BLANK pixels (and we are testing for
49    ///  BLANKs), the reconstruction cannot be done, so we return the
50    ///  input array as the output array and give a warning message.
51    ///
52    ///  \param xdim The length of the x-axis of the image.
53    ///  \param ydim The length of the y-axis of the image.
54    ///  \param input The input spectrum.
55    ///  \param output The returned reconstructed spectrum. This array
56    ///  needs to be declared beforehand.
57    ///  \param par The Param set:contains all necessary info about the
58    ///  filter and reconstruction parameters.
[3]59
[1026]60    const float SNR_THRESH=par.getAtrousCut();
61    unsigned int MIN_SCALE=par.getMinScale();
62    unsigned int MAX_SCALE=par.getMaxScale();
63
[846]64    size_t size = xdim * ydim;
[1026]65    size_t mindim = xdim;
[378]66    if (ydim<mindim) mindim = ydim;
[1026]67
[884]68    unsigned int numScales = par.filter().getNumScales(mindim);
[1026]69    if((MAX_SCALE>0)&&(MAX_SCALE<=numScales))
70      MAX_SCALE = std::min(MAX_SCALE,numScales);
71    else{
72      if((MAX_SCALE!=0))
73        DUCHAMPWARN("Reading parameters","The requested value of the parameter scaleMax, \"" << par.getMaxScale() << "\" is outside the allowed range (1-"<< numScales <<") -- setting to " << numScales);
74      MAX_SCALE = numScales;
75      par.setMaxScale(MAX_SCALE);
76    }
77
[378]78    double *sigmaFactors = new double[numScales+1];
[846]79    for(size_t i=0;i<=numScales;i++){
[378]80      if(i<=par.filter().maxFactor(2))
81        sigmaFactors[i] = par.filter().sigmaFactor(2,i);
82      else sigmaFactors[i] = sigmaFactors[i-1] / 2.;
83    }
[231]84
[894]85    float mean,originalSigma,oldsigma,newsigma;
[846]86    size_t goodSize=0;
[378]87    bool *isGood = new bool[size];
[846]88    for(size_t pos=0;pos<size;pos++){
[378]89      isGood[pos] = !par.isBlank(input[pos]);
90      if(isGood[pos]) goodSize++;
91    }
[231]92
[378]93    if(goodSize == 0){
94      // There are no good pixels -- everything is BLANK for some reason.
95      // Return the input array as the output, and give a warning message.
[231]96
[846]97      for(size_t pos=0;pos<size; pos++) output[pos] = input[pos];
[378]98
[913]99      DUCHAMPWARN("2D Reconstruction","There are no good pixels to be reconstructed -- all are BLANK. Returning input array.");
[378]100    }
101    else{
102      // Otherwise, all is good, and we continue.
[231]103
[849]104      //      findMedianStats(input,goodSize,isGood,originalMean,originalSigma);
105      // originalSigma = madfmToSigma(originalSigma);
106      if(par.getFlagRobustStats())
107        originalSigma = madfmToSigma(findMADFM(input,isGood,size));
108      else
[889]109        originalSigma = findStddev<float>(input,isGood,size);
[3]110 
[378]111      float *coeffs    = new float[size];
112      float *wavelet   = new float[size];
[849]113      // float *residual  = new float[size];
[3]114
[846]115      for(size_t pos=0;pos<size;pos++) output[pos]=0.;
[3]116
[846]117      unsigned int filterwidth = par.filter().width();
[378]118      int filterHW = filterwidth/2;
119      double *filter = new double[filterwidth*filterwidth];
[846]120      for(size_t i=0;i<filterwidth;i++){
121        for(size_t j=0;j<filterwidth;j++){
[378]122          filter[i*filterwidth+j] = par.filter().coeff(i) * par.filter().coeff(j);
123        }
[231]124      }
[3]125
[908]126      // long *xLim1 = new long[ydim];
127      // for(size_t i=0;i<ydim;i++) xLim1[i] = 0;
128      // long *yLim1 = new long[xdim];
129      // for(size_t i=0;i<xdim;i++) yLim1[i] = 0;
130      // long *xLim2 = new long[ydim];
131      // for(size_t i=0;i<ydim;i++) xLim2[i] = xdim-1;
132      // long *yLim2 = new long[xdim];
133      // for(size_t i=0;i<xdim;i++) yLim2[i] = ydim-1;
[3]134
[908]135      // if(par.getFlagBlankPix()){
136      //        float avGapX = 0, avGapY = 0;
137      //        for(size_t row=0;row<ydim;row++){
138      //          size_t ct1 = 0;
139      //          size_t ct2 = xdim - 1;
140      //          while((ct1<ct2)&&(par.isBlank(input[row*xdim+ct1]))) ct1++;
141      //          while((ct2>ct1)&&(par.isBlank(input[row*xdim+ct2]))) ct2--;
142      //          xLim1[row] = ct1;
143      //          xLim2[row] = ct2;
144      //          avGapX += ct2 - ct1;
145      //        }
146      //        avGapX /= float(ydim);
[103]147   
[908]148      //        for(size_t col=0;col<xdim;col++){
149      //          size_t ct1=0;
150      //          size_t ct2=ydim-1;
151      //          while((ct1<ct2)&&(par.isBlank(input[col+xdim*ct1]))) ct1++;
152      //          while((ct2>ct1)&&(par.isBlank(input[col+xdim*ct2]))) ct2--;
153      //          yLim1[col] = ct1;
154      //          yLim2[col] = ct2;
155      //          avGapY += ct2 - ct1;
156      //        }
157      //        avGapY /= float(xdim);
[103]158   
[908]159      //        // if(avGapX < mindim) mindim = int(avGapX);
160      //        // if(avGapY < mindim) mindim = int(avGapY);
161      //        // numScales = par.filter().getNumScales(mindim);
162      // }
[3]163
[378]164      float threshold;
165      int iteration=0;
166      newsigma = 1.e9;
[846]167      for(size_t i=0;i<size;i++) output[i] = 0;
[378]168      do{
169        if(par.isVerbose()) {
170          std::cout << "Iteration #"<<std::setw(2)<<++iteration<<":";
[231]171          printBackSpace(13);
172        }
173
[378]174        // first, get the value of oldsigma and set it to the previous
175        //   newsigma value
176        oldsigma = newsigma;
177        // we are transforming the residual array
[846]178        for(size_t i=0;i<size;i++)  coeffs[i] = input[i] - output[i]; 
[378]179
180        int spacing = 1;
[846]181        for(unsigned int scale = 1; scale<numScales; scale++){
[378]182
183          if(par.isVerbose()){
184            std::cout << "Scale ";
185            std::cout << std::setw(2)<<scale<<" / "<<std::setw(2)<<numScales;
186            printBackSpace(13);
187            std::cout <<std::flush;
188          }
189
[846]190          for(unsigned long ypos = 0; ypos<ydim; ypos++){
191            for(unsigned long xpos = 0; xpos<xdim; xpos++){
[378]192              // loops over each pixel in the image
[846]193              size_t pos = ypos*xdim + xpos;
[3]194         
[378]195              wavelet[pos] = coeffs[pos];
[3]196
[378]197              if(!isGood[pos]) wavelet[pos] = 0.;
198              else{
[3]199
[908]200                size_t filterpos = 0;
[378]201                for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
[846]202                  long y = long(ypos) + spacing*yoffset;
[908]203                  while((y<0)||(y>=long(ydim))){
204                    // boundary conditions are reflection.
205                    if(y<0) y = 0 - y;
206                    else if(y>=long(ydim)) y = 2*(ydim-1) - y;
207                  }
[231]208                  // Boundary conditions -- assume reflection at boundaries.
209                  // Use limits as calculated above
[378]210                  //          if(yLim1[xpos]!=yLim2[xpos]){
211                  //            // if these are equal we will get into an infinite loop here
212                  //            while((y<yLim1[xpos])||(y>yLim2[xpos])){
213                  //              if(y<yLim1[xpos]) y = 2*yLim1[xpos] - y;     
214                  //              else if(y>yLim2[xpos]) y = 2*yLim2[xpos] - y;     
[231]215                  //            }
[378]216                  //          }
[846]217                  size_t oldrow = y * xdim;
[378]218         
219                  for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
[846]220                    long x = long(xpos) + spacing*xoffset;
[908]221                    while((x<0)||(x>=long(xdim))){
222                      // boundary conditions are reflection.
223                      if(x<0) x = 0 - x;
224                      else if(x>=long(xdim)) x = 2*(xdim-1) - x;
225                    }
[378]226                    // Boundary conditions -- assume reflection at boundaries.
227                    // Use limits as calculated above
228                    //          if(xLim1[ypos]!=xLim2[ypos]){
229                    //            // if these are equal we will get into an infinite loop here
230                    //            while((x<xLim1[ypos])||(x>xLim2[ypos])){
231                    //              if(x<xLim1[ypos]) x = 2*xLim1[ypos] - x;     
232                    //              else if(x>xLim2[ypos]) x = 2*xLim2[ypos] - x;     
233                    //            }
234                    //          }
[3]235
[846]236                    size_t oldpos = oldrow + x;
[3]237
[908]238                    // float oldCoeff;
239                    // if((y>=yLim1[xpos])&&(y<=yLim2[xpos])&&
240                    //    (x>=xLim1[ypos])&&(x<=xLim2[ypos])  )
241                    //   oldCoeff = coeffs[oldpos];
242                    // else oldCoeff = 0.;
[3]243
[908]244                    // if(isGood[pos]) wavelet[pos] -= filter[filterpos] * oldCoeff;
245                    // //                 wavelet[pos] -= filter[filterpos] * coeffs[oldpos];
246                    if(isGood[pos])
247                      wavelet[pos] -= filter[filterpos] * coeffs[oldpos];
248
[378]249                    filterpos++;
[3]250
[378]251                  } //-> end of xoffset loop
252                } //-> end of yoffset loop
253              } //-> end of else{ ( from if(!isGood[pos])  )
[3]254       
[378]255            } //-> end of xpos loop
256          } //-> end of ypos loop
[3]257
[378]258          // Need to do this after we've done *all* the convolving
[846]259          for(size_t pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
[3]260
[378]261          // Have found wavelet coeffs for this scale -- now threshold   
[1026]262          if(scale>=MIN_SCALE && scale <=MAX_SCALE){
[849]263            //      findMedianStats(wavelet,goodSize,isGood,mean,sigma);
264            if(par.getFlagRobustStats())
[889]265              mean = findMedian<float>(wavelet,isGood,size);
[849]266            else
[889]267              mean= findMean<float>(wavelet,isGood,size);
[3]268
[1026]269            threshold = mean + SNR_THRESH * originalSigma * sigmaFactors[scale];
[846]270            for(size_t pos=0;pos<size;pos++){
[378]271              if(!isGood[pos]) output[pos] = input[pos];
272              // preserve the Blank pixel values in the output.
273              else if( fabs(wavelet[pos]) > threshold )
274                output[pos] += wavelet[pos];
275            }
[231]276          }
[378]277          spacing *= 2;
[3]278
[378]279        } // END OF LOOP OVER SCALES
[3]280
[846]281        for(size_t pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
[3]282
[849]283        // for(size_t i=0;i<size;i++) residual[i] = input[i] - output[i];
284        // findMedianStats(residual,goodSize,isGood,mean,newsigma);
285        // findMedianStatsDiff(input,output,size,isGood,mean,newsigma);
286        // newsigma = madfmToSigma(newsigma);
287        if(par.getFlagRobustStats())
288          newsigma = madfmToSigma(findMADFMDiff(input,output,isGood,size));
289        else
[889]290          newsigma = findStddevDiff<float>(input,output,isGood,size);
[849]291
[378]292        if(par.isVerbose()) printBackSpace(15);
[3]293
[378]294      } while( (iteration==1) ||
[1026]295               (fabs(oldsigma-newsigma)/newsigma > par.getReconConvergence()) );
[3]296
[378]297      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
[3]298
[908]299      // delete [] xLim1;
300      // delete [] xLim2;
301      // delete [] yLim1;
302      // delete [] yLim2;
[378]303      delete [] filter;
304      delete [] coeffs;
305      delete [] wavelet;
[849]306      // delete [] residual;
[231]307
[378]308    }
309
310    delete [] isGood;
311    delete [] sigmaFactors;
[231]312  }
[378]313   
[3]314}
Note: See TracBrowser for help on using the repository browser.