source: trunk/src/ATrous/atrous_3d_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: 12.0 KB
Line 
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// -----------------------------------------------------------------------
28#include <iostream>
29#include <iomanip>
30#include <math.h>
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>
38using Statistics::madfmToSigma;
39
40using std::endl;
41using std::setw;
42
43namespace duchamp
44{
45
46  void atrous3DReconstruct(size_t &xdim, size_t &ydim, size_t &zdim, float *&input,
47                           float *&output, Param &par)
48  {
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.
64
65    const float SNR_THRESH=par.getAtrousCut();
66    unsigned int MIN_SCALE=par.getMinScale();
67    unsigned int MAX_SCALE=par.getMaxScale();
68
69    size_t size = xdim * ydim * zdim;
70    size_t spatialSize = xdim * ydim;
71    size_t mindim = xdim;
72    if (ydim<mindim) mindim = ydim;
73    if (zdim<mindim) mindim = zdim;
74
75    unsigned int numScales = par.filter().getNumScales(mindim);
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    }
84
85    double *sigmaFactors = new double[numScales+1];
86    for(size_t i=0;i<=numScales;i++){
87      if(i<=size_t(par.filter().maxFactor(3)) )
88        sigmaFactors[i] = par.filter().sigmaFactor(3,i);
89      else sigmaFactors[i] = sigmaFactors[i-1] / sqrt(8.);
90    }
91
92    float mean,originalSigma,oldsigma,newsigma;
93    std::vector<bool> isGood(size);
94    size_t goodSize=0;
95    for(size_t pos=0;pos<size;pos++){
96      isGood[pos] = !par.isBlank(input[pos]);
97      if(isGood[pos]) goodSize++;
98    }
99
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.
103
104      for(size_t pos=0;pos<xdim; pos++) output[pos] = input[pos];
105
106      DUCHAMPWARN("3D Reconstruction", "There are no good pixels to be reconstructed -- all are BLANK. Returning input array.\n");
107    }
108    else{
109      // Otherwise, all is good, and we continue.
110
111
112      // findMedianStats(input,goodSize,isGood,originalMean,originalSigma);
113      if(par.getFlagRobustStats())
114        originalSigma = madfmToSigma(findMADFM(input,isGood,size));
115      else
116        originalSigma = findStddev<float>(input,isGood,size);
117
118      float *coeffs = new float[size];
119      float *wavelet = new float[size];
120      // float *residual = new float[size];
121
122      for(size_t pos=0;pos<size;pos++) output[pos]=0.;
123
124      // Define the 3-D (separable) filter, using info from par.filter()
125      size_t filterwidth = par.filter().width();
126      int filterHW = filterwidth/2;
127      size_t fsize = filterwidth*filterwidth*filterwidth;
128      double *filter = new double[fsize];
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++){
132            filter[i +j*filterwidth + k*filterwidth*filterwidth] =
133              par.filter().coeff(i) * par.filter().coeff(j) * par.filter().coeff(k);
134          }
135        }
136      }
137
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;
150
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);
163
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);
174 
175      //        // if(avGapX < mindim) mindim = int(avGapX);
176      //        // if(avGapY < mindim) mindim = int(avGapY);
177      //        // numScales = par.filter().getNumScales(mindim);
178      // }
179
180      float threshold;
181      int iteration=0;
182      newsigma = 1.e9;
183      for(size_t i=0;i<size;i++) output[i] = 0;
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)
189        for(size_t i=0;i<size;i++)  coeffs[i] = input[i] - output[i];
190
191        int spacing = 1;
192        for(unsigned int scale = 1; scale<=numScales; scale++){
193
194          if(par.isVerbose()){
195            std::cout << "Scale ";
196            std::cout << setw(2)<<scale<<" / "<<setw(2)<<numScales;
197            printBackSpace(std::cout,13);
198            std::cout << std::flush;
199          }
200
201          size_t pos = 0;
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++){
205                // loops over each pixel in the image
206
207                wavelet[pos] = coeffs[pos];
208           
209                if(!isGood[pos] )  wavelet[pos] = 0.;
210                else{
211
212                  unsigned int filterpos = 0;
213                  for(int zoffset=-filterHW; zoffset<=filterHW; zoffset++){
214                    long z = zpos + spacing*zoffset;
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                    }
219                    size_t oldchan = z * spatialSize;
220               
221                    for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
222                      long y = long(ypos) + spacing*yoffset;
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                      }
228
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                      // }
239                      size_t oldrow = y * xdim;
240         
241                      for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
242                        long x = long(xpos) + spacing*xoffset;
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;
247                        }
248
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
259                        size_t oldpos = oldchan + oldrow + x;
260
261                        if(isGood[oldpos])
262                          wavelet[pos] -= filter[filterpos]*coeffs[oldpos];
263                     
264                        filterpos++;
265                   
266                      } //-> end of xoffset loop
267                    } //-> end of yoffset loop
268                  } //-> end of zoffset loop
269                } //-> end of else{ ( from if(!isGood[pos])  )
270           
271                pos++;
272              } //-> end of xpos loop
273            } //-> end of ypos loop
274          } //-> end of zpos loop
275
276          // Need to do this after we've done *all* the convolving
277          for(size_t pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
278
279          // Have found wavelet coeffs for this scale -- now threshold
280          if(scale>=MIN_SCALE && scale <=MAX_SCALE){
281            if(par.getFlagRobustStats())
282              // findMedianStats(wavelet,size,isGood,mean,sigma);
283              mean = findMedian<float>(wavelet,isGood,size);
284            else
285              //findNormalStats(wavelet,size,isGood,mean,sigma);
286              mean = findMean<float>(wavelet,isGood,size);
287             
288            threshold = mean + SNR_THRESH*originalSigma*sigmaFactors[scale];
289            for(size_t pos=0;pos<size;pos++){
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              }
298            }
299          }
300 
301          spacing *= 2;  // double the scale of the filter.
302
303        } //-> end of scale loop
304
305        for(size_t pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
306
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
314          newsigma = findStddevDiff<float>(input,output,isGood,size);
315
316        if(par.isVerbose()) printBackSpace(std::cout,15);
317
318      } while( (iteration==1) ||
319               (fabs(oldsigma-newsigma)/newsigma > par.getReconConvergence()) );
320
321      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
322
323      // delete [] xLim1;
324      // delete [] xLim2;
325      // delete [] yLim1;
326      // delete [] yLim2;
327      delete [] filter;
328      // delete [] residual;
329      delete [] coeffs;
330      delete [] wavelet;
331
332    }
333
334    delete [] sigmaFactors;
335  }
336
337}
Note: See TracBrowser for help on using the repository browser.