26 #include "boost/math/constants/constants.hpp" 35 namespace lsst {
namespace meas {
namespace base {
37 FlagDefinitionList flagDefinitions;
45 return flagDefinitions;
52 double computeOldBlendedness(
56 if (!childFootprint) {
59 "blendedness_old requires a Footprint." 73 "Child footprint extends beyond image." 81 typedef ndarray::Array<float const,1,1>::Iterator ChildPixIter;
82 auto spanIter = childHeavy->getSpans()->begin();
83 auto const spanEnd = childHeavy->getSpans()->end();
84 ChildPixIter childPixIter = childHeavy->getImageArray().begin();
87 while (spanIter != spanEnd) {
89 ParentPixIter parentPixIter = parentImage.
x_at(
95 for (
int x = 0;
x < width; ++parentPixIter, ++childPixIter, ++
x) {
96 cp += (*childPixIter) * ((*parentPixIter) - (*childPixIter));
97 cc += (*childPixIter) * (*childPixIter);
107 class FluxAccumulator {
110 FluxAccumulator() :
_w(0.0),
_ww(0.0),
_wd(0.0) {}
112 void operator()(
double,
double,
float weight,
float data) {
114 _ww += weight*weight;
118 double getFlux()
const {
return _w*
_wd/
_ww; }
127 class ShapeAccumulator :
public FluxAccumulator {
130 ShapeAccumulator() : FluxAccumulator(), _wdxx(0.0), _wdyy(0.0), _wdxy(0.0) {}
132 void operator()(
double x,
double y,
float weight,
float data) {
133 FluxAccumulator::operator()(x, y, weight, data);
134 _wdxx += x*x*weight*data;
135 _wdyy += y*y*weight*data;
136 _wdxy += x*y*weight*data;
139 ShapeResult getShape()
const {
143 result.xx = 2.0*_wdxx/
_wd;
144 result.yy = 2.0*_wdyy/
_wd;
145 result.xy = 2.0*_wdxy/
_wd;
155 template <
typename Accumulator>
157 afw::image::MaskedImage<float>
const &
image,
159 afw::geom::ellipses::Quadrupole
const & shape,
160 double nSigmaWeightMax,
161 Accumulator & accumulatorRaw,
162 Accumulator & accumulatorAbs
166 afw::geom::ellipses::Ellipse ellipse(shape, centroid);
167 ellipse.getCore().scale(nSigmaWeightMax);
172 afw::geom::LinearTransform
transform = shape.getGridTransform();
174 typedef afw::geom::ellipses::PixelRegion::Iterator SpanIter;
178 afw::geom::ellipses::PixelRegion region(ellipse);
179 bool isContained = bbox.contains(region.getBBox());
180 SpanIter
const spanEnd = region.end();
181 for (SpanIter spanIter = region.begin(); spanIter != spanEnd; ++spanIter) {
182 afw::geom::Span span = *spanIter;
184 if (span.getY() < bbox.getMinY() || span.getY() > bbox.getMaxY()) {
187 span = afw::geom::Span(
189 std::max(span.getMinX(), bbox.getMinX()),
190 std::min(span.getMaxX(), bbox.getMaxX())
192 if (span.getMinX() > span.getMaxX()) {
196 PixelIter pixelIter = image.x_at(
197 span.getBeginX() - image.getX0(),
198 span.getY() - image.getY0()
200 PointIter
const pointEnd = span.end();
201 for (PointIter pointIter = span.begin(); pointIter != pointEnd; ++pointIter, ++pixelIter) {
205 float weight =
std::exp(static_cast<float>(-0.5*td.computeSquaredNorm()));
206 float data = pixelIter.image();
207 accumulatorRaw(d.getX(), d.getY(), weight, data);
208 float variance = pixelIter.variance();
211 accumulatorAbs(d.getX(), d.getY(), weight, std::abs(data) - bias);
226 schema.
join(name,
"old"),
227 "blendedness from dot products: (child.dot(parent)/child.dot(child) - 1)" 232 schema.
join(name,
"raw_flux"),
233 "measure of how flux is affected by neighbors: (1 - flux.child/flux.parent)" 235 _fluxChildRaw = schema.
addField<
double>(
236 schema.
join(name,
"raw_flux_child"),
237 "flux of the child, measured with a Gaussian weight matched to the child",
240 _fluxParentRaw = schema.
addField<
double>(
241 schema.
join(name,
"raw_flux_parent"),
242 "flux of the parent, measured with a Gaussian weight matched to the child",
246 schema.
join(name,
"abs_flux"),
247 "measure of how flux is affected by neighbors: (1 - flux.child/flux.parent)" 249 _fluxChildAbs = schema.
addField<
double>(
250 schema.
join(name,
"abs_flux_child"),
251 "flux of the child, measured with a Gaussian weight matched to the child",
254 _fluxParentAbs = schema.
addField<
double>(
255 schema.
join(name,
"abs_flux_parent"),
256 "flux of the parent, measured with a Gaussian weight matched to the child",
262 "shape of the child, measured with a Gaussian weight matched to the child",
265 "shape of the parent, measured with a Gaussian weight matched to the child",
268 "shape of the child, measured with a Gaussian weight matched to the child",
271 "shape of the parent, measured with a Gaussian weight matched to the child",
282 if (!(normalization > 0)) {
286 return data + (
std::sqrt(0.5f*variance/boost::math::constants::pi<float>()) *
287 std::exp(-0.5f*(data*data)/variance) / normalization);
291 return (
std::sqrt(2.0f*variance/boost::math::constants::pi<float>()) *
296 void BlendednessAlgorithm::_measureMoments(
306 if (!child.
getTable()->getCentroidKey().isValid()) {
308 "Centroid Key must be defined to measure the blendedness flux");
312 if (!child.
getTable()->getShapeKey().isValid()) {
314 "Shape Key must be defined to measure the blendedness shape");
319 if (child.
getTable()->getCentroidFlagKey().isValid()) {
327 if (child.
getTable()->getShapeFlagKey().isValid()) {
349 ShapeAccumulator accumulatorRaw;
350 ShapeAccumulator accumulatorAbs;
360 child.
set(fluxRawKey, accumulatorRaw.getFlux());
361 child.
set(fluxAbsKey,
std::max(accumulatorAbs.getFlux(), 0.0));
363 _shapeRawKey.
set(child, accumulatorRaw.getShape());
364 _shapeAbsKey.
set(child, accumulatorAbs.getShape());
365 }
else if (_ctrl.
doFlux) {
366 FluxAccumulator accumulatorRaw;
367 FluxAccumulator accumulatorAbs;
376 child.
set(fluxRawKey, accumulatorRaw.getFlux());
377 child.
set(fluxAbsKey,
std::max(accumulatorAbs.getFlux(), 0.0));
385 _measureMoments(image, child, _fluxChildRaw, _fluxChildAbs, _shapeChildRaw, _shapeChildAbs);
396 _measureMoments(image, child, _fluxParentRaw, _fluxParentAbs, _shapeParentRaw, _shapeParentAbs);
398 child.
set(_fluxRaw, 1.0 - child.
get(_fluxChildRaw)/child.
get(_fluxParentRaw));
399 child.
set(_fluxAbs, 1.0 - child.
get(_fluxChildAbs)/child.
get(_fluxParentAbs));
400 if (child.
get(_fluxParentAbs) == 0.0) {
virtual void set(afw::table::BaseRecord &record, ShapeResult const &value) const
Set a ShapeResult in the given record.
static FlagDefinition const NO_CENTROID
Extent< double, 2 > Extent2D
geom::Box2I getBBox(ImageOrigin origin=PARENT) const
ShapeSlotDefinition::MeasValue getShape() const
std::string join(std::string const &a, std::string const &b) const
_const_view_t::x_iterator const_x_iterator
bool getShapeFlag() const
std::shared_ptr< Footprint > getFootprint() const
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given flag index.
Field< T >::Value get(Key< T > const &key) const
static FlagDefinition const FAILURE
ImagePtr getImage() const
A FunctorKey for ShapeResult.
static float computeAbsExpectation(float data, float variance)
Compute the posterior expectation value of the true flux in a pixel from its (Gaussian) likelihood an...
static FlagDefinition const NO_SHAPE
std::shared_ptr< SourceTable const > getTable() const
Point< double, 2 > Point2D
void measureChildPixels(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child) const
bool getCentroidFlag() const
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" ;
T dynamic_pointer_cast(T... args)
std::unique_ptr< SchemaItem< U > > result
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.
#define LSST_EXCEPT(type,...)
Algorithm provides no uncertainy information at all.
static float computeAbsBias(float mu, float variance)
Compute the bias induced by using the absolute value of a pixel instead of its value.
x_iterator x_at(int x, int y) const
void set(Key< T > const &key, U const &value)
SpanPixelIterator Iterator
vector-type utility class to build a collection of FlagDefinitions
double getDeterminant() const
static FlagDefinitionList const & getFlagDefinitions()
bool doFlux
"Whether to compute quantities related to the Gaussian-weighted flux" ;
Key< T > addField(Field< T > const &field, bool doReplace=false)
bool doOld
"Whether to compute HeavyFootprint dot products (the old deblend.blendedness parameter)" ; ...
void measureParentPixels(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child) const
const_MaskedImageIterator< typename Image::x_iterator, typename Mask::x_iterator, typename Variance::x_iterator > const_x_iterator
CentroidSlotDefinition::MeasValue getCentroid() const
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.