source: tags/release-1.2.2/src/Utils/GaussSmooth1D.cc

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

Scaling the 1D Gaussian kernel properly.

File size: 7.4 KB
Line 
1// -----------------------------------------------------------------------
2// GaussSmooth1D.cc: Member functions for the GaussSmooth1D 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/GaussSmooth1D.hh>
40
41template <class Type>
42GaussSmooth1D<Type>::GaussSmooth1D()
43{
44  allocated=false;
45}
46template GaussSmooth1D<float>::GaussSmooth1D();
47template GaussSmooth1D<double>::GaussSmooth1D();
48
49template <class Type>
50GaussSmooth1D<Type>::~GaussSmooth1D()
51{
52  if(allocated) delete [] kernel;
53}
54template GaussSmooth1D<float>::~GaussSmooth1D();
55template GaussSmooth1D<double>::~GaussSmooth1D();
56
57template <class Type>
58GaussSmooth1D<Type>::GaussSmooth1D(const GaussSmooth1D& g)
59{
60  operator=(g);
61}
62template GaussSmooth1D<float>::GaussSmooth1D(const GaussSmooth1D& g);
63template GaussSmooth1D<double>::GaussSmooth1D(const GaussSmooth1D& g);
64
65template <class Type>
66GaussSmooth1D<Type>& GaussSmooth1D<Type>::operator=(const GaussSmooth1D& g)
67{
68  if(this==&g) return *this;
69  this->kernFWHM = g.kernFWHM;
70  this->kernWidth = g.kernWidth;
71  this->stddevScale = g.stddevScale;
72  if(this->allocated) delete [] this->kernel;
73  this->allocated = g.allocated;
74  if(this->allocated){
75    this->kernel = new Type[this->kernWidth*this->kernWidth];
76    for(int i=0;i<this->kernWidth*this->kernWidth;i++)
77      this->kernel[i] = g.kernel[i];
78  }
79  return *this;
80}
81template GaussSmooth1D<float>& GaussSmooth1D<float>::operator=(const GaussSmooth1D& g);
82template GaussSmooth1D<double>& GaussSmooth1D<double>::operator=(const GaussSmooth1D& g);
83
84template <class Type>
85GaussSmooth1D<Type>::GaussSmooth1D(float fwhm)
86{
87  this->allocated=false;
88  this->define(fwhm);
89}
90template GaussSmooth1D<float>::GaussSmooth1D(float fwhm);
91template GaussSmooth1D<double>::GaussSmooth1D(float fwhm);
92
93template <class Type>
94void GaussSmooth1D<Type>::define(float fwhm)
95{
96
97  this->kernFWHM = fwhm;
98
99  // The parameter kernFWHM is the full-width-at-half-maximum of the
100  // Gaussian. We correct this to the sigma parameter for the 1D
101  // gaussian by halving and dividing by sqrt(2 ln(2)). Actually work
102  // with sigma_x^2 to make things easier.
103  float sigma2 = (this->kernFWHM*this->kernFWHM/4.) / (2.*M_LN2);
104
105  // First determine the size of the kernel.  Calculate the size based
106  // on the number of pixels needed to make the exponential drop to
107  // less than the minimum floating-point value. Use the major axis to
108  // get the largest square that includes the ellipse.
109  float sigma = this->kernFWHM / (4.*M_LN2);
110  int kernelHW = int(ceil(sigma * sqrt(-2.*log(1. / MAXVAL))));
111  this->kernWidth = 2*kernelHW + 1;
112
113  if(this->allocated) delete [] this->kernel;
114  this->kernel = new Type[this->kernWidth];
115  this->allocated = true;
116  this->stddevScale=0.;
117
118  float sum=0.;
119  for(int i=0;i<this->kernWidth;i++){
120    float xpt = (i-kernelHW);
121    float rsq = (xpt*xpt/sigma2);
122    kernel[i] = exp( -0.5 * rsq);
123    sum += kernel[i];
124    this->stddevScale += kernel[i]*kernel[i];
125  }
126  for(int i=0;i<this->kernWidth;i++) kernel[i] /= sum;
127  this->stddevScale = sqrt(this->stddevScale);
128}
129template void GaussSmooth1D<float>::define(float fwhm);
130template void GaussSmooth1D<double>::define(float fwhm);
131
132template <class Type>
133Type *GaussSmooth1D<Type>::smooth(Type *input, int dim, bool normalise, bool scaleByCoverage)
134{
135  /// @details Smooth a given one-dimensional array, of dimension dim,
136  /// with a gaussian. Simply runs as a front end to
137  /// GaussSmooth1D::smooth(float *, int, bool *) by defining a mask
138  /// that allows all pixels in the input array.
139  ///
140  ///  \param input The 2D array to be smoothed.
141  ///  \param dim  The size of the x-dimension of the array.
142  ///  \return The smoothed array.
143
144  Type *smoothed;
145  bool *mask = new bool[dim];
146  for(int i=0;i<dim;i++) mask[i]=true;
147  smoothed = this->smooth(input,dim,mask,scaleByCoverage);
148  delete [] mask;
149  return smoothed;
150}
151template float *GaussSmooth1D<float>::smooth(float *input, int dim, bool normalise, bool scaleByCoverage);
152template double *GaussSmooth1D<double>::smooth(double *input, int dim, bool normalise, bool scaleByCoverage);
153
154template <class Type>
155Type *GaussSmooth1D<Type>::smooth(Type *input, int dim, bool *mask, bool normalise, bool scaleByCoverage)
156{
157  /// @details Smooth a given one-dimensional array, of dimension dim,
158  ///  with a gaussian, where the boolean array mask defines which
159  ///  values of the array are valid.
160  ///
161  ///  This function convolves the input array with the kernel that
162  ///  needs to have been defined. If it has not, the input array is
163  ///  returned unchanged.
164  ///
165  ///  The mask should be the same size as the input array, and have
166  ///  values of true for entries that are considered valid, and false
167  ///  for entries that are not. For instance, arrays from FITS files
168  ///  should have the mask entries corresponding to BLANK pixels set
169  ///  to false.
170  ///
171  ///  \param input The 2D array to be smoothed.
172  ///  \param dim  The size of the x-dimension of the array.
173  ///  \param mask The array showing which pixels in the input array
174  ///              are valid.
175  ///  \return The smoothed array.
176
177  if(!this->allocated) return input;
178  else{
179
180    Type *output = new Type[dim];
181
182    int comp,fpos,ct;
183    float fsum,kernsum=0;
184    int kernelHW = this->kernWidth/2;
185
186    for(int i=0;i<this->kernWidth;i++)
187      kernsum += this->kernel[i];
188   
189    for(int pos = 0; pos<dim; pos++){
190     
191      if(!mask[pos]) output[pos] = input[pos];
192      else{
193       
194        ct=0;
195        fsum=0.;
196        output[pos] = 0.;
197       
198        for(int off = -kernelHW; off<=kernelHW; off++){
199          comp = pos + off;           
200          if((comp>=0)&&(comp<dim)){
201            fpos = (off+kernelHW);
202            if(mask[comp]){
203              ct++;
204              fsum += this->kernel[fpos];
205              output[pos] += input[comp]*this->kernel[fpos];
206            }
207
208          }
209        } // off loop
210       
211        if(ct>0){
212          if(scaleByCoverage) output[pos] /= fsum;
213          if(normalise) output[pos] /= kernsum;
214        }
215
216      } // else{
217
218    } //pos loop
219   
220    return output;
221  }
222 
223}
224template float *GaussSmooth1D<float>::smooth(float *input, int dim, bool *mask, bool normalise, bool scaleByCoverage);
225template double *GaussSmooth1D<double>::smooth(double *input, int dim, bool *mask, bool normalise, bool scaleByCoverage);
Note: See TracBrowser for help on using the repository browser.