source: trunk/src/ATrous/atrous_2d_reconstruct.cc

Last change on this file was 1393, checked in by MatthewWhiting, 10 years ago

A large changeset that moves all use of bool arrays (ie. bool *) to std::vector<bool>. This will be a bit safer, plus potentially cheaper in memory usage. Interfaces to all stats functions with masks have changed accordingly, as well as the Gaussian smoothing functions and some spectral utility functions.

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;
[1393]87    std::vector<bool> isGood(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<<":";
[1384]171          printBackSpace(std::cout,13);
[231]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;
[1384]186            printBackSpace(std::cout,13);
[378]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
[1384]292        if(par.isVerbose()) printBackSpace(std::cout,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 [] sigmaFactors;
[231]311  }
[378]312   
[3]313}
Note: See TracBrowser for help on using the repository browser.