source: tags/release-1.1.7/src/Utils/GaussSmooth.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: 8.6 KB
Line 
1// -----------------------------------------------------------------------
2// GaussSmooth.cc: Member functions for the GaussSmooth class.
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 <math.h>
30#include <duchamp/Utils/GaussSmooth.hh>
31
32template <class Type>
33GaussSmooth<Type>::GaussSmooth()
34{
35  allocated=false;
36}
37template GaussSmooth<float>::GaussSmooth();
38template GaussSmooth<double>::GaussSmooth();
39
40template <class Type>
41GaussSmooth<Type>::~GaussSmooth()
42{
43  if(allocated) delete [] kernel;
44}
45template GaussSmooth<float>::~GaussSmooth();
46template GaussSmooth<double>::~GaussSmooth();
47
48template <class Type>
49GaussSmooth<Type>::GaussSmooth(const GaussSmooth& g)
50{
51  operator=(g);
52}
53template GaussSmooth<float>::GaussSmooth(const GaussSmooth& g);
54template GaussSmooth<double>::GaussSmooth(const GaussSmooth& g);
55
56template <class Type>
57GaussSmooth<Type>& GaussSmooth<Type>::operator=(const GaussSmooth& g)
58{
59  if(this==&g) return *this;
60  this->kernMaj   = g.kernMaj;
61  this->kernMin   = g.kernMin;
62  this->kernPA    = g.kernPA;
63  this->kernWidth = g.kernWidth;
64  this->stddevScale = g.stddevScale;
65  if(this->allocated) delete [] this->kernel;
66  this->allocated = g.allocated;
67  if(this->allocated){
68    this->kernel = new Type[this->kernWidth*this->kernWidth];
69    for(int i=0;i<this->kernWidth*this->kernWidth;i++)
70      this->kernel[i] = g.kernel[i];
71  }
72  return *this;
73}
74template GaussSmooth<float>& GaussSmooth<float>::operator=(const GaussSmooth& g);
75template GaussSmooth<double>& GaussSmooth<double>::operator=(const GaussSmooth& g);
76
77template <class Type>
78GaussSmooth<Type>::GaussSmooth(float maj, float min, float pa)
79{
80  this->allocated=false;
81  this->define(maj, min, pa);
82}
83template GaussSmooth<float>::GaussSmooth(float maj, float min, float pa);
84template GaussSmooth<double>::GaussSmooth(float maj, float min, float pa);
85
86template <class Type>
87GaussSmooth<Type>::GaussSmooth(float maj)
88{
89  this->allocated=false;
90  this->define(maj, maj, 0);
91}
92template GaussSmooth<float>::GaussSmooth(float maj);
93template GaussSmooth<double>::GaussSmooth(float maj);
94
95template <class Type>
96void GaussSmooth<Type>::define(float maj, float min, float pa)
97{
98
99  this->kernMaj = maj;
100  this->kernMin = min;
101  this->kernPA  = pa;
102
103  // The parameters kernMaj & kernMin are the FWHM in the major and
104  // minor axis directions. We correct these to the sigma_x and
105  // sigma_y parameters for the 2D gaussian by halving and dividing by
106  // sqrt(2 ln(2)). Actually work with sigma_x^2 to make things
107  // easier.
108  float sigmaX2 = (this->kernMaj*this->kernMaj/4.) / (2.*M_LN2);
109  float sigmaY2 = (this->kernMin*this->kernMin/4.) / (2.*M_LN2);
110
111  // First determine the size of the kernel.
112  // For the moment, just calculate the size based on the number of
113  // pixels needed to make the exponential drop to less than the
114  // stated precision. Use the major axis to get the largest square
115  // that includes the ellipse.
116  const float precision = 1.e-4;
117  int kernelHW = int(ceil(sqrt(-1.*log(precision)*sigmaX2)));
118  this->kernWidth = 2*kernelHW + 1;
119//   std::cerr << "Making a kernel of width " << this->kernWidth << "\n";
120
121  if(this->allocated) delete [] this->kernel;
122  this->kernel = new Type[this->kernWidth*this->kernWidth];
123  this->allocated = true;
124  this->stddevScale=0.;
125  float posang = this->kernPA * M_PI/180.;
126
127
128  for(int i=0;i<this->kernWidth;i++){
129    for(int j=0;j<this->kernWidth;j++){
130      float xpt = (i-kernelHW)*sin(posang) - (j-kernelHW)*cos(posang);
131
132      float ypt = (i-kernelHW)*cos(posang) + (j-kernelHW)*sin(posang);
133      float rsq = (xpt*xpt/sigmaX2) + (ypt*ypt/sigmaY2);
134      kernel[i*this->kernWidth+j] = exp( -0.5 * rsq);
135      this->stddevScale +=
136        kernel[i*this->kernWidth+j]*kernel[i*this->kernWidth+j];
137    }
138  }
139  this->stddevScale = sqrt(this->stddevScale);
140//   std::cerr << "Stddev scaling factor = " << this->stddevScale << "\n";
141}
142template void GaussSmooth<float>::define(float maj, float min, float pa);
143template void GaussSmooth<double>::define(float maj, float min, float pa);
144
145template <class Type>
146Type *GaussSmooth<Type>::smooth(Type *input, int xdim, int ydim, bool scaleByCoverage)
147{
148  /// @details
149  /// Smooth a given two-dimensional array, of dimensions xdim
150  /// \f$\times\f$ ydim, with an elliptical gaussian. Simply runs as a
151  /// front end to GaussSmooth::smooth(float *, int, int, bool *) by
152  /// defining a mask that allows all pixels in the input array.
153  ///
154  ///  \param input The 2D array to be smoothed.
155  ///  \param xdim  The size of the x-dimension of the array.
156  ///  \param ydim  The size of the y-dimension of the array.
157  ///  \return The smoothed array.
158
159  Type *smoothed;
160  bool *mask = new bool[xdim*ydim];
161  for(int i=0;i<xdim*ydim;i++) mask[i]=true;
162  smoothed = this->smooth(input,xdim,ydim,mask,scaleByCoverage);
163  delete [] mask;
164  return smoothed;
165}
166template float *GaussSmooth<float>::smooth(float *input, int xdim, int ydim, bool scaleByCoverage);
167template double *GaussSmooth<double>::smooth(double *input, int xdim, int ydim, bool scaleByCoverage);
168
169template <class Type>
170Type *GaussSmooth<Type>::smooth(Type *input, int xdim, int ydim, bool *mask, bool scaleByCoverage)
171{
172  /// @details
173  ///  Smooth a given two-dimensional array, of dimensions xdim
174  ///  \f$\times\f$ ydim, with an elliptical gaussian, where the
175  ///  boolean array mask defines which values of the array are valid.
176  ///
177  ///  This function convolves the input array with the kernel that
178  ///  needs to have been defined. If it has not, the input array is
179  ///  returned unchanged.
180  ///
181  ///  The mask should be the same size as the input array, and have
182  ///  values of true for entries that are considered valid, and false
183  ///  for entries that are not. For instance, arrays from FITS files
184  ///  should have the mask entries corresponding to BLANK pixels set
185  ///  to false.
186  ///
187  ///  \param input The 2D array to be smoothed.
188  ///  \param xdim  The size of the x-dimension of the array.
189  ///  \param ydim  The size of the y-dimension of the array.
190  ///  \param mask The array showing which pixels in the input array
191  ///              are valid.
192  ///  \return The smoothed array.
193
194  if(!this->allocated) return input;
195  else{
196
197    Type *output = new Type[xdim*ydim];
198
199    int pos,comp,xcomp,ycomp,fpos,ct;
200    float fsum,kernsum=0;
201    int kernelHW = this->kernWidth/2;
202
203    for(int i=0;i<this->kernWidth;i++)
204      for(int j=0;j<this->kernWidth;j++)
205        kernsum += this->kernel[i*this->kernWidth+j];
206
207    for(int ypos = 0; ypos<ydim; ypos++){
208      for(int xpos = 0; xpos<xdim; xpos++){
209        pos = ypos*xdim + xpos;
210     
211        if(!mask[pos]) output[pos] = input[pos];
212        else{
213       
214          ct=0;
215          fsum=0.;
216          output[pos] = 0.;
217       
218          for(int yoff = -kernelHW; yoff<=kernelHW; yoff++){
219            ycomp = ypos + yoff;
220            if((ycomp>=0)&&(ycomp<ydim)){
221
222              for(int xoff = -kernelHW; xoff<=kernelHW; xoff++){
223                xcomp = xpos + xoff;         
224                if((xcomp>=0)&&(xcomp<xdim)){
225
226                  fpos = (xoff+kernelHW) + (yoff+kernelHW)*this->kernWidth;
227                  comp = ycomp*xdim + xcomp;
228                  if(mask[comp]){
229                    ct++;
230                    fsum += this->kernel[fpos];
231                    output[pos] += input[comp]*this->kernel[fpos];
232                  }
233
234                }
235              } // xoff loop
236
237            }
238          }// yoff loop
239//        if(ct>0 && scaleByCoverage) output[pos] /= fsum;
240          if(ct>0 && scaleByCoverage) output[pos] *= kernsum/fsum;
241 
242        } // else{
243
244      } //xpos loop
245    }   //ypos loop
246   
247    return output;
248  }
249
250}
251template float *GaussSmooth<float>::smooth(float *input, int xdim, int ydim, bool *mask, bool scaleByCoverage);
252template double *GaussSmooth<double>::smooth(double *input, int xdim, int ydim, bool *mask, bool scaleByCoverage);
Note: See TracBrowser for help on using the repository browser.