source: tags/release-1.6/src/Utils/GaussSmooth2D.tcc @ 1455

Last change on this file since 1455 was 1297, checked in by MatthewWhiting, 11 years ago

Silencing some compiler warnings that are cropping up with the new Xcode on the mac.

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