source: trunk/src/Utils/GaussSmooth1D.cc

Last change on this file was 1393, checked in by MatthewWhiting, 10 years ago

A large changeset that moves all use of bool arrays (ie. bool *) to std::vector<bool>. This will be a bit safer, plus potentially cheaper in memory usage. Interfaces to all stats functions with masks have changed accordingly, as well as the Gaussian smoothing functions and some spectral utility functions.

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
[1393]137  /// GaussSmooth1D::smooth(float *, int, vector<bool>) by defining a mask
[638]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;
[1393]145  std::vector<bool> mask(dim,true);
[638]146  smoothed = this->smooth(input,dim,mask,scaleByCoverage);
[275]147  return smoothed;
148}
[638]149template float *GaussSmooth1D<float>::smooth(float *input, int dim, bool normalise, bool scaleByCoverage);
150template double *GaussSmooth1D<double>::smooth(double *input, int dim, bool normalise, bool scaleByCoverage);
[275]151
[516]152template <class Type>
[1393]153Type *GaussSmooth1D<Type>::smooth(Type *input, int dim, std::vector<bool> mask, bool normalise, bool scaleByCoverage)
[275]154{
[638]155  /// @details Smooth a given one-dimensional array, of dimension dim,
156  ///  with a gaussian, where the boolean array mask defines which
157  ///  values of the array are valid.
[528]158  ///
159  ///  This function convolves the input array with the kernel that
160  ///  needs to have been defined. If it has not, the input array is
161  ///  returned unchanged.
162  ///
163  ///  The mask should be the same size as the input array, and have
164  ///  values of true for entries that are considered valid, and false
165  ///  for entries that are not. For instance, arrays from FITS files
166  ///  should have the mask entries corresponding to BLANK pixels set
167  ///  to false.
168  ///
169  ///  \param input The 2D array to be smoothed.
[638]170  ///  \param dim  The size of the x-dimension of the array.
[1393]171  ///  \param mask The vector showing which pixels in the input array
[528]172  ///              are valid.
173  ///  \return The smoothed array.
[275]174
175  if(!this->allocated) return input;
176  else{
177
[638]178    Type *output = new Type[dim];
[275]179
[638]180    int comp,fpos,ct;
[516]181    float fsum,kernsum=0;
[275]182    int kernelHW = this->kernWidth/2;
183
[516]184    for(int i=0;i<this->kernWidth;i++)
[638]185      kernsum += this->kernel[i];
186   
187    for(int pos = 0; pos<dim; pos++){
[275]188     
[638]189      if(!mask[pos]) output[pos] = input[pos];
190      else{
[275]191       
[638]192        ct=0;
193        fsum=0.;
194        output[pos] = 0.;
[275]195       
[638]196        for(int off = -kernelHW; off<=kernelHW; off++){
197          comp = pos + off;           
198          if((comp>=0)&&(comp<dim)){
199            fpos = (off+kernelHW);
200            if(mask[comp]){
201              ct++;
202              fsum += this->kernel[fpos];
203              output[pos] += input[comp]*this->kernel[fpos];
204            }
[275]205
[638]206          }
207        } // off loop
208       
209        if(ct>0){
210          if(scaleByCoverage) output[pos] /= fsum;
211          if(normalise) output[pos] /= kernsum;
212        }
[275]213
[638]214      } // else{
[275]215
[638]216    } //pos loop
[275]217   
218    return output;
219  }
[638]220 
[275]221}
[1393]222template float *GaussSmooth1D<float>::smooth(float *input, int dim, std::vector<bool> mask, bool normalise, bool scaleByCoverage);
223template double *GaussSmooth1D<double>::smooth(double *input, int dim, std::vector<bool> mask, bool normalise, bool scaleByCoverage);
Note: See TracBrowser for help on using the repository browser.