LSSTApplications  8.0.0.0+107,8.0.0.1+13,9.1+18,9.2,master-g084aeec0a4,master-g0aced2eed8+6,master-g15627eb03c,master-g28afc54ef9,master-g3391ba5ea0,master-g3d0fb8ae5f,master-g4432ae2e89+36,master-g5c3c32f3ec+17,master-g60f1e072bb+1,master-g6a3ac32d1b,master-g76a88a4307+1,master-g7bce1f4e06+57,master-g8ff4092549+31,master-g98e65bf68e,master-ga6b77976b1+53,master-gae20e2b580+3,master-gb584cd3397+53,master-gc5448b162b+1,master-gc54cf9771d,master-gc69578ece6+1,master-gcbf758c456+22,master-gcec1da163f+63,master-gcf15f11bcc,master-gd167108223,master-gf44c96c709
LSSTDataManagementBasePackage
Classes | Functions | Variables
lsst::meas::base::detail Namespace Reference

Classes

class  SdssShapeImpl
 

Functions

template<typename ImageT >
bool getAdaptiveMoments (ImageT const &mimage, double bkgd, double xcen, double ycen, double shiftmax, SdssShapeImpl *shape, int maxIter, float tol1, float tol2)
 
template<typename ImageT >
std::pair< double, double > getFixedMomentsFlux (ImageT const &image, double bkgd, double xcen, double ycen, SdssShapeImpl const &shape_)
 Return the flux of an object, using the aperture described by the SdssShape object. More...
 

Variables

int const SDSS_SHAPE_MAX_ITER = 100
 
float const SDSS_SHAPE_TOL1 = 1.0e-5
 
float const SDSS_SHAPE_TOL2 = 1.0e-4
 

Function Documentation

template<typename ImageT >
bool lsst::meas::base::detail::getAdaptiveMoments ( ImageT const &  mimage,
double  bkgd,
double  xcen,
double  ycen,
double  shiftmax,
SdssShapeImpl *  shape,
int  maxIter,
float  tol1,
float  tol2 
)

Workhorse for adaptive moments

Calculate adaptive moments from an image

The moments are measured iteratively with a Gaussian window with width equal to the second moments from the previous iteration.

Parameters
mimagethe data to process
bkgdbackground level
xcenx-centre of object
yceny-centre of object
shiftmaxmax allowed centroid shift
shapea place to store desired data
maxIterMaximum number of iterations
tol1Convergence tolerance for e1,e2
tol2Convergence tolerance for FWHM

Definition at line 448 of file SdssShape.cc.

450 {
451  double I0 = 0; // amplitude of best-fit Gaussian
452  double sum; // sum of intensity*weight
453  double sumx, sumy; // sum ((int)[xy])*intensity*weight
454  double sumxx, sumxy, sumyy; // sum {x^2,xy,y^2}*intensity*weight
455  double sums4; // sum intensity*weight*exponent^2
456  float const xcen0 = xcen; // initial centre
457  float const ycen0 = ycen; // of object
458 
459  double sigma11W = 1.5; // quadratic moments of the
460  double sigma12W = 0.0; // weighting fcn;
461  double sigma22W = 1.5; // xx, xy, and yy
462 
463  double w11 = -1, w12 = -1, w22 = -1; // current weights for moments; always set when iter == 0
464  float e1_old = 1e6, e2_old = 1e6; // old values of shape parameters e1 and e2
465  float sigma11_ow_old = 1e6; // previous version of sigma11_ow
466 
467  typename ImageAdaptor<ImageT>::Image const &image = ImageAdaptor<ImageT>().getImage(mimage);
468 
469  if (lsst::utils::isnan(xcen) || lsst::utils::isnan(ycen)) {
470  // Can't do anything
471  shape->setFlag(SdssShapeImpl::UNWEIGHTED_BAD);
472  return false;
473  }
474 
475  bool interpflag = false; // interpolate finer than a pixel?
477  int iter = 0; // iteration number
478  for (; iter < maxIter; iter++) {
479  bbox = set_amom_bbox(image.getWidth(), image.getHeight(), xcen, ycen, sigma11W, sigma12W, sigma22W);
480  boost::tuple<std::pair<bool, double>, double, double, double> weights =
481  getWeights(sigma11W, sigma12W, sigma22W);
482  if (!weights.get<0>().first) {
483  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
484  break;
485  }
486 
487  double const detW = weights.get<0>().second;
488 
489 #if 0 // this form was numerically unstable on my G4 powerbook
490  assert(detW >= 0.0);
491 #else
492  assert(sigma11W*sigma22W >= sigma12W*sigma12W - std::numeric_limits<float>::epsilon());
493 #endif
494 
495  {
496  const double ow11 = w11; // old
497  const double ow12 = w12; // values
498  const double ow22 = w22; // of w11, w12, w22
499 
500  w11 = weights.get<1>();
501  w12 = weights.get<2>();
502  w22 = weights.get<3>();
503 
504  if (shouldInterp(sigma11W, sigma22W, detW)) {
505  if (!interpflag) {
506  interpflag = true; // N.b.: stays set for this object
507  if (iter > 0) {
508  sigma11_ow_old = 1.e6; // force at least one more iteration
509  w11 = ow11;
510  w12 = ow12;
511  w22 = ow22;
512  iter--; // we didn't update wXX
513  }
514  }
515  }
516  }
517 
518  if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
519  &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, &sums4) < 0) {
520  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
521  break;
522  }
523 #if 0
524 /*
525  * Find new centre
526  *
527  * This is only needed if we update the centre; if we use the input position we've already done the work
528  */
529  xcen = sumx/sum;
530  ycen = sumy/sum;
531 #endif
532  shape->setX(sumx/sum); // update centroid. N.b. we're not setting errors here
533  shape->setY(sumy/sum);
534 
535  if (fabs(shape->getX() - xcen0) > shiftmax || fabs(shape->getY() - ycen0) > shiftmax) {
536  shape->setFlag(SdssShapeImpl::SHIFT);
537  }
538 /*
539  * OK, we have the centre. Proceed to find the second moments.
540  */
541  float const sigma11_ow = sumxx/sum; // quadratic moments of
542  float const sigma22_ow = sumyy/sum; // weight*object
543  float const sigma12_ow = sumxy/sum; // xx, xy, and yy
544 
545  if (sigma11_ow <= 0 || sigma22_ow <= 0) {
546  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
547  break;
548  }
549 
550  float const d = sigma11_ow + sigma22_ow; // current values of shape parameters
551  float const e1 = (sigma11_ow - sigma22_ow)/d;
552  float const e2 = 2.0*sigma12_ow/d;
553 /*
554  * Did we converge?
555  */
556  if (iter > 0 &&
557  fabs(e1 - e1_old) < tol1 && fabs(e2 - e2_old) < tol1 &&
558  fabs(sigma11_ow/sigma11_ow_old - 1.0) < tol2 ) {
559  break; // yes; we converged
560  }
561 
562  e1_old = e1;
563  e2_old = e2;
564  sigma11_ow_old = sigma11_ow;
565 /*
566  * Didn't converge, calculate new values for weighting function
567  *
568  * The product of two Gaussians is a Gaussian:
569  * <x^2 exp(-a x^2 - 2bxy - cy^2) exp(-Ax^2 - 2Bxy - Cy^2)> =
570  * <x^2 exp(-(a + A) x^2 - 2(b + B)xy - (c + C)y^2)>
571  * i.e. the inverses of the covariances matrices add.
572  *
573  * We know sigmaXX_ow and sigmaXXW, the covariances of the weighted object
574  * and of the weights themselves. We can estimate the object's covariance as
575  * sigmaXX_ow^-1 - sigmaXXW^-1
576  * and, as we want to find a set of weights with the _same_ covariance as the
577  * object we take this to be the an estimate of our correct weights.
578  *
579  * N.b. This assumes that the object is roughly Gaussian.
580  * Consider the object:
581  * O == delta(x + p) + delta(x - p)
582  * the covariance of the weighted object is equal to that of the unweighted
583  * object, and this prescription fails badly. If we detect this, we set
584  * the UNWEIGHTED flag, and calculate the UNweighted moments
585  * instead.
586  */
587  {
588  float n11, n12, n22; // elements of inverse of next guess at weighting function
589  float ow11, ow12, ow22; // elements of inverse of sigmaXX_ow
590 
591  boost::tuple<std::pair<bool, double>, double, double, double> weights =
592  getWeights(sigma11_ow, sigma12_ow, sigma22_ow);
593  if (!weights.get<0>().first) {
594  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
595  break;
596  }
597 
598  ow11 = weights.get<1>();
599  ow12 = weights.get<2>();
600  ow22 = weights.get<3>();
601 
602  n11 = ow11 - w11;
603  n12 = ow12 - w12;
604  n22 = ow22 - w22;
605 
606  weights = getWeights(n11, n12, n22, false);
607  if (!weights.get<0>().first) {
608  // product-of-Gaussians assumption failed
609  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
610  break;
611  }
612 
613  sigma11W = weights.get<1>();
614  sigma12W = weights.get<2>();
615  sigma22W = weights.get<3>();
616  }
617 
618  if (sigma11W <= 0 || sigma22W <= 0) {
619  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
620  break;
621  }
622  }
623 
624  if (iter == maxIter) {
625  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
626  shape->setFlag(SdssShapeImpl::MAXITER);
627  }
628 
629  if (sumxx + sumyy == 0.0) {
630  shape->setFlag(SdssShapeImpl::UNWEIGHTED);
631  }
632 /*
633  * Problems; try calculating the un-weighted moments
634  */
635  if (shape->getFlag(SdssShapeImpl::UNWEIGHTED)) {
636  w11 = w22 = w12 = 0;
637  if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
638  &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, NULL) < 0 || sum <= 0) {
639  shape->resetFlag(SdssShapeImpl::UNWEIGHTED);
640  shape->setFlag(SdssShapeImpl::UNWEIGHTED_BAD);
641 
642  if (sum > 0) {
643  shape->setIxx(1/12.0); // a single pixel
644  shape->setIxy(0.0);
645  shape->setIyy(1/12.0);
646  }
647 
648  return false;
649  }
650 
651  sigma11W = sumxx/sum; // estimate of object moments
652  sigma12W = sumxy/sum; // usually, object == weight
653  sigma22W = sumyy/sum; // at this point
654  }
655 
656  shape->setI0(I0);
657  shape->setIxx(sigma11W);
658  shape->setIxy(sigma12W);
659  shape->setIyy(sigma22W);
660  shape->setIxy4(sums4/sum);
661 
662  if (shape->getIxx() + shape->getIyy() != 0.0) {
663  int const ix = lsst::afw::image::positionToIndex(xcen);
664  int const iy = lsst::afw::image::positionToIndex(ycen);
665 
666  if (ix >= 0 && ix < mimage.getWidth() && iy >= 0 && iy < mimage.getHeight()) {
667  float const bkgd_var =
668  ImageAdaptor<ImageT>().getVariance(mimage, ix, iy); // XXX Overestimate as it includes object
669 
670  if (bkgd_var > 0.0) { // NaN is not > 0.0
671  if (!(shape->getFlag(SdssShapeImpl::UNWEIGHTED))) {
672  SdssShapeImpl::Matrix4 fisher = calc_fisher(*shape, bkgd_var); // Fisher matrix
673  shape->setCovar(fisher.inverse());
674  }
675  }
676  }
677  }
678 
679  return true;
680 }
int positionToIndex(double pos)
Convert image position to nearest integer index.
Definition: ImageUtils.h:69
int iter
int isnan(T t)
Definition: ieee.h:110
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
int d
Definition: KDTree.cc:89
double sum
Definition: NaiveFlux.cc:137
template<typename ImageT >
std::pair< double, double > lsst::meas::base::detail::getFixedMomentsFlux ( ImageT const &  image,
double  bkgd,
double  xcen,
double  ycen,
SdssShapeImpl const &  shape_ 
)

Return the flux of an object, using the aperture described by the SdssShape object.

The SdssShape algorithm calculates an elliptical Gaussian fit to an object, so the "aperture" is an elliptical Gaussian

Returns
A std::pair of the flux and its error
Parameters
imagethe data to process
bkgdbackground level
xcenx-centre of object (PARENT coordinates)
yceny-centre of object (PARENT coordinates)
shape_The SdssShape of the object

Definition at line 692 of file SdssShape.cc.

698 {
699  SdssShapeImpl shape = shape_; // we need a mutable copy
700 
701  afwGeom::BoxI const& bbox = set_amom_bbox(image.getWidth(), image.getHeight(), xcen, ycen,
702  shape.getIxx(), shape.getIxy(), shape.getIyy());
703 
704  boost::tuple<std::pair<bool, double>, double, double, double> weights =
705  getWeights(shape.getIxx(), shape.getIxy(), shape.getIyy());
706  double const NaN = std::numeric_limits<double>::quiet_NaN();
707  if (!weights.get<0>().first) {
708  return std::make_pair(NaN, NaN);
709  }
710 
711  double const w11 = weights.get<1>();
712  double const w12 = weights.get<2>();
713  double const w22 = weights.get<3>();
714  bool const interp = shouldInterp(shape.getIxx(), shape.getIyy(), weights.get<0>().second);
715 
716  double I0 = 0; // amplitude of Gaussian
717  calcmom<true>(ImageAdaptor<ImageT>().getImage(image), xcen - image.getX0(), ycen - image.getY0(),
718  bbox, bkgd, interp, w11, w12, w22,
719  &I0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
720  /*
721  * We have enerything we need, but it isn't quite packaged right; we need an initialised SdssShapeImpl
722  */
723  shape.setI0(I0);
724 
725  {
726  int ix = static_cast<int>(xcen - image.getX0());
727  int iy = static_cast<int>(ycen - image.getY0());
728  float bkgd_var =
729  ImageAdaptor<ImageT>().getVariance(image, ix, iy); // XXX Overestimate as it includes object
730 
731  SdssShapeImpl::Matrix4 fisher = calc_fisher(shape, bkgd_var); // Fisher matrix
732 
733  shape.setCovar(fisher.inverse());
734  }
735 
736  double const scale = shape.getFluxScale();
737  return std::make_pair(shape.getI0()*scale, shape.getI0Err()*scale);
738 }
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117

Variable Documentation

int const lsst::meas::base::detail::SDSS_SHAPE_MAX_ITER = 100

Definition at line 12 of file SdssShapeImpl.h.

float const lsst::meas::base::detail::SDSS_SHAPE_TOL1 = 1.0e-5

Definition at line 13 of file SdssShapeImpl.h.

float const lsst::meas::base::detail::SDSS_SHAPE_TOL2 = 1.0e-4

Definition at line 14 of file SdssShapeImpl.h.