source: tags/release-1.1/src/ATrous/atrous_3d_reconstruct.cc @ 1391

Last change on this file since 1391 was 299, checked in by Matthew Whiting, 17 years ago

Adding distribution text at the start of each file...

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