source: trunk/src/Utils/GaussSmooth2D.cc @ 642

Last change on this file since 642 was 638, checked in by MatthewWhiting, 15 years ago

Making a 1D Gaussian smoothing class, and renaming the GaussSmooth? class to GaussSmooth2D.

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