source: trunk/src/ATrous/atrous_1d_reconstruct.cc @ 1026

Last change on this file since 1026 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: 7.6 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// atrous_1d_reconstruct.cc: 1-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>
[348]29#include <sstream>
[3]30#include <iomanip>
31#include <math.h>
[393]32#include <duchamp/duchamp.hh>
33#include <duchamp/param.hh>
34#include <duchamp/Utils/utils.hh>
35#include <duchamp/Utils/feedback.hh>
36#include <duchamp/ATrous/atrous.hh>
37#include <duchamp/ATrous/filter.hh>
38#include <duchamp/Utils/Statistics.hh>
[190]39using Statistics::madfmToSigma;
[3]40
[378]41namespace duchamp
[3]42{
[86]43
[887]44  void atrous1DReconstruct(size_t &xdim, float *&input, float *&output, Param &par)
[378]45  {
[528]46    ///  A routine that uses the a trous wavelet method to reconstruct a
47    ///   1-dimensional spectrum.
48    ///  The Param object "par" contains all necessary info about the filter and
49    ///   reconstruction parameters.
50    ///
51    ///  If all pixels are BLANK (and we are testing for BLANKs), the
52    ///  reconstruction will simply give BLANKs back, so we return the
53    ///  input array as the output array.
54    ///
55    ///  \param xdim The length of the spectrum.
56    ///  \param input The input spectrum.
57    ///  \param output The returned reconstructed spectrum. This array needs to
58    ///    be declared beforehand.
59    ///  \param par The Param set.
[3]60
[378]61    const float SNR_THRESH=par.getAtrousCut();
[1026]62    unsigned int MIN_SCALE=par.getMinScale();
63    unsigned int MAX_SCALE=par.getMaxScale();
64    static bool firstTime = true;  // need this static in case we do two reconstructions - e.g. baseline subtraction
[3]65
[884]66    unsigned int numScales = par.filter().getNumScales(xdim);
[1026]67    if((MAX_SCALE>0)&&(MAX_SCALE<=numScales))
68      MAX_SCALE = std::min(MAX_SCALE,numScales);
[378]69    else{
[1026]70      if((firstTime)&&(MAX_SCALE!=0)){
[378]71        firstTime=false;
[1026]72        DUCHAMPWARN("Reading parameters","The requested value of the parameter scaleMax, \"" << par.getMaxScale() << "\" is outside the allowed range (1-"<< numScales <<") -- setting to " << numScales);
[378]73      }
[1026]74      MAX_SCALE = numScales;
75      par.setMaxScale(MAX_SCALE);
[378]76    }
77    double *sigmaFactors = new double[numScales+1];
[846]78    for(size_t i=0;i<=numScales;i++){
[378]79      if(i<=par.filter().maxFactor(1))
80        sigmaFactors[i] = par.filter().sigmaFactor(1,i);
81      else sigmaFactors[i] = sigmaFactors[i-1] / sqrt(2.);
82    }
[3]83
[894]84    float mean,originalSigma,oldsigma,newsigma;
[378]85    bool *isGood = new bool[xdim];
[846]86    size_t goodSize=0;
87    for(size_t pos=0;pos<xdim;pos++) {
[378]88      isGood[pos] = !par.isBlank(input[pos]);
89      if(isGood[pos]) goodSize++;
90    }
[3]91
[378]92    if(goodSize == 0){
93      // There are no good pixels -- everything is BLANK for some reason.
94      // Return the input array as the output.
[3]95
[846]96      for(size_t pos=0;pos<xdim; pos++) output[pos] = input[pos];
[3]97
[378]98    }
99    else{
100      // Otherwise, all is good, and we continue.
[3]101
102
[378]103      float *coeffs = new float[xdim];
104      float *wavelet = new float[xdim];
[849]105      // float *residual = new float[xdim];
[3]106
[846]107      for(size_t pos=0;pos<xdim;pos++) output[pos]=0.;
[3]108
[378]109      int filterHW = par.filter().width()/2;
110      double *filter = new double[par.filter().width()];
[846]111      for(size_t i=0;i<par.filter().width();i++) filter[i] = par.filter().coeff(i);
[231]112
113
[378]114      // No trimming done in 1D case.
[3]115
[1026]116      float threshold;
[378]117      int iteration=0;
118      newsigma = 1.e9;
119      do{
[231]120        if(par.isVerbose()) {
[378]121          std::cout << "Iteration #"<<++iteration<<":";
122          printSpace(13);
[231]123        }
[378]124        // first, get the value of oldsigma and set it to the previous
125        //   newsigma value
126        oldsigma = newsigma;
127        // all other times round, we are transforming the residual array
[846]128        for(size_t i=0;i<xdim;i++)  coeffs[i] = input[i] - output[i];
[378]129   
[849]130        // findMedianStats(input,xdim,isGood,originalMean,originalSigma);
131        // originalSigma = madfmToSigma(originalSigma);
132        if(par.getFlagRobustStats())
133          originalSigma = madfmToSigma(findMADFM(input,isGood,xdim));
134        else
[889]135          originalSigma = findStddev<float>(input,isGood,xdim);
[231]136
[378]137        int spacing = 1;
[846]138        for(unsigned int scale = 1; scale<=numScales; scale++){
[231]139
[378]140          if(par.isVerbose()) {
141            std::cout << "Scale " << std::setw(2) << scale
142                      << " /"     << std::setw(2) << numScales <<std::flush;
143          }
144
[884]145          for(size_t xpos = 0; xpos<xdim; xpos++){
[378]146            // loops over each pixel in the image
147
[884]148            wavelet[xpos] = coeffs[xpos];
[3]149       
[884]150            if(!isGood[xpos] )  wavelet[xpos] = 0.;
[378]151            else{
[3]152
[378]153              for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
[846]154                long x = xpos + spacing*xoffset;
[3]155
[846]156                while((x<0)||(x>=long(xdim))){
[378]157                  // boundary conditions are reflection.
158                  if(x<0) x = 0 - x;
[846]159                  else if(x>=long(xdim)) x = 2*(xdim-1) - x;
[378]160                }
[3]161
[846]162                size_t filterpos = (xoffset+filterHW);
163                size_t oldpos = x;
[3]164
[378]165                if(isGood[oldpos])
[884]166                  wavelet[xpos] -= filter[filterpos]*coeffs[oldpos];
[3]167             
[378]168              } //-> end of xoffset loop
[884]169            } //-> end of else{ ( from if(!isGood[xpos])  )
[3]170           
[378]171          } //-> end of xpos loop
[3]172
[378]173          // Need to do this after we've done *all* the convolving
[846]174          for(size_t pos=0;pos<xdim;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
[3]175
[378]176          // Have found wavelet coeffs for this scale -- now threshold
[1026]177          if(scale>=MIN_SCALE && scale <=MAX_SCALE){
[849]178            //      findMedianStats(wavelet,xdim,isGood,mean,sigma);
179            if(par.getFlagRobustStats())
[889]180              mean = findMedian<float>(wavelet,isGood,xdim);
[849]181            else
[889]182              mean = findMean<float>(wavelet,isGood,xdim);
[1026]183
184            threshold = mean+SNR_THRESH*originalSigma*sigmaFactors[scale];
[846]185            for(size_t pos=0;pos<xdim;pos++){
[378]186              // preserve the Blank pixel values in the output.
187              if(!isGood[pos]) output[pos] = input[pos];
[1026]188              else if( fabs(wavelet[pos]) > threshold )
[378]189                output[pos] += wavelet[pos];
190            }
[231]191          }
[3]192 
[378]193          spacing *= 2;
[3]194
[378]195        } //-> end of scale loop
[3]196
[378]197        // Only add the final smoothed array if we are doing *all* the scales.
198        if(numScales == par.filter().getNumScales(xdim))
[846]199          for(size_t pos=0;pos<xdim;pos++)
[378]200            if(isGood[pos]) output[pos] += coeffs[pos];
[3]201
[849]202        // for(size_t pos=0;pos<xdim;pos++) residual[pos]=input[pos]-output[pos];
203        // findMedianStats(residual,xdim,isGood,mean,newsigma);
204        // newsigma = madfmToSigma(newsigma);
205        if(par.getFlagRobustStats())
206          newsigma = madfmToSigma(findMADFMDiff(input,output,isGood,xdim));
207        else
[889]208          newsigma = findStddevDiff<float>(input,output,isGood,xdim);
[3]209
[378]210        if(par.isVerbose()) printBackSpace(26);
[3]211
[378]212      } while( (iteration==1) ||
[1026]213               (fabs(oldsigma-newsigma)/newsigma > par.getReconConvergence()) );
[3]214
[378]215      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
[3]216
[378]217      delete [] filter;
[849]218      // delete [] residual;
[650]219      delete [] wavelet;
[378]220      delete [] coeffs;
[231]221
[378]222    }
223
224    delete [] isGood;
225    delete [] sigmaFactors;
[231]226  }
227
[3]228}
Note: See TracBrowser for help on using the repository browser.