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

Last change on this file since 1455 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: 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;
[1393]93    std::vector<bool> isGood(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 [] sigmaFactors;
[231]335  }
336
[3]337}
Note: See TracBrowser for help on using the repository browser.