26 #include "ndarray/eigen.h" 
   39 FlagDefinitionList flagDefinitions;
 
   44         flagDefinitions.add(
"flag_edge", 
"Object too close to edge");
 
   46         flagDefinitions.add(
"flag_noSecondDerivative", 
"Vanishing second derivative");
 
   48         flagDefinitions.add(
"flag_almostNoSecondDerivative", 
"Almost vanishing second derivative");
 
   50         flagDefinitions.add(
"flag_notAtMaximum", 
"Object is not at a maximum");
 
   58 float const AMPAST4 = 1.33;  
 
   67 static int inter4(
float vm, 
float v0, 
float vp, 
float *cen, 
bool negative = 
false) {
 
   68     float const sp = v0 - vp;
 
   69     float const sm = v0 - vm;
 
   70     float const d2 = sp + sm;
 
   71     float const s = 0.5 * (vp - vm);
 
   73     if ((!negative && (d2 <= 0.0f || v0 <= 0.0f)) || (negative && (d2 >= 0.0f || v0 >= 0.0f))) {
 
   77     *cen = s / d2 * (1.0 + AMPAST4 * sp * sm / (d2 * v0));
 
   79     return fabs(*cen) < 1 ? 0 : 1;
 
   86 float astrom_errors(
float skyVar,      
 
   96     double const k = quarticBad ? 0 : AMPAST4; 
 
  109         sVar += 0.5 * sourceVar * exp(-1 / (2 * tau2));
 
  110         dVar += sourceVar * (4 * exp(-1 / (2 * tau2)) + 2 * exp(-1 / (2 * tau2)));
 
  119     xVar = sVar * 
pow(1 / d + k / (4 * As) * (1 - 12 * s * s / (d * d)), 2) +
 
  120            dVar * 
pow(s / (d * d) - k / (4 * As) * 8 * s * s / (d * d * d), 2);
 
  122     return (xVar >= 0 ? 
sqrt(xVar) : NAN);
 
  130 template <
typename ImageXy_locatorT, 
typename VarImageXy_locatorT>
 
  131 void doMeasureCentroidImpl(
double *xCenter,                 
 
  135                            double *sizeX2, 
double *sizeY2,  
 
  137                            VarImageXy_locatorT vim,         
 
  138                            double smoothingSigma,  
 
  139                            FlagHandler flagHandler) {
 
  143     double const d2x = 2 * im(0, 0) - im(-1, 0) - im(1, 0);
 
  144     double const d2y = 2 * im(0, 0) - im(0, -1) - im(0, 1);
 
  145     double const sx = 0.5 * (im(1, 0) - im(-1, 0));
 
  146     double const sy = 0.5 * (im(0, 1) - im(0, -1));
 
  148     if (d2x == 0.0 || d2y == 0.0) {
 
  152     if (d2x < 0.0 || d2y < 0.0) {
 
  155                                   (
boost::format(
": d2I/dx2, d2I/dy2 = %g %g") % d2x % d2y).str(),
 
  159     double const dx0 = sx / d2x;
 
  160     double const dy0 = sy / d2y;  
 
  162     if (
fabs(dx0) > 10.0 || 
fabs(dy0) > 10.0) {
 
  166                         (
boost::format(
": sx, d2x, sy, d2y = %f %f %f %f") % sx % d2x % sy % d2y).str(),
 
  170     double vpk = im(0, 0) + 0.5 * (sx * dx0 + sy * dy0);  
 
  177     float m0x = 0, m1x = 0, m2x = 0;
 
  178     float m0y = 0, m1y = 0, m2y = 0;
 
  181     quarticBad += inter4(im(-1, -1), im(0, -1), im(1, -1), &m0x);
 
  182     quarticBad += inter4(im(-1, 0), im(0, 0), im(1, 0), &m1x);
 
  183     quarticBad += inter4(im(-1, 1), im(0, 1), im(1, 1), &m2x);
 
  185     quarticBad += inter4(im(-1, -1), im(-1, 0), im(-1, 1), &m0y);
 
  186     quarticBad += inter4(im(0, -1), im(0, 0), im(0, 1), &m1y);
 
  187     quarticBad += inter4(im(1, -1), im(1, 0), im(1, 1), &m2y);
 
  190     double sigmaX2, sigmaY2;  
 
  198         double const smx = 0.5 * (m2x - m0x);
 
  199         double const smy = 0.5 * (m2y - m0y);
 
  200         double const dm2x = m1x - 0.5 * (m0x + m2x);
 
  201         double const dm2y = m1y - 0.5 * (m0y + m2y);
 
  202         double const dx = m1x + dy0 * (smx - dy0 * dm2x);  
 
  203         double const dy = m1y + dx0 * (smy - dx0 * dm2y);
 
  204         double const dx4 = m1x + dy * (smx - dy * dm2x);  
 
  205         double const dy4 = m1y + dx * (smy - dx * dm2y);
 
  209         sigmaX2 = vpk / d2x - (1 + 6 * dx0 * dx0) / 4;  
 
  210         sigmaY2 = vpk / d2y - (1 + 6 * dy0 * dy0) / 4;  
 
  215     float tauX2 = sigmaX2;  
 
  216     float tauY2 = sigmaY2;
 
  217     tauX2 -= smoothingSigma * smoothingSigma;  
 
  218     tauY2 -= smoothingSigma * smoothingSigma;
 
  220     if (tauX2 <= smoothingSigma * smoothingSigma) {  
 
  221         tauX2 = smoothingSigma * smoothingSigma;
 
  223     if (tauY2 <= smoothingSigma * smoothingSigma) {  
 
  224         tauY2 = smoothingSigma * smoothingSigma;
 
  227     float const skyVar = (vim(-1, -1) + vim(0, -1) + vim(1, -1) + vim(-1, 0) + vim(1, 0) + vim(-1, 1) +
 
  228                           vim(0, 1) + vim(1, 1)) /
 
  230     float const sourceVar = vim(0, 0);  
 
  231     float const A = vpk * 
sqrt((sigmaX2 / tauX2) * (sigmaY2 / tauY2));  
 
  236     *dxc = astrom_errors(skyVar, sourceVar, A, tauX2, vpk, sx, d2x, 
fabs(smoothingSigma), quarticBad);
 
  237     *dyc = astrom_errors(skyVar, sourceVar, A, tauY2, vpk, sy, d2y, 
fabs(smoothingSigma), quarticBad);
 
  243 template <
typename MaskedImageXy_locatorT>
 
  244 void doMeasureCentroidImpl(
double *xCenter,                 
 
  248                            double *sizeX2, 
double *sizeY2,  
 
  250                            MaskedImageXy_locatorT mim,      
 
  251                            double smoothingSigma,  
 
  252                            bool negative, FlagHandler flagHandler) {
 
  256     double const d2x = 2 * mim.image(0, 0) - mim.image(-1, 0) - mim.image(1, 0);
 
  257     double const d2y = 2 * mim.image(0, 0) - mim.image(0, -1) - mim.image(0, 1);
 
  258     double const sx = 0.5 * (mim.image(1, 0) - mim.image(-1, 0));
 
  259     double const sy = 0.5 * (mim.image(0, 1) - mim.image(0, -1));
 
  261     if (d2x == 0.0 || d2y == 0.0) {
 
  265     if ((!negative && (d2x < 0.0 || d2y < 0.0)) || (negative && (d2x > 0.0 || d2y > 0.0))) {
 
  268                                   (
boost::format(
": d2I/dx2, d2I/dy2 = %g %g") % d2x % d2y).str(),
 
  272     double const dx0 = sx / d2x;
 
  273     double const dy0 = sy / d2y;  
 
  275     if (
fabs(dx0) > 10.0 || 
fabs(dy0) > 10.0) {
 
  279                         (
boost::format(
": sx, d2x, sy, d2y = %f %f %f %f") % sx % d2x % sy % d2y).str(),
 
  283     double vpk = mim.image(0, 0) + 0.5 * (sx * dx0 + sy * dy0);  
 
  290     float m0x = 0, m1x = 0, m2x = 0;
 
  291     float m0y = 0, m1y = 0, m2y = 0;
 
  294     quarticBad += inter4(mim.image(-1, -1), mim.image(0, -1), mim.image(1, -1), &m0x, negative);
 
  295     quarticBad += inter4(mim.image(-1, 0), mim.image(0, 0), mim.image(1, 0), &m1x, negative);
 
  296     quarticBad += inter4(mim.image(-1, 1), mim.image(0, 1), mim.image(1, 1), &m2x, negative);
 
  298     quarticBad += inter4(mim.image(-1, -1), mim.image(-1, 0), mim.image(-1, 1), &m0y, negative);
 
  299     quarticBad += inter4(mim.image(0, -1), mim.image(0, 0), mim.image(0, 1), &m1y, negative);
 
  300     quarticBad += inter4(mim.image(1, -1), mim.image(1, 0), mim.image(1, 1), &m2y, negative);
 
  303     double sigmaX2, sigmaY2;  
 
  311         double const smx = 0.5 * (m2x - m0x);
 
  312         double const smy = 0.5 * (m2y - m0y);
 
  313         double const dm2x = m1x - 0.5 * (m0x + m2x);
 
  314         double const dm2y = m1y - 0.5 * (m0y + m2y);
 
  315         double const dx = m1x + dy0 * (smx - dy0 * dm2x);  
 
  316         double const dy = m1y + dx0 * (smy - dx0 * dm2y);
 
  317         double const dx4 = m1x + dy * (smx - dy * dm2x);  
 
  318         double const dy4 = m1y + dx * (smy - dx * dm2y);
 
  322         sigmaX2 = vpk / d2x - (1 + 6 * dx0 * dx0) / 4;  
 
  323         sigmaY2 = vpk / d2y - (1 + 6 * dy0 * dy0) / 4;  
 
  328     float tauX2 = sigmaX2;  
 
  329     float tauY2 = sigmaY2;
 
  330     tauX2 -= smoothingSigma * smoothingSigma;  
 
  331     tauY2 -= smoothingSigma * smoothingSigma;
 
  333     if (tauX2 <= smoothingSigma * smoothingSigma) {  
 
  334         tauX2 = smoothingSigma * smoothingSigma;
 
  336     if (tauY2 <= smoothingSigma * smoothingSigma) {  
 
  337         tauY2 = smoothingSigma * smoothingSigma;
 
  341             (mim.variance(-1, -1) + mim.variance(0, -1) + mim.variance(1, -1) + mim.variance(-1, 0) +
 
  342              mim.variance(1, 0) + mim.variance(-1, 1) + mim.variance(0, 1) + mim.variance(1, 1)) /
 
  344     float const sourceVar = mim.variance(0, 0);  
 
  345     float const A = vpk * 
sqrt((sigmaX2 / tauX2) * (sigmaY2 / tauY2));  
 
  350     *dxc = astrom_errors(skyVar, sourceVar, A, tauX2, vpk, sx, d2x, 
fabs(smoothingSigma), quarticBad);
 
  351     *dyc = astrom_errors(skyVar, sourceVar, A, tauY2, vpk, sy, d2y, 
fabs(smoothingSigma), quarticBad);
 
  359 template <
typename MaskedImageT>
 
  361                                                   const int y, MaskedImageT 
const &mimage, 
int binX, 
int binY,
 
  362                                                   FlagHandler _flagHandler) {
 
  364     afw::geom::ellipses::Quadrupole 
const &shape = 
psf->computeShape(center);
 
  365     double const smoothingSigma = shape.getDeterminantRadius();
 
  367     double const nEffective = 
psf->computeEffectiveArea(); 
 
  369     double const nEffective = 4 * 
M_PI * smoothingSigma * smoothingSigma;  
 
  373     int const kWidth = kernel->getWidth();
 
  374     int const kHeight = kernel->getHeight();
 
  377                     geom::ExtentI(binX * (3 + kWidth + 1), binY * (3 + kHeight + 1)));
 
  380     PTR(MaskedImageT) subImage;
 
  383     } 
catch (pex::exceptions::LengthError &err) {
 
  388     binnedImage->setXY0(subImage->getXY0());
 
  390     MaskedImageT smoothedImage = MaskedImageT(*binnedImage, 
true);
 
  391     assert(smoothedImage.getWidth() / 2 == kWidth / 2 + 2);  
 
  392     assert(smoothedImage.getHeight() / 2 == kHeight / 2 + 2);
 
  394     afw::math::convolve(smoothedImage, *binnedImage, *kernel, afw::math::ConvolutionControl());
 
  395     *smoothedImage.getVariance() *= binX * binY * nEffective;  
 
  410           _centroidChecker(
schema, 
name, ctrl.doFootprintCheck, ctrl.maxDistToPeak) {}
 
  414     geom::Point2D center = _centroidExtractor(measRecord, _flagHandler);
 
  421     typedef MaskedImageT::Image ImageT;
 
  422     typedef MaskedImageT::Variance VarianceT;
 
  423     bool negative = 
false;
 
  425         negative = measRecord.
get(measRecord.
getSchema().
find<afw::table::Flag>(
"flags_negative").key);
 
  430     ImageT 
const &
image = *mimage.getImage();
 
  448     double xc = 0., yc = 0., dxc = 0., dyc = 0.;  
 
  449     for (
int binsize = 1; binsize <= _ctrl.
binmax; binsize *= 2) {
 
  451                 smoothAndBinImage(
psf, 
x, 
y, mimage, binX, binY, _flagHandler);
 
  452         MaskedImageT 
const smoothedImage = 
result.first;
 
  453         double const smoothingSigma = 
result.second;
 
  455         MaskedImageT::xy_locator mim =
 
  456                 smoothedImage.xy_at(smoothedImage.getWidth() / 2, smoothedImage.getHeight() / 2);
 
  458         double sizeX2, sizeY2;  
 
  461         doMeasureCentroidImpl(&xc, &dxc, &yc, &dyc, &sizeX2, &sizeY2, &peakVal, mim, smoothingSigma, negative,
 
  466             xc = (xc + 0.5) * binX - 0.5;
 
  468             sizeX2 *= binX * binX;
 
  470             yc = (yc + 0.5) * binY - 0.5;
 
  472             sizeY2 *= binY * binY;
 
  478         double const fac = _ctrl.
wfac * (1 + smoothingSigma * smoothingSigma);
 
  479         double const facX2 = fac * binX * binX;
 
  480         double const facY2 = fac * binY * binY;
 
  482         if (sizeX2 < facX2 && ::pow(xc - 
x, 2) < facX2 && sizeY2 < facY2 && ::pow(yc - 
y, 2) < facY2) {
 
  483             if (binsize > 1 || _ctrl.
peakMin < 0.0 || peakVal > _ctrl.
peakMin) {
 
  488         if (sizeX2 >= facX2 || ::pow(xc - 
x, 2) >= facX2) {
 
  491         if (sizeY2 >= facY2 || ::pow(yc - 
y, 2) >= facY2) {
 
  498     result.xErr = sqrt(dxc * dxc);
 
  499     result.yErr = sqrt(dyc * dyc);
 
  501     _centroidChecker(measRecord);
 
  505     _flagHandler.handleFailure(measRecord, 
error);
 
  514         if (
mapper.getInputSchema().getNames().count(
mapper.getInputSchema().join(
name, flag.
name)) == 0)