26#include "ndarray/eigen.h"
40FlagDefinitionList flagDefinitions;
45 flagDefinitions.add(
"flag_edge",
"Object too close to edge; peak used.");
47 flagDefinitions.add(
"flag_noSecondDerivative",
"Vanishing second derivative");
49 flagDefinitions.add(
"flag_almostNoSecondDerivative",
"Almost vanishing second derivative");
51 flagDefinitions.add(
"flag_notAtMaximum",
"Object is not at a maximum");
53 flagDefinitions.add(
"flag_near_edge",
"Object close to edge; fallback kernel used.");
73 float const d2 =
sp +
sm;
74 float const s = 0.5 * (
vp -
vm);
80 *cen = s / d2 * (1.0 + AMPAST4 * sp * sm / (d2 * v0));
82 return fabs(*cen) < 1 ? 0 : 1;
89float astrom_errors(
float skyVar,
99 double const k = quarticBad ? 0 : AMPAST4;
112 sVar += 0.5 * sourceVar * exp(-1 / (2 * tau2));
113 dVar += sourceVar * (4 * exp(-1 / (2 * tau2)) + 2 * exp(-1 / (2 * tau2)));
119 dVar += sourceVar / (3 *
geom::PI *
sigma2) * (2 - 3 *
exp(-1 / (3 * sigma2)) +
exp(-1 / sigma2));
122 xVar = sVar *
pow(1 / d + k / (4 * As) * (1 - 12 * s * s / (d * d)), 2) +
123 dVar *
pow(s / (d * d) - k / (4 * As) * 8 * s * s / (d * d * d), 2);
125 return (xVar >= 0 ?
sqrt(xVar) : NAN);
133template <
typename ImageXy_locatorT,
typename VarImageXy_locatorT>
134int doMeasureCentroidImpl(
double *xCenter,
138 double *sizeX2,
double *sizeY2,
140 VarImageXy_locatorT vim,
141 double smoothingSigma,
142 FlagHandler flagHandler) {
146 double const d2x = 2 * im(0, 0) - im(-1, 0) - im(1, 0);
147 double const d2y = 2 * im(0, 0) - im(0, -1) - im(0, 1);
148 double const sx = 0.5 * (im(1, 0) - im(-1, 0));
149 double const sy = 0.5 * (im(0, 1) - im(0, -1));
151 if (d2x == 0.0 || d2y == 0.0) {
154 if (d2x < 0.0 || d2y < 0.0) {
158 double const dx0 = sx / d2x;
159 double const dy0 = sy / d2y;
161 if (
fabs(dx0) > 10.0 ||
fabs(dy0) > 10.0) {
165 double vpk = im(0, 0) + 0.5 * (sx * dx0 + sy * dy0);
172 float m0x = 0, m1x = 0, m2x = 0;
173 float m0y = 0, m1y = 0, m2y = 0;
176 quarticBad += inter4(im(-1, -1), im(0, -1), im(1, -1), &m0x);
177 quarticBad += inter4(im(-1, 0), im(0, 0), im(1, 0), &m1x);
178 quarticBad += inter4(im(-1, 1), im(0, 1), im(1, 1), &m2x);
180 quarticBad += inter4(im(-1, -1), im(-1, 0), im(-1, 1), &m0y);
181 quarticBad += inter4(im(0, -1), im(0, 0), im(0, 1), &m1y);
182 quarticBad += inter4(im(1, -1), im(1, 0), im(1, 1), &m2y);
185 double sigmaX2, sigmaY2;
193 double const smx = 0.5 * (m2x - m0x);
194 double const smy = 0.5 * (m2y - m0y);
195 double const dm2x = m1x - 0.5 * (m0x + m2x);
196 double const dm2y = m1y - 0.5 * (m0y + m2y);
197 double const dx = m1x + dy0 * (smx - dy0 * dm2x);
198 double const dy = m1y + dx0 * (smy - dx0 * dm2y);
199 double const dx4 = m1x + dy * (smx - dy * dm2x);
200 double const dy4 = m1y + dx * (smy - dx * dm2y);
204 sigmaX2 = vpk / d2x - (1 + 6 * dx0 * dx0) / 4;
205 sigmaY2 = vpk / d2y - (1 + 6 * dy0 * dy0) / 4;
210 float tauX2 = sigmaX2;
211 float tauY2 = sigmaY2;
212 tauX2 -= smoothingSigma * smoothingSigma;
213 tauY2 -= smoothingSigma * smoothingSigma;
215 if (tauX2 <= smoothingSigma * smoothingSigma) {
216 tauX2 = smoothingSigma * smoothingSigma;
218 if (tauY2 <= smoothingSigma * smoothingSigma) {
219 tauY2 = smoothingSigma * smoothingSigma;
222 float const skyVar = (vim(-1, -1) + vim(0, -1) + vim(1, -1) + vim(-1, 0) + vim(1, 0) + vim(-1, 1) +
223 vim(0, 1) + vim(1, 1)) /
225 float const sourceVar = vim(0, 0);
226 float const A = vpk *
sqrt((sigmaX2 / tauX2) * (sigmaY2 / tauY2));
231 *dxc = astrom_errors(skyVar, sourceVar, A, tauX2, vpk, sx, d2x,
fabs(smoothingSigma), quarticBad);
232 *dyc = astrom_errors(skyVar, sourceVar, A, tauY2, vpk, sy, d2y,
fabs(smoothingSigma), quarticBad);
239template <
typename MaskedImageXy_locatorT>
240int doMeasureCentroidImpl(
double *xCenter,
244 double *sizeX2,
double *sizeY2,
246 MaskedImageXy_locatorT mim,
247 double smoothingSigma,
248 bool negative, FlagHandler flagHandler) {
252 double const d2x = 2 * mim.image(0, 0) - mim.image(-1, 0) - mim.image(1, 0);
253 double const d2y = 2 * mim.image(0, 0) - mim.image(0, -1) - mim.image(0, 1);
254 double const sx = 0.5 * (mim.image(1, 0) - mim.image(-1, 0));
255 double const sy = 0.5 * (mim.image(0, 1) - mim.image(0, -1));
257 if (d2x == 0.0 || d2y == 0.0) {
260 if ((!negative && (d2x < 0.0 || d2y < 0.0)) || (negative && (d2x > 0.0 || d2y > 0.0))) {
264 double const dx0 = sx / d2x;
265 double const dy0 = sy / d2y;
267 if (
fabs(dx0) > 10.0 ||
fabs(dy0) > 10.0) {
271 double vpk = mim.image(0, 0) + 0.5 * (sx * dx0 + sy * dy0);
278 float m0x = 0, m1x = 0, m2x = 0;
279 float m0y = 0, m1y = 0, m2y = 0;
282 quarticBad += inter4(mim.image(-1, -1), mim.image(0, -1), mim.image(1, -1), &m0x, negative);
283 quarticBad += inter4(mim.image(-1, 0), mim.image(0, 0), mim.image(1, 0), &m1x, negative);
284 quarticBad += inter4(mim.image(-1, 1), mim.image(0, 1), mim.image(1, 1), &m2x, negative);
286 quarticBad += inter4(mim.image(-1, -1), mim.image(-1, 0), mim.image(-1, 1), &m0y, negative);
287 quarticBad += inter4(mim.image(0, -1), mim.image(0, 0), mim.image(0, 1), &m1y, negative);
288 quarticBad += inter4(mim.image(1, -1), mim.image(1, 0), mim.image(1, 1), &m2y, negative);
291 double sigmaX2, sigmaY2;
299 double const smx = 0.5 * (m2x - m0x);
300 double const smy = 0.5 * (m2y - m0y);
301 double const dm2x = m1x - 0.5 * (m0x + m2x);
302 double const dm2y = m1y - 0.5 * (m0y + m2y);
303 double const dx = m1x + dy0 * (smx - dy0 * dm2x);
304 double const dy = m1y + dx0 * (smy - dx0 * dm2y);
305 double const dx4 = m1x + dy * (smx - dy * dm2x);
306 double const dy4 = m1y + dx * (smy - dx * dm2y);
310 sigmaX2 = vpk / d2x - (1 + 6 * dx0 * dx0) / 4;
311 sigmaY2 = vpk / d2y - (1 + 6 * dy0 * dy0) / 4;
316 float tauX2 = sigmaX2;
317 float tauY2 = sigmaY2;
318 tauX2 -= smoothingSigma * smoothingSigma;
319 tauY2 -= smoothingSigma * smoothingSigma;
321 if (tauX2 <= smoothingSigma * smoothingSigma) {
322 tauX2 = smoothingSigma * smoothingSigma;
324 if (tauY2 <= smoothingSigma * smoothingSigma) {
325 tauY2 = smoothingSigma * smoothingSigma;
329 (mim.variance(-1, -1) + mim.variance(0, -1) + mim.variance(1, -1) + mim.variance(-1, 0) +
330 mim.variance(1, 0) + mim.variance(-1, 1) + mim.variance(0, 1) + mim.variance(1, 1)) /
332 float const sourceVar = mim.variance(0, 0);
333 float const A = vpk *
sqrt((sigmaX2 / tauX2) * (sigmaY2 / tauY2));
338 *dxc = astrom_errors(skyVar, sourceVar, A, tauX2, vpk, sx, d2x,
fabs(smoothingSigma), quarticBad);
339 *dyc = astrom_errors(skyVar, sourceVar, A, tauY2, vpk, sy, d2y,
fabs(smoothingSigma), quarticBad);
348template <
typename MaskedImageT>
350 const int y, MaskedImageT
const &mimage,
int binX,
int binY,
351 FlagHandler _flagHandler) {
352 geom::Point2D const center(x + mimage.getX0(), y + mimage.getY0());
353 afw::geom::ellipses::Quadrupole
const &shape =
psf->computeShape(center);
354 double const smoothingSigma = shape.getDeterminantRadius();
356 double const nEffective =
psf->computeEffectiveArea();
358 double const nEffective = 4 * M_PI * smoothingSigma * smoothingSigma;
362 int const kWidth = kernel->getWidth();
363 int const kHeight = kernel->getHeight();
366 geom::ExtentI(binX * (3 + kWidth + 1), binY * (3 + kHeight + 1)));
375 binnedImage->setXY0(subImage->getXY0());
377 MaskedImageT smoothedImage = MaskedImageT(*binnedImage,
true);
378 if(smoothedImage.getWidth() / 2 != kWidth / 2 + 2 ||
379 smoothedImage.getHeight() / 2 != kHeight / 2 + 2) {
383 afw::math::convolve(smoothedImage, *binnedImage, *kernel, afw::math::ConvolutionControl());
384 *smoothedImage.getVariance() *= binX * binY * nEffective;
410 typedef MaskedImageT::Image
ImageT;
411 typedef MaskedImageT::Variance
VarianceT;
415 }
catch (pexExcept::Exception &
e) {
446 psf = std::make_shared<afw::detection::GaussianPsf>(5, 5, 0.5);
465 MaskedImageT::xy_locator mim =
471 errorFlag =
doMeasureCentroidImpl(&
xc, &
dxc, &
yc, &
dyc, &
sizeX2, &
sizeY2, &
peakVal, mim,
smoothingSigma,
negative,
524 _flagHandler.handleFailure(
measRecord, error);
533 if (
mapper.getInputSchema().getNames().count(
mapper.getInputSchema().join(
name, flag.
name)) == 0)
536 mapper.getInputSchema().find<afw::table::Flag>(
name +
"_" + flag.
name).key;
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
table::Key< double > sigma2
afw::table::Key< double > sigma
This implements the SdssCentroid algorithm within the meas_base measurement framework.
A FunctorKey for CentroidResult.
Exception to be thrown when a measurement algorithm experiences a fatal error.
vector-type utility class to build a collection of FlagDefinitions
Utility class for handling flag fields that indicate the failure modes of an algorithm.
Exception to be thrown when a measurement algorithm experiences a known failure mode.
static FlagDefinition const NOT_AT_MAXIMUM
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.
SdssCentroidAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
static FlagDefinition const NO_SECOND_DERIVATIVE
static FlagDefinition const FAILURE
static FlagDefinition const NEAR_EDGE
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()
static FlagDefinition const ALMOST_NO_SECOND_DERIVATIVE
static FlagDefinition const EDGE
A C++ control class to handle SdssCentroidAlgorithm's configuration.
double wfac
"fiddle factor for adjusting the binning" ;
int binmax
"maximum allowed binning" ;
double peakMin
"if the peak's less than this insist on binning at least once" ;
double indexToPosition(double ind)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
std::shared_ptr< ImageT > binImage(ImageT const &inImage, int const binX, int const binY, lsst::afw::math::Property const flags=lsst::afw::math::MEAN)
Point< double, 2 > Point2D
@ SIGMA_ONLY
Only the diagonal elements of the covariance matrix are provided.
A reusable struct for centroid measurements.
CentroidElement x
x (column) coordinate of the measured position
Simple class used to define and document flags The name and doc constitute the identity of the FlagDe...