27 #include "boost/math/constants/constants.hpp" 40 FlagDefinitionList flagDefinitions;
45 flagDefinitions.add(
"flag_noCentroid",
"Object has no centroid");
47 flagDefinitions.add(
"flag_noShape",
"Object has no shape");
55 if (!childFootprint) {
75 auto spanIter = childHeavy->getSpans()->begin();
76 auto const spanEnd = childHeavy->getSpans()->end();
77 ChildPixIter childPixIter = childHeavy->getImageArray().begin();
80 while (spanIter != spanEnd) {
82 ParentPixIter parentPixIter =
86 for (
int x = 0;
x < width; ++parentPixIter, ++childPixIter, ++
x) {
87 cp += (*childPixIter) * ((*parentPixIter) - (*childPixIter));
88 cc += (*childPixIter) * (*childPixIter);
98 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; }
116 class ShapeAccumulator :
public FluxAccumulator {
118 ShapeAccumulator() : FluxAccumulator(), _wdxx(0.0), _wdyy(0.0), _wdxy(0.0) {}
120 void operator()(
double x,
double y,
float weight,
float data) {
121 FluxAccumulator::operator()(x, y, weight, data);
122 _wdxx += x * x * weight *
data;
123 _wdyy += y * y * weight *
data;
124 _wdxy += x * y * weight *
data;
127 ShapeResult getShape()
const {
131 result.xx = 2.0 * _wdxx /
_wd;
132 result.yy = 2.0 * _wdyy /
_wd;
133 result.xy = 2.0 * _wdxy /
_wd;
143 template <
typename Accumulator>
145 afw::geom::ellipses::Quadrupole
const& shape,
double nSigmaWeightMax,
146 Accumulator& accumulatorRaw, Accumulator& accumulatorAbs) {
149 afw::geom::ellipses::Ellipse
ellipse(shape, centroid);
150 ellipse.getCore().scale(nSigmaWeightMax);
161 afw::geom::ellipses::PixelRegion
region(ellipse);
162 bool isContained = bbox.
contains(region.getBBox());
163 SpanIter
const spanEnd = region.end();
164 for (SpanIter spanIter = region.begin(); spanIter != spanEnd; ++spanIter) {
165 afw::geom::Span
span = *spanIter;
167 if (span.getY() < bbox.
getMinY() || span.getY() > bbox.
getMaxY()) {
170 span = afw::geom::Span(span.getY(),
std::max(span.getMinX(), bbox.
getMinX()),
172 if (span.getMinX() > span.getMaxX()) {
176 PixelIter pixelIter = image.x_at(span.getBeginX() - image.getX0(), span.getY() - image.getY0());
177 PointIter
const pointEnd = span.end();
178 for (PointIter pointIter = span.begin(); pointIter != pointEnd; ++pointIter, ++pixelIter) {
183 float data = pixelIter.image();
184 accumulatorRaw(d.getX(), d.getY(),
weight,
data);
185 float variance = pixelIter.variance();
188 accumulatorAbs(d.getX(), d.getY(),
weight,
std::abs(data) - bias);
200 schema.
join(name,
"old"),
201 "Blendedness from dot products: (child.dot(parent)/child.dot(child) - 1)");
205 schema.
join(name,
"raw"),
206 "Measure of how much the flux is affected by neighbors: " 207 "(1 - child_instFlux/parent_instFlux). Operates on the \"raw\" pixel values.");
208 _instFluxChildRaw = schema.
addField<
double>(
209 schema.
join(name,
"raw_child_instFlux"),
210 "Instrumental flux of the child, measured with a Gaussian weight matched to the child. " 211 "Operates on the \"raw\" pixel values.",
"count");
212 _instFluxParentRaw = schema.
addField<
double>(
213 schema.
join(name,
"raw_parent_instFlux"),
214 "Instrumental flux of the parent, measured with a Gaussian weight matched to the child. " 215 "Operates on the \"raw\" pixel values.",
"count");
217 schema.
join(name,
"abs"),
218 "Measure of how much the flux is affected by neighbors: " 219 "(1 - child_instFlux/parent_instFlux). " 220 "Operates on the absolute value of the pixels to try to obtain a \"de-noised\" value. " 221 "See section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details.");
222 _instFluxChildAbs = schema.
addField<
double>(
223 schema.
join(name,
"abs_child_instFlux"),
224 "Instrumental flux of the child, measured with a Gaussian weight matched to the child. " 225 "Operates on the absolute value of the pixels to try to obtain a \"de-noised\" value. " 226 "See section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details.",
"count");
227 _instFluxParentAbs = schema.
addField<
double>(
228 schema.
join(name,
"abs_parent_instFlux"),
229 "Instrumental flux of the parent, measured with a Gaussian weight matched to the child. " 230 "Operates on the absolute value of the pixels to try to obtain a \"de-noised\" value. " 231 "See section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details.",
"count");
235 schema, schema.
join(name,
"raw_child"),
236 "Shape of the child, measured with a Gaussian weight matched to the child. " 239 schema, schema.
join(name,
"raw_parent"),
240 "Shape of the parent, measured with a Gaussian weight matched to the child. " 243 schema, schema.
join(name,
"abs_child"),
244 "Shape of the child, measured with a Gaussian weight matched to the child. " 245 "Operates on the absolute value of the pixels to try to obtain a \"de-noised\" value. " 246 "See section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details.",
249 schema, schema.
join(name,
"abs_parent"),
250 "Shape of the parent, measured with a Gaussian weight matched to the child. " 251 "Operates on the absolute value of the pixels to try to obtain a \"de-noised\" value. " 252 "See section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details.",
262 if (!(normalization > 0)) {
266 return data + (
std::sqrt(0.5f * variance / boost::math::constants::pi<float>()) *
267 std::exp(-0.5f * (data * data) / variance) / normalization);
271 return (
std::sqrt(2.0f * variance / boost::math::constants::pi<float>()) *
272 std::exp(-0.5f * (mu * mu) / variance)) -
283 if (!child.
getTable()->getCentroidKey().isValid()) {
285 "Centroid Key must be defined to measure the blendedness instFlux");
289 if (!child.
getTable()->getShapeKey().isValid()) {
291 "Shape Key must be defined to measure the blendedness shape");
296 if (child.
getTable()->getCentroidFlagKey().isValid()) {
304 if (child.
getTable()->getShapeFlagKey().isValid()) {
326 ShapeAccumulator accumulatorRaw;
327 ShapeAccumulator accumulatorAbs;
331 child.
set(instFluxRawKey, accumulatorRaw.getFlux());
332 child.
set(instFluxAbsKey,
std::max(accumulatorAbs.getFlux(), 0.0));
334 _shapeRawKey.
set(child, accumulatorRaw.getShape());
335 _shapeAbsKey.
set(child, accumulatorAbs.getShape());
336 }
else if (_ctrl.
doFlux) {
337 FluxAccumulator accumulatorRaw;
338 FluxAccumulator accumulatorAbs;
341 child.
set(instFluxRawKey, accumulatorRaw.getFlux());
342 child.
set(instFluxAbsKey,
std::max(accumulatorAbs.getFlux(), 0.0));
348 _measureMoments(image, child, _instFluxChildRaw, _instFluxChildAbs, _shapeChildRaw, _shapeChildAbs);
356 _measureMoments(image, child, _instFluxParentRaw, _instFluxParentAbs, _shapeParentRaw, _shapeParentAbs);
358 child.
set(_raw, 1.0 - child.
get(_instFluxChildRaw) / child.
get(_instFluxParentRaw));
359 child.
set(_abs, 1.0 - child.
get(_instFluxChildAbs) / child.
get(_instFluxParentAbs));
360 if (child.
get(_instFluxParentAbs) == 0.0) {
int getBeginX() const noexcept
Begin (inclusive) x-value.
Defines the fields and offsets for a table.
T computeSquaredNorm() const
Return the squared L2 norm of the Extent (x^2 + y^2 + ...).
virtual void set(afw::table::BaseRecord &record, ShapeResult const &value) const
Set a ShapeResult in the given record.
Angle abs(Angle const &a)
static FlagDefinition const NO_CENTROID
ShapeSlotDefinition::MeasValue getShape() const
Get the value of the Shape slot measurement.
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
A range of pixels within one row of an Image.
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
bool getShapeFlag() const
Return true if the measurement in the Shape slot failed.
std::shared_ptr< Footprint > getFootprint() const
int getX0() const
Return the image's column-origin.
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
Return the value of a field for the given key.
static FlagDefinition const FAILURE
Point< double, 2 > Point2D
ImagePtr getImage() const
Return a (shared_ptr to) the MaskedImage's image.
A FunctorKey for ShapeResult.
static float computeAbsExpectation(float data, float variance)
Compute the posterior expectation value of the true instrumental flux in a pixel from its (Gaussian) ...
FastFinder::Iterator Iterator
std::vector< Span >::const_iterator Iterator
Iterator type used by begin() and end().
static FlagDefinition const NO_SHAPE
A base class for image defects.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
std::shared_ptr< SourceTable const > getTable() const
UnitVector3d centroid(VertexIterator const begin, VertexIterator const end)
int getMaxY() const noexcept
void measureChildPixels(afw::image::MaskedImage< float > const &image, afw::table::SourceRecord &child) const
int getWidth() const noexcept
Return the number of pixels.
double getX() const
Return the centroid slot x coordinate.
A class to manipulate images, masks, and variance as a single object.
bool getCentroidFlag() const
Return true if the measurement in the Centroid slot failed.
double nSigmaWeightMax
"Radius factor that sets the maximum extent of the weight function (and hence the " "flux measurement...
bool doShape
"Whether to compute quantities related to the Gaussian-weighted shape" ;
T dynamic_pointer_cast(T... args)
Reports errors in the logical structure of the program.
int getMaxX() const noexcept
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.
int getMinX() const noexcept
afw::table::Key< double > weight
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
int getY0() const
Return the image's row-origin.
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
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.
double getY() const
Return the centroid slot y coordinate.
x_iterator x_at(int x, int y) const
Return an x_iterator to the point (x, y) in the image.
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Record class that contains measurements made on a single exposure.
int getY() const noexcept
Return the y-value.
SpanPixelIterator Iterator
An iterator over points in the Span.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
vector-type utility class to build a collection of FlagDefinitions
double getDeterminant() const
Return the determinant of the matrix representation.
static FlagDefinitionList const & getFlagDefinitions()
bool doFlux
"Whether to compute quantities related to the Gaussian-weighted flux" ;
An integer coordinate rectangle.
A class to represent a 2-dimensional array of pixels.
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
bool doOld
"Whether to compute HeavyFootprint dot products (the old deblend.blendedness parameter)" ; ...
int getMinY() const noexcept
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
A const_iterator to a row of a MaskedImage.
CentroidSlotDefinition::MeasValue getCentroid() const
Get the value of the Centroid slot measurement.
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.