27 #include "boost/math/constants/constants.hpp" 47 namespace extensions {
48 namespace photometryKron {
51 base::FlagDefinitionList flagDefinitions;
54 base::FlagDefinition
const KronFluxAlgorithm::FAILURE = flagDefinitions.addFailureFlag(
"general failure flag, set if anything went wrong");
55 base::FlagDefinition
const KronFluxAlgorithm::EDGE = flagDefinitions.add(
"flag_edge",
"bad measurement due to image edge");
62 base::FlagDefinition
const KronFluxAlgorithm::SMALL_RADIUS = flagDefinitions.add(
"flag_small_radius",
"measured Kron radius was smaller than that of the PSF");
63 base::FlagDefinition
const KronFluxAlgorithm::BAD_SHAPE = flagDefinitions.add(
"flag_bad_shape",
"shape for measuring Kron radius is bad; used PSF shape");
66 return flagDefinitions;
74 template <
typename MaskedImageT>
77 explicit FootprintFlux() : _sum(0.0), _sumVar(0.0) {}
86 void operator()(afw::geom::Point2I
const & pos,
87 typename MaskedImageT::Image::Pixel
const & ival,
88 typename MaskedImageT::Variance::Pixel
const & vval) {
94 double getSum()
const {
return _sum; }
97 double getSumVar()
const {
return _sumVar; }
115 template <
typename MaskedImageT,
typename WeightImageT>
116 class FootprintFindMoment {
118 FootprintFindMoment(MaskedImageT
const& mimage,
119 afw::geom::Point2D
const& center,
122 ) : _xcen(center.getX()), _ycen(center.getY()),
124 _cosTheta(::cos(theta)),
125 _sinTheta(::sin(theta)),
126 _sum(0.0), _sumR(0.0),
128 _sumVar(0.0), _sumRVar(0.0),
130 _imageX0(mimage.getX0()), _imageY0(mimage.getY0())
138 _sumVar = _sumRVar = 0.0;
141 MaskedImageT
const& mimage = this->getImage();
143 int const x0 =
bbox.getMinX(), y0 =
bbox.getMinY(), x1 =
bbox.getMaxX(), y1 =
bbox.getMaxY();
145 if (x0 < _imageX0 || y0 < _imageY0 ||
146 x1 >= _imageX0 + mimage.getWidth() || y1 >= _imageY0 + mimage.getHeight()) {
148 (boost::format(
"Footprint %d,%d--%d,%d doesn't fit in image %d,%d--%d,%d")
150 % _imageX0 % _imageY0
151 % (_imageX0 + mimage.getWidth() - 1) % (_imageY0 + mimage.getHeight() - 1)
157 void operator()(afw::geom::Point2I
const & pos,
typename MaskedImageT::Image::Pixel
const & ival) {
158 double x =
static_cast<double>(pos.getX());
159 double y =
static_cast<double>(pos.getY());
160 double const dx = x - _xcen;
161 double const dy = y - _ycen;
162 double const du = dx*_cosTheta + dy*_sinTheta;
163 double const dv = -dx*_sinTheta + dy*_cosTheta;
165 double r = ::hypot(du, dv*_ab);
167 if (::hypot(dx, dy) < 0.5) {
179 double const eR = 0.38259771140356325;
180 r = ::hypot(r, eR*(1 + ::hypot(dx, dy)/afw::geom::ROOT2));
187 typename MaskedImageT::Variance::Pixel vval = iloc.variance(0, 0);
189 _sumRVar += r*r*vval;
194 double getIr()
const {
return _sumR/_sum; }
199 double getIrVar()
const {
return _sumRVar/(_sum*_sum) + _sumVar*_sumR*_sumR/::pow(_sum, 4); }
203 bool getGood()
const {
return _sum > 0 && _sumR > 0; }
209 double const _cosTheta, _sinTheta;
216 int const _imageX0, _imageY0;
223 afw::geom::LinearTransform
const& transformation,
232 template<
typename ImageT>
236 afw::geom::Point2D
const& center,
244 bool const smoothImage = sigma > 0;
245 int kSize = smoothImage ? 2*int(2*sigma) + 1 : 1;
248 bool const doNormalize =
true, doCopyEdge =
false;
261 afw::geom::Box2I
bbox = !smoothImage ?
264 bbox.
clip(image.getBBox());
272 FootprintFindMoment<ImageT, afw::detection::Psf::Image> iRFunctor(
278 iRFunctor, *(subImage.getImage()));
286 if (!iRFunctor.getGood()) {
290 radius = iRFunctor.getIr()*sqrt(axes.
getB()/axes.
getA());
291 if (radius <= radius0) {
300 return std::make_shared<KronAperture>(center, axes, radiusForRadius);
304 template<
typename ImageT>
308 double const maxSincRadius
312 if (axes.
getB() > maxSincRadius) {
313 FootprintFlux<ImageT> fluxFunctor;
316 fluxFunctor, *(image.getImage()), *(image.getVariance()));
317 return std::make_pair(fluxFunctor.getSum(), ::sqrt(fluxFunctor.getSumVar()));
323 LSST_EXCEPT_ADD(e, (boost::format(
"Measuring Kron flux for object at (%.3f, %.3f);" 324 " aperture radius %g,%g theta %g")
334 afw::geom::Point2D
const& center,
335 double smoothingSigma=0.0
341 return ::sqrt(afw::geom::PI/2)*::hypot(radius,
std::max(0.0, smoothingSigma));
344 template<
typename ImageT>
347 double const nRadiusForFlux,
348 double const maxSincRadius
352 axes.
scale(nRadiusForFlux);
355 return photometer(image, ellip, maxSincRadius);
373 meas::base::FluxResultKey::addFields(schema, name,
"flux from Kron Flux algorithm")
375 _radiusKey(schema.addField<float>(name +
"_radius",
"Kron radius (sqrt(a*b))")),
376 _radiusForRadiusKey(schema.addField<float>(name +
"_radius_for_radius",
377 "radius used to estimate <radius> (sqrt(a*b))")),
378 _psfRadiusKey(schema.addField<float>(name +
"_psf_radius",
"Radius of PSF")),
379 _centroidExtractor(schema, name, true)
392 void KronFluxAlgorithm::_applyAperture(
429 source.
set(_fluxResultKey, fluxResult);
436 void KronFluxAlgorithm::_applyForced(
439 afw::geom::Point2D
const & center,
441 afw::geom::AffineTransform
const & refToMeas
445 KronAperture const aperture(reference, refToMeas, radius);
446 _applyAperture(source, exposure, aperture);
456 afw::geom::Point2D center = _centroidExtractor(source, _flagHandler);
484 axes = exposure.
getPsf()->computeShape();
491 footprintAxes.
scale(::sqrt(2));
493 double radius0 = axes.getDeterminantRadius();
494 double const footRadius = footprintAxes.getDeterminantRadius();
498 axes.scale(radius0/axes.getDeterminantRadius());
517 aperture = _fallbackRadius(source, R_K_psf, e);
520 aperture = _fallbackRadius(source, R_K_psf, e);
532 double newRadius = rad;
538 }
else if (!exposure.
getPsf()) {
544 }
else if (rad < R_K_psf) {
548 if (newRadius != rad) {
554 _applyAperture(source, exposure, *aperture);
556 source.
set(_psfRadiusKey, R_K_psf);
566 afw::geom::Point2D center = _centroidExtractor(measRecord, _flagHandler);
568 _applyForced(measRecord, exposure, center, refRecord,
583 }
else if (R_K_psf > 0) {
599 #define INSTANTIATE(TYPE) \ 600 template PTR(KronAperture) KronAperture::determineRadius<afw::image::MaskedImage<TYPE> >( \ 601 afw::image::MaskedImage<TYPE> const&, \ 602 afw::geom::ellipses::Axes, \ 603 afw::geom::Point2D const&, \ 604 KronFluxControl const& \ 606 template std::pair<double, double> KronAperture::measureFlux<afw::image::MaskedImage<TYPE> >( \ 607 afw::image::MaskedImage<TYPE> const&, \
double const getB() const
static meas::base::FlagDefinition const SMALL_RADIUS
lsst::geom::Point2D const & getCenter() const
static meas::base::FlagDefinition const NO_MINIMUM_RADIUS
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
C++ control object for Kron flux.
virtual void measureForced(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure, afw::table::SourceRecord const &refRecord, afw::geom::SkyWcs const &refWcs) const
ShapeSlotDefinition::MeasValue getShape() const
std::pair< double, double > photometer(ImageT const &image, afw::geom::ellipses::Ellipse const &aperture, double const maxSincRadius)
double smoothingSigma
"Smooth image with N(0, smoothingSigma^2) Gaussian while estimating R_K" ;
double const getA() const
double calculatePsfKronRadius(boost::shared_ptr< afw::detection::Psf const > const &psf, afw::geom::Point2D const ¢er, double smoothingSigma=0.0)
double minimumRadius
"Minimum Kron radius (if == 0.0 use PSF's Kron radius) if enforceMinimumRadius. " "Also functions as ...
bool getShapeFlag() const
std::shared_ptr< Footprint > getFootprint() const
BaseCore const & getCore() const
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
KronFluxAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema, daf::base::PropertySet &metadata)
A class that knows how to calculate fluxes using the KRON photometry algorithm.
bool fixed
"if true, use existing shape and centroid measurements instead of fitting" ;
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
meas::base::FluxErrElement instFluxErr
static boost::shared_ptr< KronAperture > determineRadius(ImageT const &image, afw::geom::ellipses::Axes axes, afw::geom::Point2D const ¢er, KronFluxControl const &ctrl)
Determine the Kron Aperture from an image.
Field< T >::Value get(Key< T > const &key) const
afw::table::Key< double > sigma
static meas::base::FlagDefinition const USED_MINIMUM_RADIUS
static meas::base::FlagDefinition const USED_PSF_RADIUS
SchemaItem< T > find(std::string const &name) const
MaskedImageT getMaskedImage()
lsst::geom::Box2I growBBox(lsst::geom::Box2I const &bbox) const
static afw::geom::ellipses::Axes getKronAxes(afw::geom::ellipses::Axes const &shape, afw::geom::LinearTransform const &transformation, double const radius)
Determine Kron axes from a reference image.
static meas::base::FlagDefinition const NO_FALLBACK_RADIUS
static meas::base::FlagDefinition const BAD_SHAPE_NO_PSF
double nSigmaForRadius
"Multiplier of rms size for aperture used to initially estimate the Kron radius" ; ...
bool enforceMinimumRadius
"If true check that the Kron radius exceeds some minimum" ;
std::pair< double, double > measureFlux(ImageT const &image, double const nRadiusForFlux, double const maxSincRadius) const
Photometer within the Kron Aperture on an image.
void scale(double factor)
std::string refRadiusName
"Name of field specifying reference Kron radius for forced measurement" ;
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
std::unique_ptr< SchemaItem< U > > result
float getRadiusForRadius() const
static FlagHandler addFields(afw::table::Schema &schema, std::string const &prefix, FlagDefinitionList const &flagDefs, FlagDefinitionList const &exclDefs=FlagDefinitionList::getEmptyList())
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
static meas::base::FlagDefinition const FAILURE
#define LSST_EXCEPT(type,...)
double maxSincRadius
"Largest aperture for which to use the slow, accurate, sinc aperture code" ;
static meas::base::FlagDefinition const BAD_RADIUS
Transformer transform(lsst::geom::LinearTransform const &transform)
std::shared_ptr< lsst::afw::detection::Psf > getPsf()
int nIterForRadius
"Number of times to iterate when setting the Kron radius" ;
void clip(Box2I const &other) noexcept
bool useFootprintRadius
"Use the Footprint size as part of initial estimate of Kron radius" ;
static meas::base::FlagDefinition const EDGE
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=nullptr) const
static meas::base::FlagDefinitionList const & getFlagDefinitions()
std::shared_ptr< geom::SkyWcs const > getWcs() const
void set(Key< T > const &key, U const &value)
virtual void fail(afw::table::SourceRecord &measRecord, meas::base::MeasurementError *error=NULL) const
meas::base::Flux instFlux
double getDeterminantRadius() const
double const getTheta() const
void add(std::string const &name, T const &value)
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
#define LSST_EXCEPTION_TYPE(t, b, c)
afw::geom::ellipses::Axes & getAxes()
#define LSST_EXCEPT_ADD(e, m)
CentroidSlotDefinition::MeasValue getCentroid() const
double nRadiusForFlux
"Number of Kron radii for Kron flux" ;
#define INSTANTIATE(TYPE)
static meas::base::FlagDefinition const BAD_SHAPE
geom::ellipses::Quadrupole computeShape(lsst::geom::Point2D position=makeNullPoint(), image::Color color=image::Color()) const