source: tags/release-1.1.7/src/ATrous/atrous_3d_reconstruct.cc @ 1455

Last change on this file since 1455 was 528, checked in by MatthewWhiting, 15 years ago

Changing the documentation comments to match the askapsoft style. Also have split ChanMap? and Object3D into separate files.

File size: 10.2 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(long &xdim, long &ydim, long &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    long size = xdim * ydim * zdim;
66    long spatialSize = xdim * ydim;
67    long mindim = xdim;
68    if (ydim<mindim) mindim = ydim;
69    if (zdim<mindim) mindim = zdim;
70    int numScales = par.filter().getNumScales(mindim);
71
72    double *sigmaFactors = new double[numScales+1];
73    for(int i=0;i<=numScales;i++){
74      if(i<=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    int goodSize=0;
82    for(int 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(int 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      float *array = new float[size];
101      goodSize=0;
102      for(int i=0;i<size;i++) if(isGood[i]) array[goodSize++] = input[i];
103      findMedianStats(array,goodSize,originalMean,originalSigma);
104      originalSigma = madfmToSigma(originalSigma);
105      delete [] array;
106
107      float *coeffs = new float[size];
108      float *wavelet = new float[size];
109
110      for(int pos=0;pos<size;pos++) output[pos]=0.;
111
112      // Define the 3-D (separable) filter, using info from par.filter()
113      int filterwidth = par.filter().width();
114      int filterHW = filterwidth/2;
115      int fsize = filterwidth*filterwidth*filterwidth;
116      double *filter = new double[fsize];
117      for(int i=0;i<filterwidth;i++){
118        for(int j=0;j<filterwidth;j++){
119          for(int 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      int *xLim1 = new int[ydim];
131      for(int i=0;i<ydim;i++) xLim1[i] = 0;
132      int *xLim2 = new int[ydim];
133      for(int i=0;i<ydim;i++) xLim2[i] = xdim-1;
134      int *yLim1 = new int[xdim];
135      for(int i=0;i<xdim;i++) yLim1[i] = 0;
136      int *yLim2 = new int[xdim];
137      for(int i=0;i<xdim;i++) yLim2[i] = ydim-1;
138
139      if(par.getFlagBlankPix()){
140        float avGapX = 0, avGapY = 0;
141        for(int row=0;row<ydim;row++){
142          int ct1 = 0;
143          int 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(int col=0;col<xdim;col++){
153          int ct1=0;
154          int 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        mindim = int(avGapX);
164        if(avGapY < avGapX) mindim = int(avGapY);
165        numScales = par.filter().getNumScales(mindim);
166      }
167
168      float threshold;
169      int iteration=0;
170      newsigma = 1.e9;
171      for(int 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(int i=0;i<size;i++)  coeffs[i] = input[i] - output[i];
178
179        int spacing = 1;
180        for(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          int pos = -1;
190          for(int zpos = 0; zpos<zdim; zpos++){
191            for(int ypos = 0; ypos<ydim; ypos++){
192              for(int xpos = 0; xpos<xdim; xpos++){
193                // loops over each pixel in the image
194                pos++;
195
196                wavelet[pos] = coeffs[pos];
197           
198                if(!isGood[pos] )  wavelet[pos] = 0.;
199                else{
200
201                  int filterpos = -1;
202                  for(int zoffset=-filterHW; zoffset<=filterHW; zoffset++){
203                    int z = zpos + spacing*zoffset;
204                    if(z<0) z = -z;                 // boundary conditions are
205                    if(z>=zdim) z = 2*(zdim-1) - z; //    reflection.
206               
207                    int oldchan = z * spatialSize;
208               
209                    for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
210                      int y = ypos + spacing*yoffset;
211
212                      // Boundary conditions -- assume reflection at boundaries.
213                      // Use limits as calculated above
214                      if(yLim1[xpos]!=yLim2[xpos]){
215                        // if these are equal we will get into an infinite loop
216                        while((y<yLim1[xpos])||(y>yLim2[xpos])){
217                          if(y<yLim1[xpos]) y = 2*yLim1[xpos] - y;     
218                          else if(y>yLim2[xpos]) y = 2*yLim2[xpos] - y;     
219                        }
220                      }
221                      int oldrow = y * xdim;
222         
223                      for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
224                        int x = 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                        int 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              } //-> end of xpos loop
249            } //-> end of ypos loop
250          } //-> end of zpos loop
251
252          // Need to do this after we've done *all* the convolving
253          for(int pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
254
255          // Have found wavelet coeffs for this scale -- now threshold
256          if(scale>=par.getMinScale()){
257            array = new float[size];
258            goodSize=0;
259            for(int pos=0;pos<size;pos++)
260              if(isGood[pos]) array[goodSize++] = wavelet[pos];
261            findMedianStats(array,goodSize,mean,sigma);
262            delete [] array;
263       
264            threshold = mean +
265              par.getAtrousCut()*originalSigma*sigmaFactors[scale];
266            for(int pos=0;pos<size;pos++){
267              if(!isGood[pos]){
268                output[pos] = input[pos];
269                // this preserves the Blank pixel values in the output.
270              }
271              else if( fabs(wavelet[pos]) > threshold ){
272                output[pos] += wavelet[pos];
273                // only add to the output if the wavelet coefficient is significant
274              }
275            }
276          }
277 
278          spacing *= 2;  // double the scale of the filter.
279
280        } //-> end of scale loop
281
282        for(int pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
283
284        array = new float[size];
285        goodSize=0;
286        for(int i=0;i<size;i++) {
287          if(isGood[i]) array[goodSize++] = input[i] - output[i];
288        }
289        findMedianStats(array,goodSize,mean,newsigma);
290        newsigma = madfmToSigma(newsigma);
291        delete [] array;
292
293        if(par.isVerbose()) printBackSpace(15);
294
295      } while( (iteration==1) ||
296               (fabs(oldsigma-newsigma)/newsigma > reconTolerance) );
297
298      if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
299
300      delete [] xLim1;
301      delete [] xLim2;
302      delete [] yLim1;
303      delete [] yLim2;
304      delete [] filter;
305      delete [] coeffs;
306      delete [] wavelet;
307
308    }
309
310    delete [] isGood;
311    delete [] sigmaFactors;
312  }
313
314}
Note: See TracBrowser for help on using the repository browser.