source: trunk/src/Utils/GaussSmooth.cc @ 635

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

Adding values.h to the include statements in GaussSmooth?.cc, and adding it to the searches in the configure script. This is necessary on some systems to find the MAXFLOAT value.

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