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

Last change on this file since 890 was 889, checked in by MatthewWhiting, 12 years ago

Making our choice of template in the statistics functions explicit

File size: 10.8 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    size_t size = xdim * ydim * zdim;
66    size_t spatialSize = xdim * ydim;
67    unsigned long mindim = xdim;
68    if (ydim<mindim) mindim = ydim;
69    if (zdim<mindim) mindim = zdim;
70    unsigned int numScales = par.filter().getNumScales(mindim);
71
72    double *sigmaFactors = new double[numScales+1];
73    for(size_t i=0;i<=numScales;i++){
74      if(i<=size_t(par.filter().maxFactor(3)) )
75        sigmaFactors[i] = par.filter().sigmaFactor(3,i);
76      else sigmaFactors[i] = sigmaFactors[i-1] / sqrt(8.);
77    }
78
79    float mean,sigma,originalSigma,originalMean,oldsigma,newsigma;
80    bool *isGood = new bool[size];
81    size_t goodSize=0;
82    for(size_t pos=0;pos<size;pos++){
83      isGood[pos] = !par.isBlank(input[pos]);
84      if(isGood[pos]) goodSize++;
85    }
86
87    if(goodSize == 0){
88      // There are no good pixels -- everything is BLANK for some reason.
89      // Return the input array as the output, and give a warning message.
90
91      for(size_t pos=0;pos<xdim; pos++) output[pos] = input[pos];
92
93      duchampWarning("3D Reconstruction",
94                     "There are no good pixels to be reconstructed -- all are BLANK.\nPerhaps you need to try this with flagTrim=false.\nReturning input array.\n");
95    }
96    else{
97      // Otherwise, all is good, and we continue.
98
99
100      // findMedianStats(input,goodSize,isGood,originalMean,originalSigma);
101      if(par.getFlagRobustStats())
102        originalSigma = madfmToSigma(findMADFM(input,isGood,size));
103      else
104        originalSigma = findStddev<float>(input,isGood,size);
105
106      float *coeffs = new float[size];
107      float *wavelet = new float[size];
108      // float *residual = new float[size];
109
110      for(size_t pos=0;pos<size;pos++) output[pos]=0.;
111
112      // Define the 3-D (separable) filter, using info from par.filter()
113      size_t filterwidth = par.filter().width();
114      int filterHW = filterwidth/2;
115      size_t fsize = filterwidth*filterwidth*filterwidth;
116      double *filter = new double[fsize];
117      for(size_t i=0;i<filterwidth;i++){
118        for(size_t j=0;j<filterwidth;j++){
119          for(size_t k=0;k<filterwidth;k++){
120            filter[i +j*filterwidth + k*filterwidth*filterwidth] =
121              par.filter().coeff(i) * par.filter().coeff(j) * par.filter().coeff(k);
122          }
123        }
124      }
125
126      // Locating the borders of the image -- ignoring BLANK pixels
127      //  Only do this if flagBlankPix is true.
128      //  Otherwise use the full range of x and y.
129      //  No trimming is done in the z-direction at this point.
130      long *xLim1 = new long[ydim];
131      for(size_t i=0;i<ydim;i++) xLim1[i] = 0;
132      long *xLim2 = new long[ydim];
133      for(size_t i=0;i<ydim;i++) xLim2[i] = xdim-1;
134      long *yLim1 = new long[xdim];
135      for(size_t i=0;i<xdim;i++) yLim1[i] = 0;
136      long *yLim2 = new long[xdim];
137      for(size_t i=0;i<xdim;i++) yLim2[i] = ydim-1;
138
139      if(par.getFlagBlankPix()){
140        float avGapX = 0, avGapY = 0;
141        for(size_t row=0;row<ydim;row++){
142          size_t ct1 = 0;
143          size_t ct2 = xdim - 1;
144          while((ct1<ct2)&&(par.isBlank(input[row*xdim+ct1]))) ct1++;
145          while((ct2>ct1)&&(par.isBlank(input[row*xdim+ct2]))) ct2--;
146          xLim1[row] = ct1;
147          xLim2[row] = ct2;
148          avGapX += ct2 - ct1 + 1;
149        }
150        avGapX /= float(ydim);
151
152        for(size_t col=0;col<xdim;col++){
153          size_t ct1=0;
154          size_t ct2=ydim-1;
155          while((ct1<ct2)&&(par.isBlank(input[col+xdim*ct1]))) ct1++;
156          while((ct2>ct1)&&(par.isBlank(input[col+xdim*ct2]))) ct2--;
157          yLim1[col] = ct1;
158          yLim2[col] = ct2;
159          avGapY += ct2 - ct1 + 1;
160        }
161        avGapY /= float(xdim);
162 
163        // if(avGapX < mindim) mindim = int(avGapX);
164        // if(avGapY < mindim) mindim = int(avGapY);
165        // numScales = par.filter().getNumScales(mindim);
166      }
167
168      float threshold;
169      int iteration=0;
170      newsigma = 1.e9;
171      for(size_t i=0;i<size;i++) output[i] = 0;
172      do{
173        if(par.isVerbose()) std::cout << "Iteration #"<<setw(2)<<++iteration<<": ";
174        // first, get the value of oldsigma, set it to the previous newsigma value
175        oldsigma = newsigma;
176        // we are transforming the residual array (input array first time around)
177        for(size_t i=0;i<size;i++)  coeffs[i] = input[i] - output[i];
178
179        int spacing = 1;
180        for(unsigned int scale = 1; scale<=numScales; scale++){
181
182          if(par.isVerbose()){
183            std::cout << "Scale ";
184            std::cout << setw(2)<<scale<<" / "<<setw(2)<<numScales;
185            printBackSpace(13);
186            std::cout << std::flush;
187          }
188
189          size_t pos = 0;
190          for(unsigned long zpos = 0; zpos<zdim; zpos++){
191            for(unsigned long ypos = 0; ypos<ydim; ypos++){
192              for(unsigned long xpos = 0; xpos<xdim; xpos++){
193                // loops over each pixel in the image
194
195                wavelet[pos] = coeffs[pos];
196           
197                if(!isGood[pos] )  wavelet[pos] = 0.;
198                else{
199
200                  unsigned int filterpos = -1;
201                  for(int zoffset=-filterHW; zoffset<=filterHW; zoffset++){
202                    long z = zpos + spacing*zoffset;
203                    if(z<0) z = -z;                 // boundary conditions are
204                    if(z>=long(zdim)) z = 2*(zdim-1) - z; //    reflection.
205               
206                    size_t oldchan = z * spatialSize;
207               
208                    for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
209                      long y = long(ypos) + spacing*yoffset;
210
211                      // Boundary conditions -- assume reflection at boundaries.
212                      // Use limits as calculated above
213                      if(yLim1[xpos]!=yLim2[xpos]){
214                        // if these are equal we will get into an infinite loop
215                        while((y<yLim1[xpos])||(y>yLim2[xpos])){
216                        // std::cerr << y << " " <<spacing << " " << yoffset << " " << ypos << " " << xpos << " " << yLim1[xpos] << " " << yLim2[xpos] << "\n";
217                          if(y<yLim1[xpos]) y = 2*yLim1[xpos] - y;     
218                          else if(y>yLim2[xpos]) y = 2*yLim2[xpos] - y;     
219                        }
220                      }
221                      size_t oldrow = y * xdim;
222         
223                      for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
224                        long x = long(xpos) + spacing*xoffset;
225
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
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                        }
235
236                        size_t oldpos = oldchan + oldrow + x;
237
238                        filterpos++;
239                   
240                        if(isGood[oldpos])
241                          wavelet[pos] -= filter[filterpos]*coeffs[oldpos];
242                     
243                      } //-> end of xoffset loop
244                    } //-> end of yoffset loop
245                  } //-> end of zoffset loop
246                } //-> end of else{ ( from if(!isGood[pos])  )
247           
248                pos++;
249              } //-> end of xpos loop
250            } //-> end of ypos loop
251          } //-> end of zpos loop
252
253          // Need to do this after we've done *all* the convolving
254          for(size_t pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
255
256          // Have found wavelet coeffs for this scale -- now threshold
257          if(scale>=par.getMinScale()){
258            if(par.getFlagRobustStats())
259              // findMedianStats(wavelet,size,isGood,mean,sigma);
260              mean = findMedian<float>(wavelet,isGood,size);
261            else
262              //findNormalStats(wavelet,size,isGood,mean,sigma);
263              mean = findMean<float>(wavelet,isGood,size);
264             
265            threshold = mean +
266              par.getAtrousCut()*originalSigma*sigmaFactors[scale];
267            for(size_t pos=0;pos<size;pos++){
268              if(!isGood[pos]){
269                output[pos] = input[pos];
270                // this preserves the Blank pixel values in the output.
271              }
272              else if( fabs(wavelet[pos]) > threshold ){
273                output[pos] += wavelet[pos];
274                // only add to the output if the wavelet coefficient is significant
275              }
276            }
277          }
278 
279          spacing *= 2;  // double the scale of the filter.
280
281        } //-> end of scale loop
282
283        for(size_t pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
284
285        // for(size_t i=0;i<size;i++) residual[i] = input[i] - output[i];
286        // findMedianStats(residual,goodSize,isGood,mean,newsigma);
287        // findMedianStatsDiff(input,output,goodSize,isGood,mean,newsigma);
288        // newsigma = madfmToSigma(newsigma);
289        if(par.getFlagRobustStats())
290          newsigma = madfmToSigma(findMADFMDiff(input,output,isGood,size));
291        else
292          newsigma = findStddevDiff<float>(input,output,isGood,size);
293
294        if(par.isVerbose()) printBackSpace(15);
295
296      } while( (iteration==1) ||
297               (fabs(oldsigma-newsigma)/newsigma > reconTolerance) );
298
299      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
300
301      delete [] xLim1;
302      delete [] xLim2;
303      delete [] yLim1;
304      delete [] yLim2;
305      delete [] filter;
306      // delete [] residual;
307      delete [] coeffs;
308      delete [] wavelet;
309
310    }
311
312    delete [] isGood;
313    delete [] sigmaFactors;
314  }
315
316}
Note: See TracBrowser for help on using the repository browser.