27 #include "boost/tuple/tuple.hpp" 29 #include "lsst/afw/image.h" 30 #include "lsst/afw/detection/Psf.h" 31 #include "lsst/afw/geom/Angle.h" 32 #include "lsst/afw/geom/ellipses.h" 33 #include "lsst/afw/table/Source.h" 38 namespace pexPolicy = lsst::pex::policy;
39 namespace pexExceptions = lsst::pex::exceptions;
40 namespace afwDet = lsst::afw::detection;
41 namespace afwImage = lsst::afw::image;
42 namespace afwGeom = lsst::afw::geom;
43 namespace afwTable = lsst::afw::table;
45 namespace lsst {
namespace meas {
namespace base {
47 FlagDefinitionList flagDefinitions;
52 FlagDefinition
const SdssShapeAlgorithm::UNWEIGHTED = flagDefinitions.add(
"flag_unweighted",
"Weighted moments converged to an invalid value; using unweighted moments");
53 FlagDefinition
const SdssShapeAlgorithm::SHIFT = flagDefinitions.add(
"flag_shift",
"centroid shifted by more than the maximum allowed amount");
58 return flagDefinitions;
64 typedef Eigen::Matrix<double,4,4,Eigen::DontAlign> Matrix4d;
74 double const Mxx = result.
xx;
75 double const Mxy = result.
xy;
76 double const Myy = result.
yy;
78 double const Muu_p_Mvv = Mxx + Myy;
79 double const Muu_m_Mvv = ::sqrt(::pow(Mxx - Myy, 2) + 4*::pow(Mxy, 2));
80 double const Muu = 0.5*(Muu_p_Mvv + Muu_m_Mvv);
81 double const Mvv = 0.5*(Muu_p_Mvv - Muu_m_Mvv);
83 return lsst::afw::geom::TWOPI * ::sqrt(Muu*Mvv);
102 float const A = shape.
flux;
103 float const sigma11W = shape.
xx;
104 float const sigma12W = shape.
xy;
105 float const sigma22W = shape.
yy;
107 double const D = sigma11W*sigma22W - sigma12W*sigma12W;
109 if (D <= std::numeric_limits<double>::epsilon()) {
110 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
111 "Determinant is too small calculating Fisher matrix");
116 if (bkgd_var <= 0.0) {
117 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
118 (boost::format(
"Background variance must be positive (saw %g)") % bkgd_var).str());
120 double const F = afwGeom::PI*sqrt(D)/bkgd_var;
126 double fac = F*A/(4.0*D);
128 fisher(0, 1) = fac*sigma22W;
129 fisher(1, 0) = fisher(0, 1);
130 fisher(0, 2) = fac*sigma11W;
131 fisher(2, 0) = fisher(0, 2);
132 fisher(0, 3) = -fac*2*sigma12W;
133 fisher(3, 0) = fisher(0, 3);
135 fac = 3.0*F*A*A/(16.0*D*D);
136 fisher(1, 1) = fac*sigma22W*sigma22W;
137 fisher(2, 2) = fac*sigma11W*sigma11W;
138 fisher(3, 3) = fac*4.0*(sigma12W*sigma12W + D/3.0);
140 fisher(1, 2) = fisher(3, 3)/4.0;
141 fisher(2, 1) = fisher(1, 2);
142 fisher(1, 3) = fac*(-2*sigma22W*sigma12W);
143 fisher(3, 1) = fisher(1, 3);
144 fisher(2, 3) = fac*(-2*sigma11W*sigma12W);
145 fisher(3, 2) = fisher(2, 3);
152 template<
typename ImageT>
153 struct ImageAdaptor {
154 typedef ImageT Image;
156 static bool const hasVariance =
false;
158 Image
const& getImage(ImageT
const& image)
const {
162 double getVariance(ImageT
const&,
int,
int) {
163 return std::numeric_limits<double>::quiet_NaN();
168 struct ImageAdaptor<afwImage::MaskedImage<T> > {
169 typedef typename afwImage::MaskedImage<T>::Image Image;
171 static bool const hasVariance =
true;
173 Image
const& getImage(afwImage::MaskedImage<T>
const& mimage)
const {
174 return *mimage.getImage();
177 double getVariance(afwImage::MaskedImage<T>
const& mimage,
int ix,
int iy) {
178 return mimage.at(ix, iy).variance();
183 std::tuple<std::pair<bool, double>, double, double,
double>
184 getWeights(
double sigma11,
double sigma12,
double sigma22) {
185 double const NaN = std::numeric_limits<double>::quiet_NaN();
186 if (std::isnan(sigma11) || std::isnan(sigma12) || std::isnan(sigma22)) {
187 return std::make_tuple(std::make_pair(
false, NaN), NaN, NaN, NaN);
189 double const det = sigma11*sigma22 - sigma12*sigma12;
190 if (std::isnan(det) || det < std::numeric_limits<float>::epsilon()) {
191 return std::make_tuple(std::make_pair(
false, det), NaN, NaN, NaN);
193 return std::make_tuple(std::make_pair(
true, det), sigma22/det, -sigma12/det, sigma11/det);
197 bool shouldInterp(
double sigma11,
double sigma22,
double det) {
198 float const xinterp = 0.25;
199 return (sigma11 < xinterp || sigma22 < xinterp || det < xinterp*xinterp);
205 afw::geom::Box2I computeAdaptiveMomentsBBox(
206 afw::geom::Box2I
const & bbox,
207 afw::geom::Point2D
const & center,
211 double maxRadius = 1000
213 double radius = std::min(4*std::sqrt(std::max(sigma11_w, sigma22_w)), maxRadius);
214 afw::geom::Extent2D offset(radius, radius);
215 afw::geom::Box2I result(afw::geom::Box2D(center - offset, center + offset));
224 template<
bool fluxOnly,
typename ImageT>
226 calcmom(ImageT
const& image,
227 float xcen,
float ycen,
228 lsst::afw::geom::BoxI bbox,
231 double w11,
double w12,
double w22,
234 double *psumx,
double *psumy,
235 double *psumxx,
double *psumxy,
double *psumyy,
237 bool negative =
false 245 double sum, sumx, sumy, sumxx, sumyy, sumxy, sums4;
246 #define RECALC_W 0 // estimate sigmaXX_w within BBox? 248 double wsum, wsumxx, wsumxy, wsumyy;
250 wsum = wsumxx = wsumxy = wsumyy = 0;
254 if (fabs(w11) > 1e6 || fabs(w12) > 1e6 || fabs(w22) > 1e6) {
258 sum = sumx = sumy = sumxx = sumxy = sumyy = sums4 = 0;
260 int const ix0 = bbox.getMinX();
261 int const ix1 = bbox.getMaxX();
262 int const iy0 = bbox.getMinY();
263 int const iy1 = bbox.getMaxY();
265 if (ix0 < 0 || ix1 >= image.getWidth() || iy0 < 0 || iy1 >= image.getHeight()) {
269 for (
int i = iy0; i <= iy1; ++i) {
270 typename ImageT::x_iterator ptr = image.x_at(ix0, i);
271 float const y = i - ycen;
272 float const y2 = y*
y;
273 float const yl = y - 0.375;
274 float const yh = y + 0.375;
275 for (
int j = ix0; j <= ix1; ++j, ++ptr) {
278 float const xl = x - 0.375;
279 float const xh = x + 0.375;
281 float expon = xl*xl*w11 + yl*yl*w22 + 2.0*xl*yl*w12;
282 tmp = xh*xh*w11 + yh*yh*w22 + 2.0*xh*yh*w12;
283 expon = (expon > tmp) ? expon : tmp;
284 tmp = xl*xl*w11 + yh*yh*w22 + 2.0*xl*yh*w12;
285 expon = (expon > tmp) ? expon : tmp;
286 tmp = xh*xh*w11 + yl*yl*w22 + 2.0*xh*yl*w12;
287 expon = (expon > tmp) ? expon : tmp;
291 for (Y = yl; Y <= yh; Y += 0.25) {
292 double const interpY2 = Y*Y;
293 for (X = xl; X <= xh; X += 0.25) {
294 double const interpX2 = X*X;
295 double const interpXy = X*Y;
296 expon = interpX2*w11 + 2*interpXy*w12 + interpY2*w22;
297 weight = std::exp(-0.5*expon);
302 sumx += ymod*(X + xcen);
303 sumy += ymod*(Y + ycen);
307 tmp = interpX2*weight;
311 tmp = interpXy*weight;
315 tmp = interpY2*weight;
319 sumxx += interpX2*ymod;
320 sumxy += interpXy*ymod;
321 sumyy += interpY2*ymod;
323 sums4 += expon*expon*ymod;
331 float expon = x2*w11 + 2*xy*w12 + y2*w22;
334 weight = std::exp(-0.5*expon);
360 sums4 += expon*expon*ymod;
368 std::tuple<std::pair<bool, double>, double, double,
double>
const weights = getWeights(w11, w12, w22);
369 double const detW = std::get<1>(weights)*std::get<3>(weights) - std::pow(std::get<2>(weights), 2);
370 *pI0 = sum/(afwGeom::PI*sqrt(detW));
380 if (psums4 != NULL) {
386 if (wsum > 0 && !fluxOnly) {
387 double det = w11*w22 - w12*w12;
391 printf(
"%g %g %g %g %g %g\n", w22/det, -w12/det, w11/det, wsumxx, wsumxy, wsumyy);
396 return (fluxOnly || (sum < 0 && sumxx < 0 && sumyy < 0)) ? 0 : -1;
398 return (fluxOnly || (sum > 0 && sumxx > 0 && sumyy > 0)) ? 0 : -1;
407 template<
typename ImageT>
408 bool getAdaptiveMoments(ImageT
const& mimage,
double bkgd,
double xcen,
double ycen,
double shiftmax,
409 SdssShapeResult *shape,
int maxIter,
float tol1,
float tol2,
bool negative)
414 double sumxx, sumxy, sumyy;
416 float const xcen0 = xcen;
417 float const ycen0 = ycen;
419 double sigma11W = 1.5;
420 double sigma12W = 0.0;
421 double sigma22W = 1.5;
423 double w11 = -1, w12 = -1, w22 = -1;
424 float e1_old = 1e6, e2_old = 1e6;
425 float sigma11_ow_old = 1e6;
427 typename ImageAdaptor<ImageT>::Image
const &image = ImageAdaptor<ImageT>().getImage(mimage);
429 if (std::isnan(xcen) || std::isnan(ycen)) {
431 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED_BAD.number] =
true;
435 bool interpflag =
false;
436 lsst::afw::geom::BoxI bbox;
438 for (; iter < maxIter; iter++) {
439 bbox = computeAdaptiveMomentsBBox(image.getBBox(afw::image::LOCAL), afw::geom::Point2D(xcen, ycen),
440 sigma11W, sigma12W, sigma22W);
441 std::tuple<std::pair<bool, double>, double, double,
double> weights =
442 getWeights(sigma11W, sigma12W, sigma22W);
443 if (!std::get<0>(weights).first) {
444 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
448 double const detW = std::get<0>(weights).second;
450 #if 0 // this form was numerically unstable on my G4 powerbook 453 assert(sigma11W*sigma22W >= sigma12W*sigma12W - std::numeric_limits<float>::epsilon());
457 const double ow11 = w11;
458 const double ow12 = w12;
459 const double ow22 = w22;
461 w11 = std::get<1>(weights);
462 w12 = std::get<2>(weights);
463 w22 = std::get<3>(weights);
465 if (shouldInterp(sigma11W, sigma22W, detW)) {
469 sigma11_ow_old = 1.e6;
479 if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
480 &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, &sums4, negative) < 0) {
481 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
497 if (fabs(shape->
x - xcen0) > shiftmax || fabs(shape->
y - ycen0) > shiftmax) {
498 shape->
flags[SdssShapeAlgorithm::SHIFT.number] =
true;
503 float const sigma11_ow = sumxx/sum;
504 float const sigma22_ow = sumyy/sum;
505 float const sigma12_ow = sumxy/sum;
507 if (sigma11_ow <= 0 || sigma22_ow <= 0) {
508 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
512 float const d = sigma11_ow + sigma22_ow;
513 float const e1 = (sigma11_ow - sigma22_ow)/d;
514 float const e2 = 2.0*sigma12_ow/d;
519 fabs(e1 - e1_old) < tol1 && fabs(e2 - e2_old) < tol1 &&
520 fabs(sigma11_ow/sigma11_ow_old - 1.0) < tol2 ) {
526 sigma11_ow_old = sigma11_ow;
551 float ow11, ow12, ow22;
553 std::tuple<std::pair<bool, double>, double, double,
double> weights =
554 getWeights(sigma11_ow, sigma12_ow, sigma22_ow);
555 if (!std::get<0>(weights).first) {
556 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
560 ow11 = std::get<1>(weights);
561 ow12 = std::get<2>(weights);
562 ow22 = std::get<3>(weights);
568 weights = getWeights(n11, n12, n22);
569 if (!std::get<0>(weights).first) {
571 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
575 sigma11W = std::get<1>(weights);
576 sigma12W = std::get<2>(weights);
577 sigma22W = std::get<3>(weights);
580 if (sigma11W <= 0 || sigma22W <= 0) {
581 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
586 if (iter == maxIter) {
587 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
588 shape->
flags[SdssShapeAlgorithm::MAXITER.number] =
true;
591 if (sumxx + sumyy == 0.0) {
592 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
true;
597 if (shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number]) {
599 if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
600 &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, NULL, negative) < 0 ||
601 (!negative && sum <= 0) || (negative && sum >= 0)) {
602 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number] =
false;
603 shape->
flags[SdssShapeAlgorithm::UNWEIGHTED_BAD.number] =
true;
614 sigma11W = sumxx/sum;
615 sigma12W = sumxy/sum;
616 sigma22W = sumyy/sum;
620 shape->
xx = sigma11W;
621 shape->
xy = sigma12W;
622 shape->
yy = sigma22W;
624 if (shape->
xx + shape->
yy != 0.0) {
625 int const ix = lsst::afw::image::positionToIndex(xcen);
626 int const iy = lsst::afw::image::positionToIndex(ycen);
628 if (ix >= 0 && ix < mimage.getWidth() && iy >= 0 && iy < mimage.getHeight()) {
629 float const bkgd_var =
630 ImageAdaptor<ImageT>().getVariance(mimage, ix, iy);
632 if (bkgd_var > 0.0) {
633 if (!(shape->
flags[SdssShapeAlgorithm::UNWEIGHTED.number])) {
634 Matrix4d fisher = calc_fisher(*shape, bkgd_var);
635 Matrix4d cov = fisher.inverse();
640 shape->
xxSigma = std::sqrt(cov(1, 1));
641 shape->
xySigma = std::sqrt(cov(2, 2));
642 shape->
yySigma = std::sqrt(cov(3, 3));
668 afw::table::Schema & schema,
669 std::string
const & name,
682 r._includePsf =
true;
683 r._psfShapeResult = afwTable::QuadrupoleKey::addFields(
684 schema, schema.join(name,
"psf"),
"adaptive moments of the PSF model at the object position");
686 r._includePsf =
false;
690 schema.join(name,
"flux",
"xx",
"Cov"),
691 (boost::format(
"uncertainty covariance between %s and %s")
692 % schema.join(name,
"flux") % schema.join(name,
"xx")).str(),
696 schema.join(name,
"flux",
"yy",
"Cov"),
697 (boost::format(
"uncertainty covariance between %s and %s")
698 % schema.join(name,
"flux") % schema.join(name,
"yy")).str(),
702 schema.join(name,
"flux",
"xy",
"Cov"),
703 (boost::format(
"uncertainty covariance between %s and %s")
704 % schema.join(name,
"flux") % schema.join(name,
"xy")).str(),
714 {SdssShapeAlgorithm::PSF_SHAPE_BAD});
723 _flux_xx_Cov(s[
"flux"][
"xx"][
"Cov"]),
724 _flux_yy_Cov(s[
"flux"][
"yy"][
"Cov"]),
725 _flux_xy_Cov(s[
"flux"][
"xy"][
"Cov"])
729 _psfShapeResult = afwTable::QuadrupoleKey(s[
"psf"]);
732 }
catch (pex::exceptions::NotFoundError& e) {
740 static_cast<ShapeResult&
>(result) = record.get(_shapeResult);
741 static_cast<CentroidResult&
>(result) = record.get(_centroidResult);
742 static_cast<FluxResult&
>(result) = record.get(_fluxResult);
747 if (n == SdssShapeAlgorithm::PSF_SHAPE_BAD.number && !_includePsf)
continue;
754 return record.get(_psfShapeResult);
758 record.set(_shapeResult, value);
759 record.set(_centroidResult, value);
760 record.set(_fluxResult, value);
765 if (n == SdssShapeAlgorithm::PSF_SHAPE_BAD.number && !_includePsf)
continue;
771 afwGeom::ellipses::Quadrupole
const & value)
const {
772 record.set(_psfShapeResult, value);
776 return _shapeResult == other._shapeResult &&
777 _centroidResult == other._centroidResult &&
778 _fluxResult == other._fluxResult &&
779 _psfShapeResult == other._psfShapeResult &&
780 _flux_xx_Cov == other._flux_xx_Cov &&
781 _flux_yy_Cov == other._flux_yy_Cov &&
782 _flux_xy_Cov == other._flux_xy_Cov;
787 return _shapeResult.
isValid() &&
790 _psfShapeResult.isValid() &&
791 _flux_xx_Cov.isValid() &&
792 _flux_yy_Cov.isValid() &&
793 _flux_xy_Cov.isValid();
799 std::string
const & name,
800 afw::table::Schema & schema
804 _centroidExtractor(schema, name)
807 template <
typename ImageT>
809 ImageT
const & image,
810 afw::geom::Point2D
const & center,
814 double xcen = center.getX();
815 double ycen = center.getY();
817 xcen -= image.getX0();
818 ycen -= image.getY0();
823 }
else if (shiftmax > 10) {
830 image, control.
background, xcen, ycen, shiftmax, &result,
833 }
catch (pex::exceptions::Exception & err) {
849 pex::exceptions::LogicError,
850 "Should not get singular moments unless a flag is set");
857 double fluxScale = computeFluxScale(result);
859 result.
flux *= fluxScale;
861 result.
x += image.getX0();
862 result.
y += image.getY0();
864 if (ImageAdaptor<ImageT>::hasVariance) {
873 template <
typename ImageT>
875 ImageT
const & image,
876 afw::geom::ellipses::Quadrupole
const & shape,
877 afw::geom::Point2D
const & center
880 afw::geom::Point2D localCenter = center - afw::geom::Extent2D(image.getXY0());
882 afwGeom::BoxI
const bbox = computeAdaptiveMomentsBBox(image.getBBox(afw::image::LOCAL),
884 shape.getIxx(), shape.getIxy(), shape.getIyy());
886 std::tuple<std::pair<bool, double>, double, double,
double> weights =
887 getWeights(shape.getIxx(), shape.getIxy(), shape.getIyy());
891 if (!std::get<0>(weights).first) {
892 throw pex::exceptions::InvalidParameterError(
"Input shape is singular");
895 double const w11 = std::get<1>(weights);
896 double const w12 = std::get<2>(weights);
897 double const w22 = std::get<3>(weights);
898 bool const interp = shouldInterp(shape.getIxx(), shape.getIyy(), std::get<0>(weights).second);
901 if (calcmom<true>(ImageAdaptor<ImageT>().getImage(image), localCenter.getX(), localCenter.getY(),
902 bbox, 0.0, interp, w11, w12, w22, &i0, NULL, NULL, NULL, NULL, NULL, NULL, NULL)< 0) {
903 throw LSST_EXCEPT(pex::exceptions::RuntimeError,
"Error from calcmom");
906 double const wArea = afw::geom::PI*std::sqrt(shape.getDeterminant());
908 result.flux = i0*2*wArea;
910 if (ImageAdaptor<ImageT>::hasVariance) {
911 int ix =
static_cast<int>(center.getX() - image.getX0());
912 int iy =
static_cast<int>(center.getY() - image.getY0());
913 if (!image.getBBox(afw::image::LOCAL).contains(afw::geom::Point2I(ix, iy))) {
914 throw LSST_EXCEPT(pex::exceptions::RuntimeError,
915 (boost::format(
"Center (%d,%d) not in image (%dx%d)") %
916 ix % iy % image.getWidth() % image.getHeight()).str());
918 double var = ImageAdaptor<ImageT>().getVariance(image, ix, iy);
919 double i0Err = std::sqrt(var/wArea);
920 result.fluxSigma = i0Err*2*wArea;
927 afw::table::SourceRecord & measRecord,
928 afw::image::Exposure<float>
const & exposure
930 bool negative =
false;
933 negative = measRecord.get(measRecord.getSchema().find<afw::table::Flag>(
"flags_negative").key);
934 }
catch(pexExcept::Exception &e) {
937 exposure.getMaskedImage(),
952 PTR(afw::detection::Psf
const) psf = exposure.getPsf();
956 _resultKey.
setPsfShape(measRecord, psf->computeShape(afw::geom::Point2D(result.
x, result.
y)));
958 }
catch (pex::exceptions::Exception & err) {
963 measRecord.set(_resultKey, result);
967 afw::table::SourceRecord & measRecord,
973 #define INSTANTIATE_IMAGE(IMAGE) \ 974 template SdssShapeResult SdssShapeAlgorithm::computeAdaptiveMoments( \ 976 afw::geom::Point2D const &, \ 980 template FluxResult SdssShapeAlgorithm::computeFixedMomentsFlux( \ 982 afw::geom::ellipses::Quadrupole const &, \ 983 afw::geom::Point2D const & \ 986 #define INSTANTIATE_PIXEL(PIXEL) \ 987 INSTANTIATE_IMAGE(lsst::afw::image::Image<PIXEL>); \ 988 INSTANTIATE_IMAGE(lsst::afw::image::MaskedImage<PIXEL>); 996 std::string
const & name,
997 afw::table::SchemaMapper & mapper
1000 _fluxTransform{name, mapper},
1001 _centroidTransform{name, mapper}
1004 _transformPsf = mapper.getInputSchema().getNames().count(
"sdssShape_flag_psf") ? true :
false;
1009 if (flag == SdssShapeAlgorithm::FAILURE)
continue;
1010 if (mapper.getInputSchema().getNames().count(
1011 mapper.getInputSchema().join(name, flag.
name)) == 0)
continue;
1012 afw::table::Key<afw::table::Flag> key = mapper.getInputSchema().find<afw::table::Flag>(
1013 name +
"_" + flag.
name).key;
1014 mapper.addMapping(key);
1019 if (_transformPsf) {
1020 _outPsfShapeKey = afwTable::QuadrupoleKey::addFields(mapper.editOutputSchema(), name +
"_psf",
1021 "PSF shape in celestial moments",
1022 afw::table::CoordinateType::CELESTIAL);
1027 afw::table::SourceCatalog
const & inputCatalog,
1028 afw::table::BaseCatalog & outputCatalog,
1029 afw::image::Wcs
const & wcs,
1030 afw::image::Calib
const & calib
1034 _fluxTransform(inputCatalog, outputCatalog, wcs, calib);
1035 _centroidTransform(inputCatalog, outputCatalog, wcs, calib);
1039 afwTable::QuadrupoleKey inPsfShapeKey;
1040 if (_transformPsf) {
1041 inPsfShapeKey = afwTable::QuadrupoleKey(
1042 inputCatalog.getSchema()[inputCatalog.getSchema().join(
_name,
"psf")]);
1045 afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
1046 afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
1047 for (; inSrc != inputCatalog.end(); ++inSrc, ++outSrc) {
1052 afw::geom::AffineTransform crdTr = wcs.linearizePixelToSky(centroidKey.get(*inSrc).getCentroid(),
1053 afw::geom::radians);
1060 _outShapeKey.
set(*outSrc, outShape);
1062 if (_transformPsf) {
1063 _outPsfShapeKey.set(*outSrc, inPsfShapeKey.get(*inSrc).transform(crdTr.getLinear()));
std::size_t size() const
return the current size (number of defined elements) of the collection
virtual void set(afw::table::BaseRecord &record, ShapeResult const &value) const
Set a ShapeResult in the given record.
bool doMeasurePsf
"Whether to also compute the shape of the PSF model" ;
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 Result computeAdaptiveMoments(ImageT const &image, afw::geom::Point2D const &position, bool negative=false, Control const &ctrl=Control())
Compute the adaptive Gaussian-weighted moments of an image.
ShapeTrMatrix makeShapeTransformMatrix(afw::geom::LinearTransform const &xform)
Construct a matrix suitable for transforming second moments.
ErrElement yy_xy_Cov
yy,xy term in the uncertainty convariance matrix
static FluxResult computeFixedMomentsFlux(ImageT const &image, afw::geom::ellipses::Quadrupole const &shape, afw::geom::Point2D const &position)
Compute the flux within a fixed Gaussian aperture.
float tol2
"Convergence tolerance for FWHM" ;
static FlagDefinition const SHIFT
Shape const getShape() const
Return an afw::geom::ellipses object corresponding to xx, yy, xy.
Simple class used to define and document flags The name and doc constitute the identity of the FlagDe...
Only the diagonal elements of the covariance matrix are provided.
A reusable struct for centroid measurements.
afw::geom::ellipses::Quadrupole getQuadrupole()
double background
"Additional value to add to background" ;
bool isValid() const
Return True if the centroid key is valid.
The full covariance matrix is provided.
CentroidElement x
x (column) coordinate of the measured position
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 maxIter
"Maximum number of iterations" ;
bool operator==(SdssShapeResultKey const &other) const
Compare the FunctorKey for equality with another, using the underlying Keys.
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given flag index.
Exception to be thrown when a measurement algorithm experiences a known failure mode.
static FlagDefinition const UNWEIGHTED
ErrElement xySigma
1-Sigma uncertainty on xy (sqrt of variance)
static FluxResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _flux, _fluxSigma fields to a Schema, and return a FluxResultKey that points to them...
float tol1
"Convergence tolerance for e1,e2" ;
bool isValid() const
Return True if the key is valid.
static FlagDefinition const UNWEIGHTED_BAD
double maxShift
"Maximum centroid shift, limited to 2-10" ;
ErrElement flux_yy_Cov
flux, yy term in the uncertainty covariance matrix
A FunctorKey for ShapeResult.
ErrElement xx_xy_Cov
xx,xy term in the uncertainty convariance matrix
void setShapeErr(ShapeCov const &matrix)
Set the struct uncertainty elements from the given matrix, with rows and columns ordered (xx...
ErrElement xx_yy_Cov
xx,yy term in the uncertainty convariance matrix
Utility class for handling flag fields that indicate the failure modes of an algorithm.
A reusable struct for moments-based shape measurements.
static unsigned int const N_FLAGS
Result object SdssShapeAlgorithm.
static FlagDefinitionList const & getFlagDefinitions()
SdssShapeResult()
Constructor; initializes everything to NaN.
SdssShapeAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
Flux flux
Measured flux in DN.
virtual void set(afw::table::BaseRecord &record, SdssShapeResult const &value) const
Set an SdssShapeResult in the given record.
static CentroidResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty)
Add the appropriate fields to a Schema, and return a CentroidResultKey that manages them...
A C++ control class to handle SdssShapeAlgorithm's configuration.
bool isValid() const
Return True if the shape key is valid.
bool isValid() const
Return True if both the flux and fluxSigma Keys are valid.
static FlagHandler addFields(afw::table::Schema &schema, std::string const &prefix, FlagDefinitionList const &flagDefs, FlagDefinitionList const &exclDefs=FlagDefinitionList::getEmptyList())
Add Flag fields to a schema, creating a FlagHandler object to manage them.
std::bitset< SdssShapeAlgorithm::N_FLAGS > flags
Status flags (see SdssShapeAlgorithm).
virtual SdssShapeResult get(afw::table::BaseRecord const &record) const
Get an SdssShapeResult from the given record.
virtual afw::geom::ellipses::Quadrupole getPsfShape(afw::table::BaseRecord const &record) const
Get a Quadrupole for the Psf from the given record.
static FlagDefinition const MAXITER
static FlagDefinition const PSF_SHAPE_BAD
A FunctorKey that maps SdssShapeResult to afw::table Records.
Algorithm provides no uncertainy information at all.
static FlagDefinition const FAILURE
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=nullptr) const
Handle an expected or unexpected Exception thrown by a measurement algorithm.
ErrElement yySigma
1-Sigma uncertainty on yy (sqrt of variance)
A FunctorKey for CentroidResult.
CentroidElement y
y (row) coordinate of the measured position
ErrElement xxSigma
1-Sigma uncertainty on xx (sqrt of variance)
bool getValue(afw::table::BaseRecord const &record, std::size_t i) const
Return the value of the flag field corresponding to the given flag index.
SdssShapeResultKey()
Default constructor; instance will not be usuable unless subsequently assigned to.
FlagHandler const & getFlagHandler() const
#define INSTANTIATE_PIXEL(PIXEL)
vector-type utility class to build a collection of FlagDefinitions
ErrElement flux_xx_Cov
flux, xx term in the uncertainty covariance matrix
void setShape(Shape const &shape)
Set struct elements from the given Quadrupole object.
FluxErrElement fluxSigma
1-Sigma error (sqrt of variance) on flux in DN.
Eigen::Matrix< ShapeElement, 3, 3, Eigen::DontAlign > ShapeTrMatrix
static SdssShapeResultKey addFields(afw::table::Schema &schema, std::string const &name, bool doMeasurePsf)
Add the appropriate fields to a Schema, and return a SdssShapeResultKey that manages them...
virtual void setPsfShape(afw::table::BaseRecord &record, afw::geom::ellipses::Quadrupole const &value) const
Set a Quadrupole for the Psf at the position of the given record.
A reusable result struct for flux measurements.
ErrElement flux_xy_Cov
flux, xy term in the uncertainty covariance matrix
ShapeCov const getShapeErr() const
Return the 3x3 symmetric covariance matrix, with rows and columns ordered (xx, yy, xy)
static ShapeResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty, afw::table::CoordinateType coordType=afw::table::CoordinateType::PIXEL)
Add the appropriate fields to a Schema, and return a ShapeResultKey that manages them.