23 #include "ndarray/eigen.h"
32 namespace lsst {
namespace meas {
namespace base {
34 #define USE_WEIGHT 0 // zweight is only set, not used. It isn't even set if this is false
44 typedef Eigen::Matrix<double, FittedModel::NPARAM, FittedModel::NPARAM> Matrix;
45 typedef Eigen::Matrix<double, FittedModel::NPARAM, 1> Vector;
47 template<
typename PixelT>
48 explicit Fit2d(afw::image::Image<PixelT>
const& im) :
wide(32),
rast(
wide*
wide) {
49 ncols = im.getWidth();
50 nrows = im.getHeight();
107 static void dcalc2(Fit2d *fit,
108 Fit2d::Vector
const &el,
109 Fit2d::Matrix *
alpha,
124 }
else if (s <= 0.0) {
139 for (
int i = 0, nrast = fit->rast.size(); i != nrast; i++) {
140 double const dx = (fit->rast[i].x -
x0)/s;
141 double const dy = (fit->rast[i].y -
y0)/s;
142 double const d = hypot(dx, dy);
144 if (d >= fit->dc2zmin && d <= fit->
dc2zmax) {
145 double const arg = exp(-d*d/2.0);
146 double const funct = a*arg +
b;
149 df << arg, 1.0, a*arg*dx/s, a*arg*dy/s, a*arg*(dx*dx/s + dy*dy/s);
151 double const r = fit->rast[i].zo - funct;
154 *alpha += df*df.transpose();
164 fit->stnew = sqrt(fit->chnew/nu);
171 static void curf2(Fit2d *fit) {
176 if (fit->iter == 0) {
177 dcalc2(fit, fit->elnew, &fit->alnew, &fit->benew);
178 if (fit->status != 0) {
181 fit->nref = fit->nin;
187 fit->chold = fit->chnew;
188 fit->stold = fit->stnew;
189 fit->elold = fit->elnew;
190 fit->sgold = fit->sgnew;
191 fit->beold = fit->benew;
192 fit->alold = fit->alnew;
197 for (
int poor = 0; poor != NPLIM; ++poor) {
199 if (fit->alnew(j, j) == 0.0) {
204 fit->alpha(j, k) = fit->alnew(j, k)/sqrt(fit->alnew(j, j)*fit->alnew(k, k));
206 fit->alpha(j, j) = 1.0 + fit->flamd;
212 fit->alpha.computeInverse();
214 Eigen::FullPivLU<Fit2d::Matrix> alphaLU(fit->alpha);
215 if (!alphaLU.isInvertible()) {
219 fit->alpha = alphaLU.inverse();
227 fit->elnew[j] += fit->benew[k]*fit->alpha(j,k)/sqrt(fit->alnew(j, j)*fit->alnew(k, k));
233 dcalc2(fit, fit->elnew, &fit->alnew, &fit->benew);
240 fit->sgnew[j] = fit->stnew*sqrt(fabs(fit->alpha(j, j)/fit->alnew(j, j)));
245 if (fit->status == 0.0 && fit->stnew <= fit->stold) {
246 fit->flamd = fit->flamd/fit->xlamd;
252 fit->flamd = 3.0*fit->flamd;
253 fit->chnew = fit->chold;
254 fit->stnew = fit->stold;
255 fit->elnew = fit->elold;
256 fit->sgnew = fit->sgold;
257 fit->benew = fit->beold;
258 fit->alnew = fit->alold;
266 static void cond2(Fit2d *fit) {
270 if (fit->iter <= 3) {
274 if (fit->flamd < fit->flamdok) {
281 if (fit->status < 0) {
288 if (fit->chnew <= 0.0) {
304 if (ex > fit->lost || ey > fit->lost) {
311 double const ratio = (fit->stnew - fit->stold)/fit->stnew;
312 if (ratio > fit->ratiomin) {
314 }
else if (fit->iter > fit->nitmax) {
325 template<
typename PixelT>
326 static void fg2(afw::image::Image<PixelT>
const& im,
327 double x0,
double y0,
333 int ix0 =
static_cast<int>(x0 + 0.5);
334 int iy0 =
static_cast<int>(y0 + 0.5);
335 if(ix0 < fit->
tooclose || im.getWidth() - ix0 < fit->tooclose ||
336 iy0 < fit->tooclose || im.getHeight() - iy0 < fit->tooclose) {
342 double peak = im(jx0, jy0);
346 double const w = fit->wide/2;
347 int xl =
static_cast<int>(ix0 - w + 0.5);
351 int xh =
static_cast<int>(xl + 2*w + 0.5);
352 if (xh > im.getWidth()) {
355 int yl =
static_cast<int>(iy0 - w + 0.5);
359 int yh =
static_cast<int>(yl + 2*w + 0.5);
360 if (yh > im.getHeight()) {
364 double sky = im(xl, yl);
366 for (
int y = yl;
y != yh; ++
y) {
367 for (
int x = xl;
x != xh; ++
x) {
368 fit->rast[put].x =
x;
369 fit->rast[put].y =
y;
370 fit->rast[put].zo = im(
x,
y);
372 fit->rast[put].zweight = 1.0;
374 if (im(
x,
y) < sky) {
377 double const ex =
x - ix0;
378 double const ey =
y - iy0;
379 double const er = hypot(ex, ey);
380 if (er <= fit->
lost) {
381 if (im(
x,
y) > peak) {
390 fit->rast.resize(put);
397 double xmax = xh - 1;
399 double ymax = yh - 1;
400 double const test = 0.5*(im(ix0, iy0) + sky);
401 for (
int x = ix0;
x < xh - 1; ++
x) {
402 if (im(
x + 1, iy0) <= test) {
403 double a = test - im(
x, iy0);
404 double b = im(
x + 1, iy0) - im(
x, iy0);
406 xmax =
x + ((b == 0.0) ? 0.5 : a/
b);
410 for (
int x = ix0;
x > 0; --
x) {
411 if (im(
x - 1, iy0) <= test) {
412 double a = test - im(
x, iy0);
413 double b = im(
x - 1, iy0) - im(
x, iy0);
415 xmin =
x - ((b == 0.0) ? 0.5 : a/
b);
419 for (
int y = iy0;
y < yh - 1; ++
y) {
420 if (im(ix0,
y + 1) <= test) {
421 double a = test - im(ix0,
y);
422 double b = im(ix0,
y + 1) - im(ix0,
y);
424 ymax =
y + ((b == 0.0) ? 0.5 : a/
b);
428 for (
int y = iy0;
y > 0; --
y) {
429 if (im(ix0,
y - 1) <= test) {
430 double a = test - im(ix0,
y);
431 double b = im(ix0,
y - 1) - im(ix0,
y);
433 ymin =
y - ((b == 0.0) ? 0.5 : a/
b);
448 fit->elnew = fit->param;
457 template<
typename PixelT>
458 FittedModel twodg(afw::image::Image<PixelT>
const& im,
469 fg2(im, x0, y0, &fit);
470 if (fit.status != 0) {
472 std::copy(&fit.elnew[0], &fit.elnew[0] + fit.elnew.size(), params.begin());
474 return FittedModel(fit.status, params);
479 for (fit.iter = 0; fit.status == 0; ++fit.iter) {
485 std::copy(&fit.elnew[0], &fit.elnew[0] + fit.elnew.size(), params.begin());
487 return FittedModel(fit.status, params, fit.iter, fit.flamd, fit.chnew);
492 #define MAKE_TWODG(IMAGE_T) \
493 template FittedModel twodg(IMAGE_T const& im, double x0, double y0)
499 std::array<FlagDefinition,GaussianCentroidAlgorithm::N_FLAGS>
const &
getFlagDefinitions() {
500 static std::array<FlagDefinition,GaussianCentroidAlgorithm::N_FLAGS>
const flagDefs = {{
501 {
"flag",
"general failure flag, set if anything went wrong"},
502 {
"flag_noPeak",
"Fitted Centroid has a negative peak"}
511 std::string
const &
name,
519 _centroidExtractor(schema, name, true),
520 _centroidChecker(schema, name, ctrl.doFootprintCheck, ctrl.maxDistToPeak)
525 template<
typename PixelT>
544 result.
x = center.getX();
545 result.
y = center.getY();
550 int x =
static_cast<int>(center.getX() + 0.5);
551 int y =
static_cast<int>(center.getY() + 0.5);
579 #define MAKE_FIT_CENTROID(IMAGE_T) \
580 template afw::geom::Point2D GaussianCentroidAlgorithm::fitCentroid(IMAGE_T const &, double, double)
587 std::string
const &
name,
593 mapper.
addMapping(mapper.getInputSchema().find<afw::table::Flag>(
594 mapper.getInputSchema().join(
name, flag->name)).key);
Defines the fields and offsets for a table.
GaussianCentroidAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
std::vector< Raster > rast
double indexToPosition(double ind)
Convert image index to image position.
table::Key< std::string > name
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=NULL) const
Handle an exception thrown by the current algorithm by setting flags in the given record...
afw::table::Schema schema
A mapping between the keys of two Schemas, used to copy data between them.
A reusable struct for centroid measurements.
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
ImagePtr getImage(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage's image.
std::array< FlagDefinition, BlendednessAlgorithm::N_FLAGS > const & getFlagDefinitions()
Exception to be thrown when a measurement algorithm experiences a known failure mode.
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
FlagDefinition getDefinition(std::size_t i) const
Return the FlagDefinition object that corresponds to a particular enum value.
table::Key< table::Array< Kernel::Pixel > > image
Utility class for handling flag fields that indicate the failure modes of an algorithm.
MaskedImageT getMaskedImage()
Return the MaskedImage.
std::vector< double > params
A C++ control class to handle GaussianCentroidAlgorithm's configuration.
CentroidChecker _centroidChecker
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given enum value.
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Called to measure a single child source in an image.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
#define MAKE_TWODG(IMAGE_T)
Algorithm provides no uncertainy information at all.
A FunctorKey for CentroidResult.
afw::table::Key< double > b
CentroidElement y
y (row) coordinate of the measured position
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=NULL) const
Handle an expected or unexpected Exception thrown by a measurement algorithm.
Point< double, 2 > Point2D
#define MAKE_FIT_CENTROID(IMAGE_T)
Record class that contains measurements made on a single exposure.
A class to represent a 2-dimensional array of pixels.
CentroidResultKey _centroidKey
Key< T > addMapping(Key< T > const &inputKey, bool doReplace=false)
Add a new field to the output Schema that is a copy of a field in the input Schema.
SafeCentroidExtractor _centroidExtractor