LSSTApplications  11.0-22-g33de520,13.0+148,14.0+46,14.0+49,14.0-1-g013352c+30,14.0-1-g13ef843+9,14.0-1-g4b114ac+12,14.0-1-g7257b6a+10,14.0-1-g8b7e855+45,14.0-10-g59393990+4,14.0-13-g7a60b79,14.0-14-g87d16e8+8,14.0-16-g7a4f44b+1,14.0-2-g319577b+9,14.0-2-g8373656+25,14.0-2-ga5af9b6+8,14.0-21-g4f575af+3,14.0-42-g1a25f2ae,14.0-42-g99f9a3040,14.0-5-g744ff5f,14.0-5-g86eb1bd+25,14.0-6-g095d685+2,14.0-6-gd5b81a9,14.0-6-ge2c9487+36,14.0-8-g1f982c9,14.0-8-g7f6dd6b+6,14.0-8-gc7d89b4+3
LSSTDataManagementBasePackage
GaussianCentroid.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2013 LSST Corporation.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 #include "ndarray/eigen.h"
24 #include "lsst/afw/table/Source.h"
26 
27 #include <algorithm>
28 #include "Eigen/Core"
29 #include "Eigen/LU"
30 
31 
32 namespace lsst { namespace meas { namespace base {
33 namespace {
34 FlagDefinitionList flagDefinitions;
35 } // end anonymous
36 
37 FlagDefinition const GaussianCentroidAlgorithm::FAILURE = flagDefinitions.addFailureFlag();
38 FlagDefinition const GaussianCentroidAlgorithm::NO_PEAK = flagDefinitions.add("flag_noPeak", "Fitted Centroid has a negative peak");
39 
41  return flagDefinitions;
42 }
43 
44 namespace {
45 #define USE_WEIGHT 0 // zweight is only set, not used. It isn't even set if this is false
46 struct Raster {
47  int x, y; // x, y index of rastered pixel
48  double zo; // pixel's value
49 #if USE_WEIGHT
50  double zweight; // weight for the pixel
51 #endif
52 };
53 
54 struct Fit2d {
55  typedef Eigen::Matrix<double, FittedModel::NPARAM, FittedModel::NPARAM> Matrix;
56  typedef Eigen::Matrix<double, FittedModel::NPARAM, 1> Vector;
57 
58  template<typename PixelT>
59  explicit Fit2d(afw::image::Image<PixelT> const& im) : wide(32), rast(wide*wide) {
60  ncols = im.getWidth();
61  nrows = im.getHeight();
62 
63  dc2zmin = 0.3;
64  dc2zmax = 3.5;
65  tooclose = 3;
66  toosmall = 1.5;
67  nitmax = 15;
68  flamdok = 1.0e-7;
69  ratiomin = -1.0e-7;
70  lost = 3.5;
71  xlamd = 5.0;
72 
73  iter = 0;
74  flamd = 1.0;
75  }
76 
77  int wide; // patch of image being fitted is wide*wide
78  std::vector<Raster> rast; // The pixels being fitted, thought of as a raster scan
79  int nin;
80  int nref;
81  int iter;
82  int tooclose;
83  Vector param;
84  Matrix alpha;
85  Vector beta;
86  Vector elold;
87  Vector elnew;
88  Vector sgold;
89  Vector sgnew;
90  Matrix alold;
91  Matrix alnew;
92  Vector beold;
93  Vector benew;
94  double chisq;
95  double chold;
96  double stold;
97  double chnew;
98  double stnew;
99  double flamd;
100  double flamdok;
101  double xlamd;
102  double ratiomin;
103  int nitmax;
104  double dc2zmin;
105  double dc2zmax;
106  double lost;
107  double toosmall; // minimum acceptable width
108  int ncols; // number of columns in image
109  int nrows; // number of rows in image
110  int status; // status of processing
111 };
112 
113 /************************************************************************************************************/
118 static void dcalc2(Fit2d *fit, // the struct carrying all the fit information
119  Fit2d::Vector const &el, // current parameters of the fit
120  Fit2d::Matrix *alpha, // desired alpha matrix
121  Fit2d::Vector *beta // desired beta vector
122  ) {
123 /*
124  * Pass arguments and initialize
125  */
126  double const a = el[FittedModel::PEAK];
127  double const b = el[FittedModel::SKY];
128  double const x0 = el[FittedModel::X0];
129  double const y0 = el[FittedModel::Y0];
130  double const s = el[FittedModel::SIGMA];
131 
132  if (a <= 0.0) {
133  fit->status = FittedModel::BAD_A;
134  return;
135  } else if (s <= 0.0) {
136  fit->status = FittedModel::BAD_WIDTH;
137  return;
138  } else {
139  fit->status = 0;
140  }
141 
142  beta->setZero();
143  alpha->setZero();
144 
145  fit->nin = 0;
146  fit->chnew = 0.0;
147 /*
148  * Examine all pixels in raster
149  */
150  for (int i = 0, nrast = fit->rast.size(); i != nrast; i++) {
151  double const dx = (fit->rast[i].x - x0)/s;
152  double const dy = (fit->rast[i].y - y0)/s;
153  double const d = hypot(dx, dy);
154 
155  if (d >= fit->dc2zmin && d <= fit->dc2zmax) {
156  double const arg = exp(-d*d/2.0);
157  double const funct = a*arg + b;
158 
159  Fit2d::Vector df;
160  df << arg, 1.0, a*arg*dx/s, a*arg*dy/s, a*arg*(dx*dx/s + dy*dy/s);
161 
162  double const r = fit->rast[i].zo - funct; // residual
163  fit->chnew += r*r;
164  *beta += r*df;
165  *alpha += df*df.transpose(); // outer product
166 
167  fit->nin++;
168  }
169  }
170  int nu = fit->nin - (FittedModel::NPARAM + 1); // number of degrees of freedom
171  if (nu <= 0) {
172  fit->status = FittedModel::TOO_FEW;
173  return;
174  }
175  fit->stnew = sqrt(fit->chnew/nu);
176 }
177 
178 /************************************************************************************************************/
179 /*
180  * From Bevington's CURFIT
181  */
182 static void curf2(Fit2d *fit) {
183 /*
184  * Initialization
185  */
186  fit->status = 0;
187  if (fit->iter == 0) {
188  dcalc2(fit, fit->elnew, &fit->alnew, &fit->benew);
189  if (fit->status != 0) {
190  return;
191  }
192  fit->nref = fit->nin;
193  fit->stnew = sqrt(fit->chnew/(fit->nref - (FittedModel::NPARAM + 1)));
194  }
195 /*
196  * Save Current Parameters
197  */
198  fit->chold = fit->chnew;
199  fit->stold = fit->stnew;
200  fit->elold = fit->elnew;
201  fit->sgold = fit->sgnew;
202  fit->beold = fit->benew;
203  fit->alold = fit->alnew;
204 /*
205  * Previous Call To DCALC Used To Fill Current
206  */
207  int const NPLIM = 4;
208  for (int poor = 0; poor != NPLIM; ++poor) {
209  for (int j = 0; j != FittedModel::NPARAM; ++j) {
210  if (fit->alnew(j, j) == 0.0) {
211  fit->status = FittedModel::DIAGONAL;
212  return;
213  }
214  for (int k = 0; k != FittedModel::NPARAM; ++k) {
215  fit->alpha(j, k) = fit->alnew(j, k)/sqrt(fit->alnew(j, j)*fit->alnew(k, k));
216  }
217  fit->alpha(j, j) = 1.0 + fit->flamd;
218  }
219 /*
220  * Inversion.
221  */
222 #if 0
223  fit->alpha.computeInverse(); // has no way to check if inverse succeeded
224 #else
225  Eigen::FullPivLU<Fit2d::Matrix> alphaLU(fit->alpha);
226  if (!alphaLU.isInvertible()) {
227  fit->status = -1;
228  return;
229  }
230  fit->alpha = alphaLU.inverse();
231 #endif
232 
233 /*
234  * New Elements
235  */
236  for (int j = 0; j != FittedModel::NPARAM; ++j) {
237  for (int k = 0; k != FittedModel::NPARAM; ++k) {
238  fit->elnew[j] += fit->benew[k]*fit->alpha(j,k)/sqrt(fit->alnew(j, j)*fit->alnew(k, k));
239  }
240  }
241 /*
242  * Compute Current Chi-Squared And Next ALPHA+BETA
243  */
244  dcalc2(fit, fit->elnew, &fit->alnew, &fit->benew);
245  if (fit->status == FittedModel::TOO_FEW) {
246  return;
247  }
248  fit->stnew = sqrt(fit->chnew/(fit->nref - (FittedModel::NPARAM + 1)));
249 
250  for (int j = 0; j != FittedModel::NPARAM; ++j) {
251  fit->sgnew[j] = fit->stnew*sqrt(fabs(fit->alpha(j, j)/fit->alnew(j, j)));
252  }
253 /*
254  * Quick Return If Solution Got Better
255  */
256  if (fit->status == 0.0 && fit->stnew <= fit->stold) {
257  fit->flamd = fit->flamd/fit->xlamd;
258  return;
259  }
260 /*
261  * Undo Solution And Try Again
262  */
263  fit->flamd = 3.0*fit->flamd;
264  fit->chnew = fit->chold;
265  fit->stnew = fit->stold;
266  fit->elnew = fit->elold;
267  fit->sgnew = fit->sgold;
268  fit->benew = fit->beold;
269  fit->alnew = fit->alold;
270  }
271 }
272 
273 /************************************************************************************************************/
274 /*
275  * Test of convergence or fatal errors
276  */
277 static void cond2(Fit2d *fit) {
278 /*
279  * Ignore CURF errors for these conditions
280  */
281  if (fit->iter <= 3) {
282  fit->status = 0;
283  return;
284  }
285  if (fit->flamd < fit->flamdok) {
286  fit->status = FittedModel::ALMOST;
287  return;
288  }
289 /*
290  * Catch Fatal Errors
291  */
292  if (fit->status < 0) {
293  return;
294  }
295  if (fit->nin < FittedModel::NPARAM + 1) {
296  fit->status = FittedModel::TOO_FEW;
297  return;
298  }
299  if (fit->chnew <= 0.0) {
300  fit->status = FittedModel::CHI_SQUARED;
301  return;
302  }
303  if (fit->elnew[FittedModel::X0] < 0.0 || fit->elnew[FittedModel::X0] > fit->ncols ||
304  fit->elnew[FittedModel::Y0] < 0.0 || fit->elnew[FittedModel::Y0] > fit->nrows) {
305  fit->status = FittedModel::RANGE;
306  return;
307  }
308  if (fit->elnew[FittedModel::SIGMA] < 0.0) {
309  fit->status = FittedModel::BAD_WIDTH;
310  return;
311  }
312 
313  double const ex = fabs(fit->param[FittedModel::X0] - fit->elnew[FittedModel::X0]);
314  double const ey = fabs(fit->param[FittedModel::Y0] - fit->elnew[FittedModel::Y0]);
315  if (ex > fit->lost || ey > fit->lost) {
316  fit->status = FittedModel::LOST;
317  return;
318  }
319 /*
320  * Test for convergence
321  */
322  double const ratio = (fit->stnew - fit->stold)/fit->stnew;
323  if (ratio > fit->ratiomin) {
324  fit->status = (fit->flamd < 0.001) ? FittedModel::CONVERGE : FittedModel::POOR;
325  } else if (fit->iter > fit->nitmax) {
326  fit->status = FittedModel::ITERATE;
327  } else {
328  fit->status = 0;
329  }
330 }
331 
332 /************************************************************************************************************/
333 /*
334  * First guess for 2-D Gaussian
335  */
336 template<typename PixelT>
337 static void fg2(afw::image::Image<PixelT> const& im,
338  double x0, double y0,
339  Fit2d *fit
340  ) {
341 /*
342  * Sanity Check
343  */
344  int ix0 = static_cast<int>(x0 + 0.5);
345  int iy0 = static_cast<int>(y0 + 0.5);
346  if(ix0 < fit->tooclose || im.getWidth() - ix0 < fit->tooclose ||
347  iy0 < fit->tooclose || im.getHeight() - iy0 < fit->tooclose) {
348  fit->status = FittedModel::BAD_GUESS;
349  return;
350  }
351  int jx0 = ix0;
352  int jy0 = iy0;
353  double peak = im(jx0, jy0);
354 /*
355  * Extract interesting portion
356  */
357  double const w = fit->wide/2;
358  int xl = static_cast<int>(ix0 - w + 0.5);
359  if (xl < 0) {
360  xl = 0;
361  }
362  int xh = static_cast<int>(xl + 2*w + 0.5);
363  if (xh > im.getWidth()) {
364  xh = im.getWidth();
365  }
366  int yl = static_cast<int>(iy0 - w + 0.5);
367  if (yl < 0) {
368  yl = 0;
369  }
370  int yh = static_cast<int>(yl + 2*w + 0.5);
371  if (yh > im.getHeight()) {
372  yh = im.getHeight();
373  }
374 
375  double sky = im(xl, yl);
376  int put = 0;
377  for (int y = yl; y != yh; ++y) {
378  for (int x = xl; x != xh; ++x) {
379  fit->rast[put].x = x;
380  fit->rast[put].y = y;
381  fit->rast[put].zo = im(x, y);
382 #if USE_WEIGHT
383  fit->rast[put].zweight = 1.0;
384 #endif
385  if (im(x, y) < sky) {
386  sky = im(x, y);
387  }
388  double const ex = x - ix0;
389  double const ey = y - iy0;
390  double const er = hypot(ex, ey);
391  if (er <= fit->lost) {
392  if (im(x, y) > peak) {
393  jx0 = x;
394  jy0 = y;
395  peak = im(x, y);
396  }
397  }
398  put++;
399  }
400  }
401  fit->rast.resize(put);
402  ix0 = jx0;
403  iy0 = jy0;
404 /*
405  * Look For FWHM
406  */
407  double xmin = xl;
408  double xmax = xh - 1;
409  double ymin = yl;
410  double ymax = yh - 1;
411  double const test = 0.5*(im(ix0, iy0) + sky); // pixel value of half-maximum above sky
412  for (int x = ix0; x < xh - 1; ++x) {
413  if (im(x + 1, iy0) <= test) {
414  double a = test - im(x, iy0);
415  double b = im(x + 1, iy0) - im(x, iy0);
416 
417  xmax = x + ((b == 0.0) ? 0.5 : a/b);
418  break;
419  }
420  }
421  for (int x = ix0; x > 0; --x) {
422  if (im(x - 1, iy0) <= test) {
423  double a = test - im(x, iy0);
424  double b = im(x - 1, iy0) - im(x, iy0);
425 
426  xmin = x - ((b == 0.0) ? 0.5 : a/b);
427  break;
428  }
429  }
430  for (int y = iy0; y < yh - 1; ++y) {
431  if (im(ix0, y + 1) <= test) {
432  double a = test - im(ix0, y);
433  double b = im(ix0, y + 1) - im(ix0, y);
434 
435  ymax = y + ((b == 0.0) ? 0.5 : a/b);
436  break;
437  }
438  }
439  for (int y = iy0; y > 0; --y) {
440  if (im(ix0, y - 1) <= test) {
441  double a = test - im(ix0, y);
442  double b = im(ix0, y - 1) - im(ix0, y);
443 
444  ymin = y - ((b == 0.0) ? 0.5 : a/b);
445  break;
446  }
447  }
448 /*
449  * Assemble the fitting vector
450  */
451  fit->param[FittedModel::PEAK] = im(ix0, iy0) - sky;
452  fit->param[FittedModel::SKY] = sky;
453  fit->param[FittedModel::X0] = x0;
454  fit->param[FittedModel::Y0] = y0;
455  fit->param[FittedModel::SIGMA] = 0.5*((xmax - xmin)+(ymax - ymin))/2.354;
456  if (fit->param[FittedModel::SIGMA] < fit->toosmall) {
457  fit->param[FittedModel::SIGMA] = fit->toosmall;
458  }
459  fit->elnew = fit->param;
460 
461  fit->status = 0;
462 }
463 
464 /************************************************************************************************************/
468 template<typename PixelT>
469 FittedModel twodg(afw::image::Image<PixelT> const& im,
470  double x0,
471  double y0
472  ) {
473 /*
474  * Initialize the fitting structure
475  */
476  Fit2d fit(im);
477 /*
478  * Initialization
479  */
480  fg2(im, x0, y0, &fit);
481  if (fit.status != 0) {
483  std::copy(&fit.elnew[0], &fit.elnew[0] + fit.elnew.size(), params.begin());
484 
485  return FittedModel(fit.status, params);
486  }
487 /*
488  * Find best-fit model
489  */
490  for (fit.iter = 0; fit.status == 0; ++fit.iter) {
491  curf2(&fit);
492  cond2(&fit);
493  }
494 
496  std::copy(&fit.elnew[0], &fit.elnew[0] + fit.elnew.size(), params.begin());
497 
498  return FittedModel(fit.status, params, fit.iter, fit.flamd, fit.chnew);
499 }
500 //
501 // Explicit instantiations
502 //
503 #define MAKE_TWODG(IMAGE_T) \
504  template FittedModel twodg(IMAGE_T const& im, double x0, double y0)
505 
506 MAKE_TWODG(afw::image::Image<float>);
507 MAKE_TWODG(afw::image::Image<double>);
508 MAKE_TWODG(afw::image::Image<int>);
509 
510 
511 } // end anonymous namespace
512 
514  Control const & ctrl,
515  std::string const & name,
517 ) : _ctrl(ctrl),
518  _centroidKey(
519  CentroidResultKey::addFields(schema, name, "centroid from Gaussian Centroid algorithm", NO_UNCERTAINTY)
520  ),
521  _flagHandler(FlagHandler::addFields(schema, name,
522  getFlagDefinitions())),
523  _centroidExtractor(schema, name, true),
524  _centroidChecker(schema, name, ctrl.doFootprintCheck, ctrl.maxDistToPeak)
525 {
526 }
527 
528 
529 template<typename PixelT>
531  double x,
532  double y
533 ) {
534  base::FittedModel fit = base::twodg(image, x, y);
535  double const xCen = fit.params[base::FittedModel::X0];
536  double const yCen = fit.params[base::FittedModel::Y0];
537  return afw::geom::Point2D(xCen, yCen);
538 }
539 
540 
542  afw::table::SourceRecord & measRecord,
543  afw::image::Exposure<float> const & exposure
544 ) const {
545  // get our current best guess about the centroid: either a centroider measurement or peak.
546  afw::geom::Point2D center = _centroidExtractor(measRecord, _flagHandler);
547  CentroidResult result;
548  result.x = center.getX();
549  result.y = center.getY();
550  measRecord.set(_centroidKey, result); // better than NaN
551  typedef afw::image::Image<float> ImageT;
552  ImageT const& image = *exposure.getMaskedImage().getImage();
553 
554  int x = static_cast<int>(center.getX() + 0.5);
555  int y = static_cast<int>(center.getY() + 0.5);
556 
557  x -= image.getX0(); // work in image Pixel coordinates
558  y -= image.getY0();
559 
560  FittedModel fit = twodg(image, x, y); // here's the fitter
561  if (fit.params[FittedModel::PEAK] <= 0) {
562  throw LSST_EXCEPT(
564  NO_PEAK.doc,
566  );
567  }
568  result.x = lsst::afw::image::indexToPosition(image.getX0()) + fit.params[FittedModel::X0];
569  result.y = lsst::afw::image::indexToPosition(image.getY0()) + fit.params[FittedModel::Y0];
570  _flagHandler.setValue(measRecord, FAILURE.number, false); // if we had a suspect flag, we'd set that instead
571  measRecord.set(_centroidKey, result);
572  _centroidChecker(measRecord);
573 }
574 
575 
577  _flagHandler.handleFailure(measRecord, error);
578 }
579 
580 //
581 // Explicit instantiations
582 //
583 #define MAKE_FIT_CENTROID(IMAGE_T) \
584  template afw::geom::Point2D GaussianCentroidAlgorithm::fitCentroid(IMAGE_T const &, double, double)
585 
586 MAKE_FIT_CENTROID(afw::image::Image<float>);
587 MAKE_FIT_CENTROID(afw::image::Image<double>);
588 
590  Control const & ctrl,
591  std::string const & name,
592  afw::table::SchemaMapper & mapper
593 ) :
594  CentroidTransform{name, mapper}
595 {
598  if (flag == GaussianCentroidAlgorithm::FAILURE) continue;
599  if (mapper.getInputSchema().getNames().count(
600  mapper.getInputSchema().join(name, flag.name)) == 0) continue;
601  afw::table::Key<afw::table::Flag> key = mapper.getInputSchema().find<afw::table::Flag>(
602  name + "_" + flag.name).key;
603  mapper.addMapping(key);
604  }
605 }
606 
607 }}} // namespace lsst::meas::base
608 
609 
int y
int iter
std::size_t size() const
return the current size (number of defined elements) of the collection
Definition: FlagHandler.h:133
Defines the fields and offsets for a table.
Definition: Schema.h:47
int tooclose
GaussianCentroidAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
int nref
int ncols
solver_t * s
T copy(T... args)
std::vector< Raster > rast
double xlamd
Matrix alold
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:55
table::Key< std::string > name
Definition: ApCorrMap.cc:71
Vector beold
afw::table::Schema schema
Definition: GaussianPsf.cc:43
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
Simple class used to define and document flags The name and doc constitute the identity of the FlagDe...
Definition: FlagHandler.h:38
A reusable struct for centroid measurements.
Vector elold
Vector sgold
static afw::geom::Point2D fitCentroid(afw::image::Image< PixelT > const &im, double x0, double y0)
Compute centroids with 2-D Gaussian fitter.
CentroidElement x
x (column) coordinate of the measured position
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given flag index.
Definition: FlagHandler.h:276
Exception to be thrown when a measurement algorithm experiences a known failure mode.
Definition: exceptions.h:48
Vector benew
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=nullptr) const
Handle an exception thrown by the current algorithm by setting flags in the given record...
int nrows
Matrix alpha
Vector param
ImagePtr getImage() const
Return a (shared_ptr to) the MaskedImage&#39;s image.
Definition: MaskedImage.h:1042
STL class.
Vector sgnew
double stnew
Utility class for handling flag fields that indicate the failure modes of an algorithm.
Definition: FlagHandler.h:156
Matrix alnew
double toosmall
A base class for image defects.
Definition: cameraGeom.dox:3
MaskedImageT getMaskedImage()
Return the MaskedImage.
Definition: Exposure.h:209
double w
Definition: CoaddPsf.cc:57
std::vector< double > params
Point< double, 2 > Point2D
Definition: Point.h:300
double dc2zmin
double flamd
A C++ control class to handle GaussianCentroidAlgorithm&#39;s configuration.
int wide
table::Key< int > b
double dc2zmax
double chold
double stold
int x
int nin
double chisq
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
GaussianCentroidTransform(Control const &ctrl, std::string const &name, afw::table::SchemaMapper &mapper)
double flamdok
STL class.
int nitmax
double zo
#define MAKE_TWODG(IMAGE_T)
T begin(T... args)
int status
double chnew
Algorithm provides no uncertainy information at all.
Definition: constants.h:42
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Called to measure a single child source in an image.
static FlagDefinitionList const & getFlagDefinitions()
Vector elnew
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=nullptr) const
Handle an expected or unexpected Exception thrown by a measurement algorithm.
Definition: FlagHandler.cc:93
A FunctorKey for CentroidResult.
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Definition: BaseRecord.h:136
CentroidElement y
y (row) coordinate of the measured position
table::Key< int > a
#define MAKE_FIT_CENTROID(IMAGE_T)
Record class that contains measurements made on a single exposure.
Definition: Source.h:80
double ratiomin
vector-type utility class to build a collection of FlagDefinitions
Definition: FlagHandler.h:63
double lost
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:69
Base for centroid measurement transformations.
Vector beta