26 #include "boost/math/special_functions/erf.hpp"
27 #include <boost/math/constants/constants.hpp>
36 namespace lsst {
namespace meas {
namespace base {
41 double computeOldBlendedness(
43 afw::image::Image<float>
const & parentImage
45 if (!childFootprint) {
47 pex::exceptions::LogicError,
48 "blendedness_old requires a Footprint."
52 PTR(afw::detection::HeavyFootprint<float>
const) childHeavy =
53 std::dynamic_pointer_cast<afw::detection::HeavyFootprint<
float> const>(childFootprint);
61 pex::exceptions::LogicError,
62 "Child footprint extends beyond image."
69 typedef afw::detection::Footprint::SpanList::const_iterator SpanIter;
71 typedef ndarray::Array<float const,1,1>::Iterator ChildPixIter;
72 SpanIter spanIter = childHeavy->getSpans().begin();
73 SpanIter
const spanEnd = childHeavy->getSpans().end();
74 ChildPixIter childPixIter = childHeavy->getImageArray().begin();
77 while (spanIter != spanEnd) {
78 afw::geom::Span
const & span = **spanIter;
79 ParentPixIter parentPixIter = parentImage.x_at(
80 span.getBeginX() - parentImage.getX0(),
81 span.getY() - parentImage.getY0()
83 int const width = span.getWidth();
85 for (
int x = 0;
x <
width; ++parentPixIter, ++childPixIter, ++
x) {
86 cp += (*childPixIter) * ((*parentPixIter) - (*childPixIter));
87 cc += (*childPixIter) * (*childPixIter);
97 class FluxAccumulator {
100 FluxAccumulator() :
_w(0.0),
_ww(0.0),
_wd(0.0) {}
102 void operator()(
double,
double,
float weight,
float data) {
108 double getFlux()
const {
return _w*
_wd/
_ww; }
117 class ShapeAccumulator :
public FluxAccumulator {
120 ShapeAccumulator() : FluxAccumulator(),
_wdxx(0.0),
_wdyy(0.0),
_wdxy(0.0) {}
122 void operator()(
double x,
double y,
float weight,
float data) {
123 FluxAccumulator::operator()(x, y, weight, data);
124 _wdxx += x*x*weight*data;
125 _wdyy += y*y*weight*data;
126 _wdxy += x*y*weight*data;
129 ShapeResult getShape()
const {
146 template <
typename Accumulator>
148 afw::image::MaskedImage<float>
const &
image,
150 afw::geom::ellipses::Quadrupole
const & shape,
151 double nSigmaWeightMax,
152 Accumulator & accumulatorRaw,
153 Accumulator & accumulatorAbs
157 afw::geom::ellipses::Ellipse ellipse(shape, centroid);
158 ellipse.getCore().scale(nSigmaWeightMax);
163 afw::geom::LinearTransform transform = shape.getGridTransform();
165 typedef afw::geom::ellipses::PixelRegion::Iterator SpanIter;
167 typedef afw::image::MaskedImage<float>::const_x_iterator PixelIter;
169 afw::geom::ellipses::PixelRegion region(ellipse);
170 bool isContained = bbox.contains(region.getBBox());
171 SpanIter
const spanEnd = region.end();
172 for (SpanIter spanIter = region.begin(); spanIter != spanEnd; ++spanIter) {
173 afw::geom::Span span = *spanIter;
175 if (span.getY() < bbox.getMinY() || span.getY() > bbox.getMaxY()) {
178 span = afw::geom::Span(
180 std::max(span.getMinX(), bbox.getMinX()),
181 std::min(span.getMaxX(), bbox.getMaxX())
183 if (span.getMinX() > span.getMaxX()) {
187 PixelIter pixelIter = image.x_at(
188 span.getBeginX() - image.getX0(),
189 span.getY() - image.getY0()
191 PointIter
const pointEnd = span.end();
192 for (PointIter pointIter = span.begin(); pointIter != pointEnd; ++pointIter, ++pixelIter) {
196 float weight = std::exp(static_cast<float>(-0.5*td.computeSquaredNorm()));
197 float data = pixelIter.image();
198 accumulatorRaw(d.getX(), d.getY(),
weight, data);
199 float variance = pixelIter.variance();
200 float mu = (std::sqrt(variance/(2.0f/boost::math::constants::pi<float>()))*
201 std::exp(-0.5f*(data*data)/variance)) +
202 0.5f*data*boost::math::erfc(-data/std::sqrt(2.0f*variance));
203 float bias = (std::sqrt(2.0f*variance/boost::math::constants::pi<float>())*
204 std::exp(-0.5f*(mu*mu)/variance)) -
205 mu*boost::math::erfc(mu/std::sqrt(2.0f*variance));
206 accumulatorAbs(d.getX(), d.getY(),
weight, std::max(std::abs(data) - bias, 0.0f));
216 static std::array<FlagDefinition,BlendednessAlgorithm::N_FLAGS>
const flagDefs = {{
217 {
"flag",
"general failure flag"},
218 {
"flag_noCentroid",
"Object has no centroid"},
219 {
"flag_noShape",
"Object has no shape"}
229 schema.
join(name,
"old"),
230 "blendedness from dot products: (child.dot(parent)/child.dot(child) - 1)"
235 schema.
join(name,
"raw_flux"),
236 "measure of how flux is affected by neighbors: (1 - flux.child/flux.parent)"
239 schema.
join(name,
"raw_flux_child"),
240 "flux of the child, measured with a Gaussian weight matched to the child",
244 schema.
join(name,
"raw_flux_parent"),
245 "flux of the parent, measured with a Gaussian weight matched to the child",
249 schema.
join(name,
"abs_flux"),
250 "measure of how flux is affected by neighbors: (1 - flux.child/flux.parent)"
253 schema.
join(name,
"abs_flux_child"),
254 "flux of the child, measured with a Gaussian weight matched to the child",
258 schema.
join(name,
"abs_flux_parent"),
259 "flux of the parent, measured with a Gaussian weight matched to the child",
265 "shape of the child, measured with a Gaussian weight matched to the child",
268 "shape of the parent, measured with a Gaussian weight matched to the child",
271 "shape of the child, measured with a Gaussian weight matched to the child",
274 "shape of the parent, measured with a Gaussian weight matched to the child",
293 if (!child.
getTable()->getCentroidKey().isValid()) {
295 "Centroid Key must be defined to measure the blendedness flux");
299 if (!child.
getTable()->getShapeKey().isValid()) {
301 "Shape Key must be defined to measure the blendedness shape");
306 if (child.
getTable()->getCentroidFlagKey().isValid()) {
314 if (child.
getTable()->getShapeFlagKey().isValid()) {
326 if (!(std::isfinite(child.
getX()) && std::isfinite(child.
getY()))) {
336 ShapeAccumulator accumulatorRaw;
337 ShapeAccumulator accumulatorAbs;
347 child.
set(fluxRawKey, accumulatorRaw.getFlux());
348 child.
set(fluxAbsKey, accumulatorAbs.getFlux());
350 _shapeRawKey.
set(child, accumulatorRaw.getShape());
351 _shapeAbsKey.
set(child, accumulatorAbs.getShape());
353 FluxAccumulator accumulatorRaw;
354 FluxAccumulator accumulatorAbs;
363 child.
set(fluxRawKey, accumulatorRaw.getFlux());
364 child.
set(fluxAbsKey, accumulatorAbs.getFlux());
Defines the fields and offsets for a table.
ShapeResultKey _shapeParentRaw
double getX() const
Return the centroid slot x coordinate.
table::Key< std::string > name
CentroidSlotDefinition::MeasValue getCentroid() const
Get the value of the Centroid slot measurement.
tbl::Key< double > weight
afw::table::Key< double > _fluxParentRaw
afw::table::Schema schema
ShapeResultKey _shapeChildAbs
Extent< double, 2 > Extent2D
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
lsst::afw::detection::Footprint Footprint
ShapeResultKey _shapeChildRaw
afw::table::Key< double > _fluxRaw
bool getCentroidFlag() const
Return true if the measurement in the Centroid slot failed.
ImagePtr getImage(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage's image.
std::array< FlagDefinition, BlendednessAlgorithm::N_FLAGS > const & getFlagDefinitions()
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
afw::table::Key< double > _fluxChildRaw
afw::table::Key< double > _old
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
A FunctorKey for ShapeResult.
void measureParentPixels(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child) const
table::Key< table::Array< Kernel::Pixel > > image
virtual void set(afw::table::BaseRecord &record, ShapeResult const &value) const
Set a ShapeResult in the given record.
void ImageT ImageT int float saturatedPixelValue int const width
void measureChildPixels(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child) const
afw::table::Key< double > _fluxChildAbs
A class to manipulate images, masks, and variance as a single object.
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
double nSigmaWeightMax
"Radius factor that sets the maximum extent of the weight function (and hence the flux measurements)"...
bool doShape
"Whether to compute quantities related to the Gaussian-weighted shape" ;
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given enum value.
afw::table::Key< double > _fluxAbs
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
void _measureMoments(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child, afw::table::Key< double > const &fluxRawKey, afw::table::Key< double > const &fluxAbsKey, ShapeResultKey const &_shapeRawKey, ShapeResultKey const &_shapeAbsKey) const
boost::shared_ptr< SourceTable const > getTable() const
Algorithm provides no uncertainy information at all.
double getY() const
Return the centroid slot y coordinate.
bool getShapeFlag() const
Return true if the measurement in the Shape slot failed.
Point< double, 2 > Point2D
SpanPixelIterator Iterator
An iterator over points in the Span.
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Record class that contains measurements made on a single exposure.
ShapeSlotDefinition::MeasValue getShape() const
Get the value of the Shape slot measurement.
double getDeterminant() const
Return the determinant of the matrix representation.
Forward declarations, typedefs, and definitions for Ellipse.
ShapeResultKey _shapeParentAbs
bool doFlux
"Whether to compute quantities related to the Gaussian-weighted flux" ;
boost::shared_ptr< Footprint > getFootprint() const
static FlagHandler addFields(afw::table::Schema &schema, std::string const &prefix, FlagDefinition const *begin, FlagDefinition const *end)
Add Flag fields to a schema, creating a FlagHandler object to manage them.
bool doOld
"Whether to compute HeavyFootprint dot products (the old deblend.blendedness parameter)" ; ...
afw::table::Key< double > _fluxParentAbs
BlendednessAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
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.