source: tags/release-1.1.4/src/Utils/GaussSmooth.cc @ 1441

Last change on this file since 1441 was 419, checked in by MatthewWhiting, 16 years ago

Some minor fixes to correct compilation warnings. Moved Object3D::order() into the .cc file.

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