source: trunk/src/ATrous/atrous_2d_reconstruct.cc @ 1441

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