source: tags/release-1.1.5/src/ATrous/atrous_3d_reconstruct.cc @ 1441

Last change on this file since 1441 was 393, checked in by MatthewWhiting, 17 years ago

Fixed up headers for trunk as well.

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