source: trunk/src/ATrous/atrous_3d_reconstruct.cc @ 1391

Last change on this file since 1391 was 1384, checked in by MatthewWhiting, 10 years ago

A refactoring of the progress bar class, improving the code and adding a percentage done at the end of the bar (for clarity). Have also made some changes to other code that call the printing commands directly.

File size: 12.0 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// atrous_3d_reconstruct.cc: 3-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
40using std::endl;
41using std::setw;
42
[378]43namespace duchamp
[3]44{
[86]45
[887]46  void atrous3DReconstruct(size_t &xdim, size_t &ydim, size_t &zdim, float *&input,
[378]47                           float *&output, Param &par)
48  {
[528]49    ///  A routine that uses the a trous wavelet method to reconstruct a
50    ///   3-dimensional image cube.
51    ///  The Param object "par" contains all necessary info about the filter and
52    ///   reconstruction parameters.
53    ///
54    ///  If there are no non-BLANK pixels (and we are testing for
55    ///  BLANKs), the reconstruction cannot be done, so we return the
56    ///  input array as the output array and give a warning message.
57    ///
58    ///  \param xdim The length of the x-axis.
59    ///  \param ydim The length of the y-axis.
60    ///  \param zdim The length of the z-axis.
61    ///  \param input The input spectrum.
62    ///  \param output The returned reconstructed spectrum. This array needs to be declared beforehand.
63    ///  \param par The Param set.
[52]64
[1026]65    const float SNR_THRESH=par.getAtrousCut();
66    unsigned int MIN_SCALE=par.getMinScale();
67    unsigned int MAX_SCALE=par.getMaxScale();
68
[846]69    size_t size = xdim * ydim * zdim;
70    size_t spatialSize = xdim * ydim;
[1026]71    size_t mindim = xdim;
[378]72    if (ydim<mindim) mindim = ydim;
73    if (zdim<mindim) mindim = zdim;
[1026]74
[846]75    unsigned int numScales = par.filter().getNumScales(mindim);
[1026]76    if((MAX_SCALE>0)&&(MAX_SCALE<=numScales))
77      MAX_SCALE = std::min(MAX_SCALE,numScales);
78    else{
79      if(MAX_SCALE!=0)
80        DUCHAMPWARN("Reading parameters","The requested value of the parameter scaleMax, \"" << par.getMaxScale() << "\" is outside the allowed range (1-"<< numScales <<") -- setting to " << numScales);
81      MAX_SCALE = numScales;
82      par.setMaxScale(MAX_SCALE);
83    }
[3]84
[378]85    double *sigmaFactors = new double[numScales+1];
[846]86    for(size_t i=0;i<=numScales;i++){
87      if(i<=size_t(par.filter().maxFactor(3)) )
[378]88        sigmaFactors[i] = par.filter().sigmaFactor(3,i);
89      else sigmaFactors[i] = sigmaFactors[i-1] / sqrt(8.);
90    }
[52]91
[894]92    float mean,originalSigma,oldsigma,newsigma;
[378]93    bool *isGood = new bool[size];
[846]94    size_t goodSize=0;
95    for(size_t pos=0;pos<size;pos++){
[378]96      isGood[pos] = !par.isBlank(input[pos]);
97      if(isGood[pos]) goodSize++;
98    }
[3]99
[378]100    if(goodSize == 0){
101      // There are no good pixels -- everything is BLANK for some reason.
102      // Return the input array as the output, and give a warning message.
[3]103
[846]104      for(size_t pos=0;pos<xdim; pos++) output[pos] = input[pos];
[3]105
[913]106      DUCHAMPWARN("3D Reconstruction", "There are no good pixels to be reconstructed -- all are BLANK. Returning input array.\n");
[378]107    }
108    else{
109      // Otherwise, all is good, and we continue.
[231]110
111
[849]112      // findMedianStats(input,goodSize,isGood,originalMean,originalSigma);
113      if(par.getFlagRobustStats())
114        originalSigma = madfmToSigma(findMADFM(input,isGood,size));
115      else
[889]116        originalSigma = findStddev<float>(input,isGood,size);
[231]117
[378]118      float *coeffs = new float[size];
119      float *wavelet = new float[size];
[849]120      // float *residual = new float[size];
[231]121
[846]122      for(size_t pos=0;pos<size;pos++) output[pos]=0.;
[378]123
124      // Define the 3-D (separable) filter, using info from par.filter()
[846]125      size_t filterwidth = par.filter().width();
[378]126      int filterHW = filterwidth/2;
[846]127      size_t fsize = filterwidth*filterwidth*filterwidth;
[378]128      double *filter = new double[fsize];
[846]129      for(size_t i=0;i<filterwidth;i++){
130        for(size_t j=0;j<filterwidth;j++){
131          for(size_t k=0;k<filterwidth;k++){
[378]132            filter[i +j*filterwidth + k*filterwidth*filterwidth] =
133              par.filter().coeff(i) * par.filter().coeff(j) * par.filter().coeff(k);
134          }
[231]135        }
[3]136      }
137
[908]138      // // Locating the borders of the image -- ignoring BLANK pixels
139      // //  Only do this if flagBlankPix is true.
140      // //  Otherwise use the full range of x and y.
141      // //  No trimming is done in the z-direction at this point.
142      // long *xLim1 = new long[ydim];
143      // for(size_t i=0;i<ydim;i++) xLim1[i] = 0;
144      // long *xLim2 = new long[ydim];
145      // for(size_t i=0;i<ydim;i++) xLim2[i] = xdim-1;
146      // long *yLim1 = new long[xdim];
147      // for(size_t i=0;i<xdim;i++) yLim1[i] = 0;
148      // long *yLim2 = new long[xdim];
149      // for(size_t i=0;i<xdim;i++) yLim2[i] = ydim-1;
[3]150
[908]151      // if(par.getFlagBlankPix()){
152      //        float avGapX = 0, avGapY = 0;
153      //        for(size_t row=0;row<ydim;row++){
154      //          size_t ct1 = 0;
155      //          size_t ct2 = xdim - 1;
156      //          while((ct1<ct2)&&(par.isBlank(input[row*xdim+ct1]))) ct1++;
157      //          while((ct2>ct1)&&(par.isBlank(input[row*xdim+ct2]))) ct2--;
158      //          xLim1[row] = ct1;
159      //          xLim2[row] = ct2;
160      //          avGapX += ct2 - ct1 + 1;
161      //        }
162      //        avGapX /= float(ydim);
[52]163
[908]164      //        for(size_t col=0;col<xdim;col++){
165      //          size_t ct1=0;
166      //          size_t ct2=ydim-1;
167      //          while((ct1<ct2)&&(par.isBlank(input[col+xdim*ct1]))) ct1++;
168      //          while((ct2>ct1)&&(par.isBlank(input[col+xdim*ct2]))) ct2--;
169      //          yLim1[col] = ct1;
170      //          yLim2[col] = ct2;
171      //          avGapY += ct2 - ct1 + 1;
172      //        }
173      //        avGapY /= float(xdim);
[378]174 
[908]175      //        // if(avGapX < mindim) mindim = int(avGapX);
176      //        // if(avGapY < mindim) mindim = int(avGapY);
177      //        // numScales = par.filter().getNumScales(mindim);
178      // }
[3]179
[378]180      float threshold;
181      int iteration=0;
182      newsigma = 1.e9;
[846]183      for(size_t i=0;i<size;i++) output[i] = 0;
[378]184      do{
185        if(par.isVerbose()) std::cout << "Iteration #"<<setw(2)<<++iteration<<": ";
186        // first, get the value of oldsigma, set it to the previous newsigma value
187        oldsigma = newsigma;
188        // we are transforming the residual array (input array first time around)
[846]189        for(size_t i=0;i<size;i++)  coeffs[i] = input[i] - output[i];
[3]190
[378]191        int spacing = 1;
[846]192        for(unsigned int scale = 1; scale<=numScales; scale++){
[3]193
[378]194          if(par.isVerbose()){
195            std::cout << "Scale ";
196            std::cout << setw(2)<<scale<<" / "<<setw(2)<<numScales;
[1384]197            printBackSpace(std::cout,13);
[378]198            std::cout << std::flush;
199          }
[3]200
[884]201          size_t pos = 0;
[846]202          for(unsigned long zpos = 0; zpos<zdim; zpos++){
203            for(unsigned long ypos = 0; ypos<ydim; ypos++){
204              for(unsigned long xpos = 0; xpos<xdim; xpos++){
[378]205                // loops over each pixel in the image
[3]206
[378]207                wavelet[pos] = coeffs[pos];
[3]208           
[378]209                if(!isGood[pos] )  wavelet[pos] = 0.;
210                else{
[3]211
[908]212                  unsigned int filterpos = 0;
[378]213                  for(int zoffset=-filterHW; zoffset<=filterHW; zoffset++){
[846]214                    long z = zpos + spacing*zoffset;
[908]215                    while((z<0)||(z>=long(zdim))){
216                      if(z<0) z = -z;                 // boundary conditions are
217                      if(z>=long(zdim)) z = 2*(zdim-1) - z; //    reflection.
218                    }
[846]219                    size_t oldchan = z * spatialSize;
[103]220               
[378]221                    for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
[846]222                      long y = long(ypos) + spacing*yoffset;
[908]223                      while((y<0)||(y>=long(ydim))){
224                        // boundary conditions are reflection.
225                        if(y<0) y = 0 - y;
226                        else if(y>=long(ydim)) y = 2*(ydim-1) - y;
227                      }
[103]228
[908]229                      // // Boundary conditions -- assume reflection at boundaries.
230                      // // Use limits as calculated above
231                      // if(yLim1[xpos]!=yLim2[xpos]){
232                      //        // if these are equal we will get into an infinite loop
233                      //        while((y<yLim1[xpos])||(y>yLim2[xpos])){
234                      //        // std::cerr << y << " " <<spacing << " " << yoffset << " " << ypos << " " << xpos << " " << yLim1[xpos] << " " << yLim2[xpos] << "\n";
235                      //          if(y<yLim1[xpos]) y = 2*yLim1[xpos] - y;     
236                      //          else if(y>yLim2[xpos]) y = 2*yLim2[xpos] - y;     
237                      //        }
238                      // }
[846]239                      size_t oldrow = y * xdim;
[378]240         
241                      for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
[846]242                        long x = long(xpos) + spacing*xoffset;
[908]243                        while((x<0)||(x>=long(xdim))){
244                          // boundary conditions are reflection.
245                          if(x<0) x = 0 - x;
246                          else if(x>=long(xdim)) x = 2*(xdim-1) - x;
[378]247                        }
[231]248
[908]249                        // // Boundary conditions -- assume reflection at boundaries.
250                        // // Use limits as calculated above
251                        // if(xLim1[ypos]!=xLim2[ypos]){
252                        //   // if these are equal we will get into an infinite loop
253                        //   while((x<xLim1[ypos])||(x>xLim2[ypos])){
254                        //     if(x<xLim1[ypos]) x = 2*xLim1[ypos] - x;     
255                        //     else if(x>xLim2[ypos]) x = 2*xLim2[ypos] - x;     
256                        //   }
257                        // }
258
[846]259                        size_t oldpos = oldchan + oldrow + x;
[378]260
261                        if(isGood[oldpos])
262                          wavelet[pos] -= filter[filterpos]*coeffs[oldpos];
[3]263                     
[908]264                        filterpos++;
265                   
[378]266                      } //-> end of xoffset loop
267                    } //-> end of yoffset loop
268                  } //-> end of zoffset loop
269                } //-> end of else{ ( from if(!isGood[pos])  )
[3]270           
[884]271                pos++;
[378]272              } //-> end of xpos loop
273            } //-> end of ypos loop
274          } //-> end of zpos loop
[3]275
[378]276          // Need to do this after we've done *all* the convolving
[846]277          for(size_t pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
[3]278
[378]279          // Have found wavelet coeffs for this scale -- now threshold
[1026]280          if(scale>=MIN_SCALE && scale <=MAX_SCALE){
[849]281            if(par.getFlagRobustStats())
282              // findMedianStats(wavelet,size,isGood,mean,sigma);
[889]283              mean = findMedian<float>(wavelet,isGood,size);
[849]284            else
285              //findNormalStats(wavelet,size,isGood,mean,sigma);
[889]286              mean = findMean<float>(wavelet,isGood,size);
[849]287             
[1026]288            threshold = mean + SNR_THRESH*originalSigma*sigmaFactors[scale];
[846]289            for(size_t pos=0;pos<size;pos++){
[378]290              if(!isGood[pos]){
291                output[pos] = input[pos];
292                // this preserves the Blank pixel values in the output.
293              }
294              else if( fabs(wavelet[pos]) > threshold ){
295                output[pos] += wavelet[pos];
296                // only add to the output if the wavelet coefficient is significant
297              }
[231]298            }
[86]299          }
[3]300 
[378]301          spacing *= 2;  // double the scale of the filter.
[3]302
[378]303        } //-> end of scale loop
[3]304
[846]305        for(size_t pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
[3]306
[849]307        // for(size_t i=0;i<size;i++) residual[i] = input[i] - output[i];
308        // findMedianStats(residual,goodSize,isGood,mean,newsigma);
309        // findMedianStatsDiff(input,output,goodSize,isGood,mean,newsigma);
310        // newsigma = madfmToSigma(newsigma);
311        if(par.getFlagRobustStats())
312          newsigma = madfmToSigma(findMADFMDiff(input,output,isGood,size));
313        else
[889]314          newsigma = findStddevDiff<float>(input,output,isGood,size);
[3]315
[1384]316        if(par.isVerbose()) printBackSpace(std::cout,15);
[3]317
[378]318      } while( (iteration==1) ||
[1026]319               (fabs(oldsigma-newsigma)/newsigma > par.getReconConvergence()) );
[3]320
[378]321      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
[3]322
[908]323      // delete [] xLim1;
324      // delete [] xLim2;
325      // delete [] yLim1;
326      // delete [] yLim2;
[378]327      delete [] filter;
[849]328      // delete [] residual;
[378]329      delete [] coeffs;
330      delete [] wavelet;
[231]331
[378]332    }
333
334    delete [] isGood;
335    delete [] sigmaFactors;
[231]336  }
337
[3]338}
Note: See TracBrowser for help on using the repository browser.