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

Last change on this file since 301 was 301, checked in by Matthew Whiting, 17 years ago

Mostly adding the distribution text to the start of files, with a few additional comments added too.

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