source: branches/pixel-map-branch/src/ATrous/atrous_3d_reconstruct.cc @ 1441

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

Large raft of changes. Most are minor ones related to fixing up the use of std::string and std::vector (whether they are declared as using, or not...). Other changes include:

  • Moving the reconstruction filter class Filter into its own header/implementation files filter.{hh,cc}. As a result, the atrous.cc file is removed, but atrous.hh remains with just the function prototypes.
  • Incorporating a Filter object into the Param set, so that the reconstruction routines can see it without the messy "extern" call. The define() function is now called in both the Param() and Param::readParams() functions, and no longer in the main body.
  • Col functions in columns.cc moved into the Column namespace, while the template function printEntry is moved into the columns.hh file -- it would not compile on delphinus with it in the columns.cc, even though all the implementations were present.
  • Improved the introductory section of the Guide, with a bit more detail about each of the execution steps. This way the reader can read this section and have a reasonably good idea about what is happening.
  • Other minor changes to the Guide.
File size: 8.7 KB
Line 
1#include <iostream>
2#include <iomanip>
3#include <math.h>
4#include <duchamp.hh>
5#include <ATrous/atrous.hh>
6#include <ATrous/filter.hh>
7#include <Utils/utils.hh>
8#include <Utils/feedback.hh>
9#include <Utils/Statistics.hh>
10using Statistics::madfmToSigma;
11
12using std::endl;
13using std::setw;
14
15void atrous3DReconstruct(long &xdim, long &ydim, long &zdim, float *&input,
16                         float *&output, Param &par)
17{
18  /**
19   *  A routine that uses the a trous wavelet method to reconstruct a
20   *   3-dimensional image cube.
21   *  The Param object "par" contains all necessary info about the filter and
22   *   reconstruction parameters.
23   *
24   *  If there are no non-BLANK pixels (and we are testing for
25   *  BLANKs), the reconstruction cannot be done, so we return the
26   *  input array as the output array and give a warning message.
27   *
28   *  \param xdim The length of the x-axis.
29   *  \param ydim The length of the y-axis.
30   *  \param zdim The length of the z-axis.
31   *  \param input The input spectrum.
32   *  \param output The returned reconstructed spectrum. This array needs to be declared beforehand.
33   *  \param par The Param set.
34   */
35
36  long size = xdim * ydim * zdim;
37  long spatialSize = xdim * ydim;
38  long mindim = xdim;
39  if (ydim<mindim) mindim = ydim;
40  if (zdim<mindim) mindim = zdim;
41  int numScales = par.filter().getNumScales(mindim);
42
43  double *sigmaFactors = new double[numScales+1];
44  for(int i=0;i<=numScales;i++){
45    if(i<=par.filter().maxFactor(3))
46      sigmaFactors[i] = par.filter().sigmaFactor(3,i);
47    else sigmaFactors[i] = sigmaFactors[i-1] / sqrt(8.);
48  }
49
50  float mean,sigma,originalSigma,originalMean,oldsigma,newsigma;
51  bool *isGood = new bool[size];
52  int goodSize=0;
53  float blankPixValue = par.getBlankPixVal();
54  for(int pos=0;pos<size;pos++){
55    isGood[pos] = !par.isBlank(input[pos]);
56    if(isGood[pos]) goodSize++;
57  }
58
59  if(goodSize == 0){
60    // There are no good pixels -- everything is BLANK for some reason.
61    // Return the input array as the output, and give a warning message.
62
63    for(int pos=0;pos<xdim; pos++) output[pos] = input[pos];
64
65    duchampWarning("atrous1DReconstruct",
66                   "There are no good pixels to be reconstructed -- all are BLANK.\nPerhaps you need to try this with flagBlankPix=false.\nReturning input array.\n");
67  }
68  else{
69    // Otherwise, all is good, and we continue.
70
71
72    float *array = new float[size];
73    goodSize=0;
74    for(int i=0;i<size;i++) if(isGood[i]) array[goodSize++] = input[i];
75    findMedianStats(array,goodSize,originalMean,originalSigma);
76    originalSigma = madfmToSigma(originalSigma);
77    delete [] array;
78
79    float *coeffs = new float[size];
80    float *wavelet = new float[size];
81
82    for(int pos=0;pos<size;pos++) output[pos]=0.;
83
84    // Define the 3-D (separable) filter, using info from par.filter()
85    int filterwidth = par.filter().width();
86    int filterHW = filterwidth/2;
87    int fsize = filterwidth*filterwidth*filterwidth;
88    double *filter = new double[fsize];
89    for(int i=0;i<filterwidth;i++){
90      for(int j=0;j<filterwidth;j++){
91        for(int k=0;k<filterwidth;k++){
92          filter[i +j*filterwidth + k*filterwidth*filterwidth] =
93            par.filter().coeff(i) * par.filter().coeff(j) * par.filter().coeff(k);
94        }
95      }
96    }
97
98    // Locating the borders of the image -- ignoring BLANK pixels
99    //  Only do this if flagBlankPix is true.
100    //  Otherwise use the full range of x and y.
101    //  No trimming is done in the z-direction at this point.
102    int *xLim1 = new int[ydim];
103    for(int i=0;i<ydim;i++) xLim1[i] = 0;
104    int *xLim2 = new int[ydim];
105    for(int i=0;i<ydim;i++) xLim2[i] = xdim-1;
106    int *yLim1 = new int[xdim];
107    for(int i=0;i<xdim;i++) yLim1[i] = 0;
108    int *yLim2 = new int[xdim];
109    for(int i=0;i<xdim;i++) yLim2[i] = ydim-1;
110
111    if(par.getFlagBlankPix()){
112      float avGapX = 0, avGapY = 0;
113      for(int row=0;row<ydim;row++){
114        int ct1 = 0;
115        int ct2 = xdim - 1;
116        while((ct1<ct2)&&(par.isBlank(input[row*xdim+ct1]))) ct1++;
117        while((ct2>ct1)&&(par.isBlank(input[row*xdim+ct2]))) ct2--;
118        xLim1[row] = ct1;
119        xLim2[row] = ct2;
120        avGapX += ct2 - ct1 + 1;
121      }
122      avGapX /= float(ydim);
123
124      for(int col=0;col<xdim;col++){
125        int ct1=0;
126        int ct2=ydim-1;
127        while((ct1<ct2)&&(par.isBlank(input[col+xdim*ct1]))) ct1++;
128        while((ct2>ct1)&&(par.isBlank(input[col+xdim*ct2]))) ct2--;
129        yLim1[col] = ct1;
130        yLim2[col] = ct2;
131        avGapY += ct2 - ct1 + 1;
132      }
133      avGapY /= float(xdim);
134 
135      mindim = int(avGapX);
136      if(avGapY < avGapX) mindim = int(avGapY);
137      numScales = par.filter().getNumScales(mindim);
138    }
139
140    float threshold;
141    int iteration=0;
142    newsigma = 1.e9;
143    for(int i=0;i<size;i++) output[i] = 0;
144    do{
145      if(par.isVerbose()) std::cout << "Iteration #"<<setw(2)<<++iteration<<": ";
146      // first, get the value of oldsigma, set it to the previous newsigma value
147      oldsigma = newsigma;
148      // we are transforming the residual array (input array first time around)
149      for(int i=0;i<size;i++)  coeffs[i] = input[i] - output[i];
150
151      int spacing = 1;
152      for(int scale = 1; scale<=numScales; scale++){
153
154        if(par.isVerbose()){
155          std::cout << "Scale ";
156          std::cout << setw(2)<<scale<<" / "<<setw(2)<<numScales;
157          printBackSpace(13);
158          std::cout << std::flush;
159        }
160
161        int pos = -1;
162        for(int zpos = 0; zpos<zdim; zpos++){
163          for(int ypos = 0; ypos<ydim; ypos++){
164            for(int xpos = 0; xpos<xdim; xpos++){
165              // loops over each pixel in the image
166              pos++;
167
168              wavelet[pos] = coeffs[pos];
169           
170              if(!isGood[pos] )  wavelet[pos] = 0.;
171              else{
172
173                int filterpos = -1;
174                for(int zoffset=-filterHW; zoffset<=filterHW; zoffset++){
175                  int z = zpos + spacing*zoffset;
176                  if(z<0) z = -z;                 // boundary conditions are
177                  if(z>=zdim) z = 2*(zdim-1) - z; //    reflection.
178               
179                  int oldchan = z * spatialSize;
180               
181                  for(int yoffset=-filterHW; yoffset<=filterHW; yoffset++){
182                    int y = ypos + spacing*yoffset;
183
184                    // Boundary conditions -- assume reflection at boundaries.
185                    // Use limits as calculated above
186                    if(yLim1[xpos]!=yLim2[xpos]){
187                      // if these are equal we will get into an infinite loop
188                      while((y<yLim1[xpos])||(y>yLim2[xpos])){
189                        if(y<yLim1[xpos]) y = 2*yLim1[xpos] - y;     
190                        else if(y>yLim2[xpos]) y = 2*yLim2[xpos] - y;     
191                      }
192                    }
193                    int oldrow = y * xdim;
194         
195                    for(int xoffset=-filterHW; xoffset<=filterHW; xoffset++){
196                      int x = xpos + spacing*xoffset;
197
198                      // Boundary conditions -- assume reflection at boundaries.
199                      // Use limits as calculated above
200                      if(xLim1[ypos]!=xLim2[ypos]){
201                        // if these are equal we will get into an infinite loop
202                        while((x<xLim1[ypos])||(x>xLim2[ypos])){
203                          if(x<xLim1[ypos]) x = 2*xLim1[ypos] - x;     
204                          else if(x>xLim2[ypos]) x = 2*xLim2[ypos] - x;     
205                        }
206                      }
207
208                      int oldpos = oldchan + oldrow + x;
209
210                      filterpos++;
211                   
212                      if(isGood[oldpos])
213                        wavelet[pos] -= filter[filterpos]*coeffs[oldpos];
214                     
215                    } //-> end of xoffset loop
216                  } //-> end of yoffset loop
217                } //-> end of zoffset loop
218              } //-> end of else{ ( from if(!isGood[pos])  )
219           
220            } //-> end of xpos loop
221          } //-> end of ypos loop
222        } //-> end of zpos loop
223
224        // Need to do this after we've done *all* the convolving
225        for(int pos=0;pos<size;pos++) coeffs[pos] = coeffs[pos] - wavelet[pos];
226
227        // Have found wavelet coeffs for this scale -- now threshold
228        if(scale>=par.getMinScale()){
229          array = new float[size];
230          goodSize=0;
231          for(int pos=0;pos<size;pos++)
232            if(isGood[pos]) array[goodSize++] = wavelet[pos];
233          findMedianStats(array,goodSize,mean,sigma);
234          delete [] array;
235       
236          threshold = mean +
237            par.getAtrousCut()*originalSigma*sigmaFactors[scale];
238          for(int pos=0;pos<size;pos++){
239            if(!isGood[pos]){
240              output[pos] = blankPixValue;
241              // this preserves the Blank pixel values in the output.
242            }
243            else if( fabs(wavelet[pos]) > threshold ){
244              output[pos] += wavelet[pos];
245              // only add to the output if the wavelet coefficient is significant
246            }
247          }
248        }
249 
250        spacing *= 2;  // double the scale of the filter.
251
252      } //-> end of scale loop
253
254      for(int pos=0;pos<size;pos++) if(isGood[pos]) output[pos] += coeffs[pos];
255
256      array = new float[size];
257      goodSize=0;
258      for(int i=0;i<size;i++) {
259        if(isGood[i]) array[goodSize++] = input[i] - output[i];
260      }
261      findMedianStats(array,goodSize,mean,newsigma);
262      newsigma = madfmToSigma(newsigma);
263      delete [] array;
264
265      if(par.isVerbose()) printBackSpace(15);
266
267    } while( (iteration==1) ||
268             (fabs(oldsigma-newsigma)/newsigma > reconTolerance) );
269
270    if(par.isVerbose()) std::cout << "Completed "<<iteration<<" iterations. ";
271
272    delete [] xLim1;
273    delete [] xLim2;
274    delete [] yLim1;
275    delete [] yLim2;
276    delete [] filter;
277    delete [] coeffs;
278    delete [] wavelet;
279
280  }
281
282  delete [] isGood;
283  delete [] sigmaFactors;
284}
Note: See TracBrowser for help on using the repository browser.