mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
imCenterCircleSym.hpp
Go to the documentation of this file.
1 /** \file imCenterCircleSym.hpp
2  * \brief A class to find PSF centers using circular symmetry.
3  * \ingroup image_processing_files
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 #ifndef __imCenterCircleSym_hpp__
28 #define __imCenterCircleSym_hpp__
29 
30 #include "../math/vectorUtils.hpp"
31 #include "../math/fit/fitGaussian.hpp"
32 #include "imageFilters.hpp"
33 #include "eigenImage.hpp"
34 
35 //#define ICCS_OMP
36 namespace mx
37 {
38 namespace improc
39 {
40 
41 
42 ///Find the center of the image of a point source using circular symmetry of the PSF.
43 /** Conducts a grid search through possible center positions. Finds the point with the minimum
44  * total variance around concentric circles about that point. The cost grid is fit with a Gaussian.
45  *
46  * \tparam realT is a real floating point type.
47  *
48  * \ingroup image_reg
49  */
50 template<typename realT>
52 {
53 
54  eigenImage<realT> * mask; ///< An optional pointer to a mask. If not NULL and the same size as the input image, any 0 pixels in this image are ignored.
55 
56  eigenImage<realT> grid; ///< The cost grid.
57  eigenImage<realT> smGrid; ///< The smoothed cost grid.
58 
59 
60  realT maxPix; ///<The maximum range of the grid search, the grid will be +/- maxPix. Default: 5.0.
61  realT dPix; ///< The spacing of the points in the grid search. Default: 0.1.
62 
63  realT minRad; ///< The minimum radius to include in the cost function. Default: 1.0.
64  realT maxRad; ///< The maximum radius to include in the cost function Default: 20.0.
65  realT dRad; ///< The spacing of the radii. Default: 1.0.
66 
67  realT smWidth; ///< FWHM of the Guassian smoothing kernel. Default is 10 (seems to work well regardless of dPix). Set to 0 for no smoothing.
68  realT guessWidth; ///< Guess in original pixels for the FWHM of the cost grid. Default is 0.5, which seems to work well in most cases.
69 
70  ///The fitter for finding the centroid of the grid. You can use this to inspect the details of the fit if desired.
71  //mx::math::fit::fitGaussian2D<mx::gaussian2D_gen_fitter<realT>> fit;
73 
74  realT _x0; ///< Internal storage of the guess center position
75  realT _y0; ///< Internal storage of the guess center position.
76 
78  {
79 
80  mask = 0;
81 
82  init( 5, 0.1, 1.0, 20.0, 1.0);
83 
84  smWidth = 10;
85  guessWidth = 0.5;
86 
87  }
88 
89  ///Initialize the grid.
90  int init( realT maxP, ///< [in] the new value of maxPix
91  realT dP, ///< [in] the new value of dPix
92  realT minR, ///< [in] the new value of minRad
93  realT maxR, ///< [in] the new value of maxRad
94  realT dR ///< [in] the new value of dRad
95  )
96  {
97  maxPix = maxP;
98  dPix = dP;
99  minRad = minR;
100  maxRad = maxR;
101  dRad = dR;
102  return 0;
103  }
104 
105  ///Peform the grid search and fit.
106  int center( realT & x, ///< [out] the x-coordinate of the estimated center of rotational symmetry
107  realT & y, ///< [out] the y-coordinate estimated center of rotational symmetry
108  eigenImage<realT> & im, ///< [in] the image to centroid
109  realT x0, ///< [in] an initial guess at the x-coordinate, the grid is centered about this point.
110  realT y0 ///< [in] an initial guess at the y-coordinate, the grid is centered about this point.
111  )
112  {
113  _x0 = x0;
114  _y0 = y0;
115 
116  bool doMask = false;
117  if( mask )
118  {
119  if( mask->rows() == im.rows() && mask->cols() == im.cols()) doMask = true;
120  }
121 
122  grid.resize( 2*(maxPix/dPix) + 1, 2*(maxPix/dPix) + 1);
123 
124 #ifdef ICCS_OMP
125  #pragma omp parallel
126  {
127 #endif
128  int nRad = (maxRad - minRad)/dRad+1;
129  std::vector< std::vector<realT> > rads;
130  rads.resize( nRad );
131 
132  int N = 2*(maxPix/dPix)+1;
133 
134  realT startX, startY;
135 #ifdef ICCS_OMP
136  #pragma omp for
137 #endif
138  for(int i =0; i<N; ++i)
139  {
140  startX = x0 - maxPix + i*dPix;
141  for(int j=0; j<N;++j)
142  {
143  startY = y0 - maxPix + j*dPix;
144 
145  for(int k =0; k< rads.size(); ++k)
146  {
147  rads[k].clear();
148  }
149 
150  for( int ii = startX - maxRad; ii <= startX+maxRad; ++ii)
151  {
152  for( int jj = startY - maxRad; jj <= startY+maxRad; ++jj)
153  {
154 
155  if(doMask)
156  {
157  if( (*mask)(ii,jj) == 0) continue;
158  }
159 
160  realT rad;
161  rad = sqrt(pow( ii-startX, 2) + pow( jj-startY,2));
162 
163  if(rad < minRad || rad >= maxRad) continue;
164 
165  rads[ (rad-minRad)/dRad ].push_back( im(ii,jj) );
166  }//jj
167  }//ii
168 
169  grid(i,j) = 0;
170 
171  realT mean, var;
172  for(int k =0; k< rads.size(); ++k)
173  {
174  if(rads[k].size() <= 1) continue;
175  mean = math::vectorMean(rads[k]);
176  var = math::vectorVariance(rads[k], mean);
177 
178  grid(i,j) += var/pow(mean,2);
179  }
180  } //j
181  } //i
182 #ifdef ICCS_OMP
183  } //omp parallel
184 #endif
185  //-------- Now Smooth the grid, and multiply by -1 for fitting -------------
186 
187  if(smWidth > 0)
188  {
190  }
191  else
192  {
193  smGrid = grid;
194  }
195 
196  smGrid *= -1;
197 
198 
199  //Get initial guess for the fit.
200  realT mx, mn, gx, gy;
201 
202  mx = smGrid.maxCoeff(&gx, &gy);
203  mn = smGrid.minCoeff();
204 
205 
206  //------------- Now fit the smoothed cost grid to a 2D elliptical Gaussian ------------
207  /** \todo This needs to be able to handle highly non-symmetric peaks much better.
208  */
209  fit.setArray(smGrid.data(), smGrid.rows(), smGrid.cols());
210  fit.setGuess(mn, mx-mn, gx, gy, guessWidth/dPix, guessWidth/dPix, 0);
211 
212  fit.fit();
213 
214  //The estimated enter of circular symmetry from the fit.
215  x = x0 - maxPix + fit.x0()*dPix;
216  y = y0 - maxPix + fit.y0()*dPix;
217 
218 
219  return 0;
220 
221  }
222 
223  ///Output the results to a stream
224  /** Prints a result summary to the input stream.
225  *
226  * \tparam iosT is a std::ostream-like type.
227  * \tparam comment is a comment character to start each line. Can be '\0'.
228  */
229  template<typename iosT, char comment='#'>
230  iosT & dumpResults( iosT & ios )
231  {
232  char c[] = {comment, '\0'};
233 
234  ios << c << "--------------------------------------\n";
235  ios << c << "mx::improc::imCenterCircleSym Results \n";
236  ios << c << "--------------------------------------\n";
237  ios << c << "Estimated x-center: " << _x0 - maxPix + fit.x0()*dPix << "\n";
238  ios << c << "Estimated y-center: " << _y0 - maxPix + fit.y0()*dPix << "\n";
239  ios << c << "Cost half-width: " << 0.5*sigma2fwhm( sqrt( pow(fit.sigma_x(),2) + pow(fit.sigma_y(),2)) * dPix) << " pixels\n";
240  ios << c << "--------------------------------------\n";
241  ios << c << "Setup:\n";
242  ios << c << "--------------------------------------\n";
243  ios << c << "maxPix: " << maxPix << "\n";
244  ios << c << "dPix: " << dPix << "\n";
245  ios << c << "minRad: " << minRad << "\n";
246  ios << c << "maxRad: " << maxRad << "\n";
247  ios << c << "dRad: " << dRad << "\n";
248  ios << c << "smWidth: " << smWidth << "\n";
249  ios << c << "guessWidth: " << guessWidth << "\n";
250  ios << c << "--------------------------------------\n";
251  ios << c << "Fit results:\n" ;
252  fit.dumpReport(ios);
253  ios << c << "--------------------------------------\n";
254 
255  return ios;
256  }
257 
258  ///Output the results to std::cout
259  /** Prints a result summary to std::cout
260  *
261  * \tparam comment is a comment character to start each line. Can be '\0'.
262  */
263  template<char comment ='#'>
264  std::ostream & dumpResults()
265  {
266  return dumpResults<std::ostream, comment>(std::cout);
267  }
268 
269 };
270 
271 } //improc
272 } //mx
273 
274 #endif //__imCenterCircleSym_hpp__
Class to manage fitting a 2D Gaussian to data via the levmarInterface.
Tools for using the eigen library for image processing.
constexpr units::realT c()
The speed of light.
Definition: constants.hpp:60
constexpr units::realT k()
Boltzmann Constant.
Definition: constants.hpp:71
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Definition: eigenImage.hpp:44
floatT sigma2fwhm(floatT sig)
Convert from Gaussian width parameter to FWHM.
Definition: gaussian.hpp:80
void filterImage(imageOutT &fim, imageInT im, kernelT kernel, int maxr=0)
Filter an image with a mean kernel.
valueT vectorMean(const valueT *vec, size_t sz)
Calculate the mean of a vector.
valueT vectorVariance(const valueT *vec, size_t sz, valueT mean)
Calculate the variance of a vector relative to a supplied mean value.
Image filters (smoothing, radial profiles, etc.)
The mxlib c++ namespace.
Definition: mxError.hpp:107
Symetric Gaussian smoothing kernel.
Find the center of the image of a point source using circular symmetry of the PSF.
realT minRad
The minimum radius to include in the cost function. Default: 1.0.
eigenImage< realT > grid
The cost grid.
realT _x0
Internal storage of the guess center position.
realT dRad
The spacing of the radii. Default: 1.0.
int init(realT maxP, realT dP, realT minR, realT maxR, realT dR)
Initialize the grid.
eigenImage< realT > smGrid
The smoothed cost grid.
eigenImage< realT > * mask
An optional pointer to a mask. If not NULL and the same size as the input image, any 0 pixels in this...
mx::math::fit::fitGaussian2Dgen< realT > fit
The fitter for finding the centroid of the grid. You can use this to inspect the details of the fit i...
realT _y0
Internal storage of the guess center position.
realT dPix
The spacing of the points in the grid search. Default: 0.1.
realT smWidth
FWHM of the Guassian smoothing kernel. Default is 10 (seems to work well regardless of dPix)....
iosT & dumpResults(iosT &ios)
Output the results to a stream.
std::ostream & dumpResults()
Output the results to std::cout.
int center(realT &x, realT &y, eigenImage< realT > &im, realT x0, realT y0)
Peform the grid search and fit.
realT maxRad
The maximum radius to include in the cost function Default: 20.0.
realT maxPix
The maximum range of the grid search, the grid will be +/- maxPix. Default: 5.0.
realT guessWidth
Guess in original pixels for the FWHM of the cost grid. Default is 0.5, which seems to work well in m...