source: trunk/src/Utils/GaussSmooth1D.cc @ 1213

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

Scaling the 1D Gaussian kernel properly.

File size: 7.4 KB
RevLine 
[301]1// -----------------------------------------------------------------------
[638]2// GaussSmooth1D.cc: Member functions for the GaussSmooth1D class.
[301]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// -----------------------------------------------------------------------
[275]28#include <iostream>
[636]29#include <duchamp/config.h>
[275]30#include <math.h>
[635]31#ifdef HAVE_VALUES_H
32#include <values.h>
33#endif
[636]34#ifdef MAXFLOAT
35#define MAXVAL MAXFLOAT
36#else
37#define MAXVAL 1.e38F
38#endif
[638]39#include <duchamp/Utils/GaussSmooth1D.hh>
[275]40
[516]41template <class Type>
[638]42GaussSmooth1D<Type>::GaussSmooth1D()
[275]43{
44  allocated=false;
[419]45}
[638]46template GaussSmooth1D<float>::GaussSmooth1D();
47template GaussSmooth1D<double>::GaussSmooth1D();
[419]48
[516]49template <class Type>
[638]50GaussSmooth1D<Type>::~GaussSmooth1D()
[275]51{
52  if(allocated) delete [] kernel;
[419]53}
[638]54template GaussSmooth1D<float>::~GaussSmooth1D();
55template GaussSmooth1D<double>::~GaussSmooth1D();
[275]56
[516]57template <class Type>
[638]58GaussSmooth1D<Type>::GaussSmooth1D(const GaussSmooth1D& g)
[365]59{
60  operator=(g);
61}
[638]62template GaussSmooth1D<float>::GaussSmooth1D(const GaussSmooth1D& g);
63template GaussSmooth1D<double>::GaussSmooth1D(const GaussSmooth1D& g);
[365]64
[516]65template <class Type>
[638]66GaussSmooth1D<Type>& GaussSmooth1D<Type>::operator=(const GaussSmooth1D& g)
[365]67{
68  if(this==&g) return *this;
[638]69  this->kernFWHM = g.kernFWHM;
[365]70  this->kernWidth = g.kernWidth;
71  this->stddevScale = g.stddevScale;
[526]72  if(this->allocated) delete [] this->kernel;
[365]73  this->allocated = g.allocated;
74  if(this->allocated){
[516]75    this->kernel = new Type[this->kernWidth*this->kernWidth];
[365]76    for(int i=0;i<this->kernWidth*this->kernWidth;i++)
77      this->kernel[i] = g.kernel[i];
78  }
79  return *this;
80}
[638]81template GaussSmooth1D<float>& GaussSmooth1D<float>::operator=(const GaussSmooth1D& g);
82template GaussSmooth1D<double>& GaussSmooth1D<double>::operator=(const GaussSmooth1D& g);
[365]83
[516]84template <class Type>
[638]85GaussSmooth1D<Type>::GaussSmooth1D(float fwhm)
[275]86{
87  this->allocated=false;
[638]88  this->define(fwhm);
[419]89}
[638]90template GaussSmooth1D<float>::GaussSmooth1D(float fwhm);
91template GaussSmooth1D<double>::GaussSmooth1D(float fwhm);
[275]92
[516]93template <class Type>
[638]94void GaussSmooth1D<Type>::define(float fwhm)
[275]95{
96
[638]97  this->kernFWHM = fwhm;
[275]98
[638]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);
[275]104
[618]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.
[638]109  float sigma = this->kernFWHM / (4.*M_LN2);
110  int kernelHW = int(ceil(sigma * sqrt(-2.*log(1. / MAXVAL))));
[275]111  this->kernWidth = 2*kernelHW + 1;
112
113  if(this->allocated) delete [] this->kernel;
[638]114  this->kernel = new Type[this->kernWidth];
[275]115  this->allocated = true;
116  this->stddevScale=0.;
117
[640]118  float sum=0.;
[275]119  for(int i=0;i<this->kernWidth;i++){
[638]120    float xpt = (i-kernelHW);
121    float rsq = (xpt*xpt/sigma2);
122    kernel[i] = exp( -0.5 * rsq);
[640]123    sum += kernel[i];
[638]124    this->stddevScale += kernel[i]*kernel[i];
[275]125  }
[640]126  for(int i=0;i<this->kernWidth;i++) kernel[i] /= sum;
[275]127  this->stddevScale = sqrt(this->stddevScale);
128}
[638]129template void GaussSmooth1D<float>::define(float fwhm);
130template void GaussSmooth1D<double>::define(float fwhm);
[275]131
[516]132template <class Type>
[638]133Type *GaussSmooth1D<Type>::smooth(Type *input, int dim, bool normalise, bool scaleByCoverage)
[275]134{
[638]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.
[528]139  ///
140  ///  \param input The 2D array to be smoothed.
[638]141  ///  \param dim  The size of the x-dimension of the array.
[528]142  ///  \return The smoothed array.
143
[516]144  Type *smoothed;
[638]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);
[275]148  delete [] mask;
149  return smoothed;
150}
[638]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);
[275]153
[516]154template <class Type>
[638]155Type *GaussSmooth1D<Type>::smooth(Type *input, int dim, bool *mask, bool normalise, bool scaleByCoverage)
[275]156{
[638]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.
[528]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.
[638]172  ///  \param dim  The size of the x-dimension of the array.
[528]173  ///  \param mask The array showing which pixels in the input array
174  ///              are valid.
175  ///  \return The smoothed array.
[275]176
177  if(!this->allocated) return input;
178  else{
179
[638]180    Type *output = new Type[dim];
[275]181
[638]182    int comp,fpos,ct;
[516]183    float fsum,kernsum=0;
[275]184    int kernelHW = this->kernWidth/2;
185
[516]186    for(int i=0;i<this->kernWidth;i++)
[638]187      kernsum += this->kernel[i];
188   
189    for(int pos = 0; pos<dim; pos++){
[275]190     
[638]191      if(!mask[pos]) output[pos] = input[pos];
192      else{
[275]193       
[638]194        ct=0;
195        fsum=0.;
196        output[pos] = 0.;
[275]197       
[638]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            }
[275]207
[638]208          }
209        } // off loop
210       
211        if(ct>0){
212          if(scaleByCoverage) output[pos] /= fsum;
213          if(normalise) output[pos] /= kernsum;
214        }
[275]215
[638]216      } // else{
[275]217
[638]218    } //pos loop
[275]219   
220    return output;
221  }
[638]222 
[275]223}
[638]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.