38 return flagDefinitions;
62template <
typename Function,
typename Iterator>
63void iterateSpan(Function & function, Iterator pixIter,
Span const & span) {
66 pointIter != pointEnd;
67 ++pointIter, ++pixIter
69 function(*pointIter, *pixIter);
73template <
typename Function,
typename Image,
typename Region>
74void iterateRegion(Function & function,
Image const &
image, Region
const & region) {
76 if (bbox.contains(region.getBBox())) {
80 typename Region::Iterator spanIter = region.begin(), spanEnd = region.end();
86 image.x_at(spanIter->getMinX() -
image.getX0(), spanIter->getY() -
image.getY0()),
92 typename Region::Iterator spanIter = region.begin(), spanEnd = region.end();
96 Span span = clipSpan(*spanIter, bbox);
118enum { Q0=0, QXX, QYY, QXY, QX, QY, N_Q };
119enum { MXX=0, MYY, MXY, MX, MY, N_M };
121typedef Eigen::Matrix<double,N_Q,1> VectorQ;
122typedef Eigen::Matrix<double,N_Q,N_Q> MatrixQ;
123typedef Eigen::Matrix<double,N_M,1> VectorM;
124typedef Eigen::Matrix<double,N_M,N_M> MatrixM;
125typedef Eigen::Matrix<double,N_M,N_Q> MatrixMQ;
127struct RawMomentAccumulator {
129 template <
typename PixelT>
130 void operator()(
geom::Point2I const & pos, PixelT
const & pixel) {
133 double w =
std::exp(-0.5 * (gtd.getX()*gtd.getX() + gtd.getY()*gtd.getY()));
134 VectorQ q = VectorQ::Constant(w);
135 q[QXX] *= d.getX() * d.getX();
136 q[QYY] *= d.getY() * d.getY();
137 q[QXY] *= d.getX() * d.getY();
140 moments += q *
pixel.image();
141 covariance.selfadjointView<Eigen::Lower>().rankUpdate(q,
pixel.variance());
144 explicit RawMomentAccumulator(afw::geom::ellipses::Ellipse
const & weightEllipse) :
145 moments(VectorQ::Zero()),
146 covariance(MatrixQ::Zero()),
147 _center(weightEllipse.getCenter()),
148 _gt(weightEllipse.getCore().getGridTransform())
155 geom::LinearTransform _gt;
178 RawMomentAccumulator functor(weight);
179 iterateRegion(functor,
image, region);
183 MatrixMQ dm_dq =
convertRawMoments(functor.moments, result.ellipse, result.center);
184 MatrixM mCov = dm_dq * functor.covariance.selfadjointView<Eigen::Lower>() * dm_dq.adjoint();
194 result.covariance = dc_dm * mCov.selfadjointView<Eigen::Lower>() * dc_dm.adjoint();
208 VectorM m = q.segment<N_M>(1) / q[Q0];
209 MatrixMQ dm_dq = MatrixMQ::Zero();;
210 dm_dq.block<N_M,N_M>(0,1) = MatrixM::Identity() / q[Q0];
211 dm_dq.col(Q0) = -m / q[Q0];
213 m[MXX] -= m[MX] * m[MX];
214 m[MYY] -= m[MY] * m[MY];
215 m[MXY] -= m[MX] * m[MY];
216 dm_dq(MXX, QX) = -2.0 * m[MX] / q[Q0];
217 dm_dq(MYY, QY) = -2.0 * m[MY] / q[Q0];
218 dm_dq(MXY, QX) = m[MY] / q[Q0];
219 dm_dq(MXY, QY) = m[MX] / q[Q0];
220 double tmp = 2.0 / (q[Q0] * q[Q0] * q[Q0]);
221 dm_dq(MXX, Q0) += tmp * q[QX] * q[QX];
222 dm_dq(MYY, Q0) += tmp * q[QY] * q[QY];
223 dm_dq(MXY, Q0) += tmp * q[QX] * q[QY];
239 Eigen::Matrix2d wMat = weight.
getMatrix();
240 Eigen::Vector2d mVec = center.
asEigen();
241 Eigen::Matrix2d mMat = ellipse.
getMatrix();
242 if (wMat.determinant() <= 0.0) {
245 "Weight moments matrix is singular",
249 if (mMat.determinant() <= 0.0) {
252 "Measured moments matrix is singular",
256 Eigen::Matrix2d mInv = mMat.inverse();
257 Eigen::Matrix2d cInv = mInv - wMat.inverse();
258 if (cInv.determinant() <= 0.0) {
261 "Corrected moments matrix is singular",
265 Eigen::Matrix2d cMat = cInv.inverse();
266 ellipse.
setIxx(cMat(0, 0));
267 ellipse.
setIyy(cMat(1, 1));
268 ellipse.
setIxy(cMat(0, 1));
269 Eigen::Matrix2d cMat_mInv = cMat * mInv;
270 Eigen::Vector2d mInv_mVec = mInv * mVec;
271 Eigen::Vector2d cVec = cMat_mInv * mVec;
272 center.setX(cVec[0]);
273 center.setY(cVec[1]);
274 Eigen::Matrix2d dcMat_dmxx = cMat_mInv.col(0) * cMat_mInv.col(0).adjoint();
275 Eigen::Matrix2d dcMat_dmyy = cMat_mInv.col(1) * cMat_mInv.col(1).adjoint();
276 Eigen::Matrix2d dcMat_dmxy = cMat_mInv.col(0) * cMat_mInv.col(1).adjoint()
277 + cMat_mInv.col(1) * cMat_mInv.col(0).adjoint();
278 Eigen::Vector2d dcVec_dmxx = cMat_mInv.col(0) * mInv_mVec[0];
279 Eigen::Vector2d dcVec_dmyy = cMat_mInv.col(1) * mInv_mVec[1];
280 Eigen::Vector2d dcVec_dmxy = cMat_mInv.col(0) * mInv_mVec[1] + cMat_mInv.col(1) * mInv_mVec[0];
281 Eigen::Matrix2d
const & dcVec_dmVec = cMat_mInv;
285 MatrixM dc_dm = MatrixM::Zero();
286 dc_dm(MXX, MXX) = dcMat_dmxx(0, 0);
287 dc_dm(MYY, MXX) = dcMat_dmxx(1, 1);
288 dc_dm(MXY, MXX) = dcMat_dmxx(0, 1);
289 dc_dm(MXX, MYY) = dcMat_dmyy(0, 0);
290 dc_dm(MYY, MYY) = dcMat_dmyy(1, 1);
291 dc_dm(MXY, MYY) = dcMat_dmyy(0, 1);
292 dc_dm(MXX, MXY) = dcMat_dmxy(0, 0);
293 dc_dm(MYY, MXY) = dcMat_dmxy(1, 1);
294 dc_dm(MXY, MXY) = dcMat_dmxy(0, 1);
295 dc_dm(MX, MXX) = dcVec_dmxx[0];
296 dc_dm(MY, MXX) = dcVec_dmxx[1];
297 dc_dm(MX, MYY) = dcVec_dmyy[0];
298 dc_dm(MY, MYY) = dcVec_dmyy[1];
299 dc_dm(MX, MXY) = dcVec_dmxy[0];
300 dc_dm(MY, MXY) = dcVec_dmxy[1];
301 dc_dm(MX, MX) = dcVec_dmVec(0, 0);
302 dc_dm(MX, MY) = dcVec_dmVec(0, 1);
303 dc_dm(MY, MX) = dcVec_dmVec(1, 0);
304 dc_dm(MY, MY) = dcVec_dmVec(1, 1);
325 name,
"elliptical Gaussian moments");
327 name,
"elliptical Gaussian moments",
"pixel");
330 "Ix",
"Iy"}),
"pixel");
339 _uncertantyResult(s,
std::vector<
std::string> ({
"Ixx",
"Iyy",
"Ixy",
"Ix",
"Iy"})),
345 result.ellipse = record.
get(_shapeResult);
346 result.center = record.
get(_centroidResult);
347 result.covariance = record.
get(_uncertantyResult);
349 result.flags[n] = _flagHandler.getValue(record, n);
355 record.
set(_shapeResult, value.ellipse);
356 record.
set(_centroidResult, value.center);
357 record.
set(_uncertantyResult, value.covariance);
359 _flagHandler.setValue(record, n, value.flags[n]);
364 return _shapeResult == other._shapeResult &&
365 _centroidResult == other._centroidResult &&
366 _uncertantyResult == other._uncertantyResult;
371 return _shapeResult.
isValid() &&
372 _centroidResult.isValid() &&
373 _uncertantyResult.isValid();
385 _centroidExtractor(schema,
name)
392 geom::Point2D center = _centroidExtractor(source, _resultKey.getFlagHandler());
396 source.set(_resultKey, result);
403 _resultKey.getFlagHandler().handleFailure(measRecord, error);
406#define INSTANTIATE_IMAGE(IMAGE) \
407 template SimpleShapeResult SimpleShape::computeMoments(\
408 afw::geom::ellipses::Ellipse const &, \
406#define INSTANTIATE_IMAGE(IMAGE) \ …
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
A range of pixels within one row of an Image.
An ellipse core for the semimajor/semiminor axis and position angle parametrization (a,...
void scale(double factor)
Scale the size of the ellipse core by the given factor.
Converter< Output > as() const
Convert this to the core type specified as a template parameter.
An ellipse defined by an arbitrary BaseCore and a center point.
lsst::geom::Point2D const & getCenter() const
Return the center point.
BaseCore const & getCore() const
Return the ellipse core.
A pixelized region containing all pixels whose centers are within an Ellipse.
An ellipse core with quadrupole moments as parameters.
Matrix const & getMatrix() const
Return a 2x2 symmetric matrix of the parameters.
A class to contain the data, WCS, and other information needed to describe an image of the sky.
A class to manipulate images, masks, and variance as a single object.
Base class for all records.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
static CovarianceMatrixKey addFields(Schema &schema, std::string const &prefix, NameArray const &names, std::string const &unit, bool diagonalOnly=false)
Add covariance matrix fields to a Schema, and return a CovarianceMatrixKey to manage them.
bool isValid() const noexcept
Return True if all the constituent error Keys are valid.
static PointKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
static QuadrupoleKey addFields(Schema &schema, std::string const &name, std::string const &doc, CoordinateType coordType=CoordinateType::PIXEL)
Add a set of quadrupole subfields to a schema and return a QuadrupoleKey that points to them.
Defines the fields and offsets for a table.
Record class that contains measurements made on a single exposure.
A proxy type for name lookups in a Schema.
An integer coordinate rectangle.
int getMinY() const noexcept
int getMinX() const noexcept
int getMaxX() const noexcept
int getMaxY() const noexcept
EigenVector const & asEigen() const noexcept(IS_ELEMENT_NOTHROW_COPYABLE)
vector-type utility class to build a collection of FlagDefinitions
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.
Exception to be thrown when a measurement algorithm experiences a known failure mode.
SimpleShape(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
static Eigen::Matrix< double, 5, 5 > correctWeightedMoments(afw::geom::ellipses::Quadrupole const &weight, afw::geom::ellipses::Quadrupole &ellipse, geom::Point2D ¢er)
Correct moments measured with a Gaussian weight function by assuming the data was also an elliptical ...
static SimpleShapeResult computeMoments(afw::geom::ellipses::Ellipse const &weight, afw::image::MaskedImage< T > const &image, double nSigmaRegion=3.0)
Compute the Gaussian-weighted moments of an image.
virtual void fail(afw::table::SourceRecord &measRecord, lsst::meas::base::MeasurementError *error=NULL) const
Handle an exception thrown by the current algorithm by setting flags in the given record.
static unsigned int const N_FLAGS
SimpleShapeControl Control
static base::FlagDefinitionList const & getFlagDefinitions()
static base::FlagDefinition const FAILURE
static Eigen::Matrix< double, 5, 6 > convertRawMoments(Eigen::Matrix< double, 6, 1 > const &q, afw::geom::ellipses::Quadrupole &quadrupole, geom::Point2D ¢er)
Convert linear raw moments into an ellipse and centroid, and return the derivative of the conversion.
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Called to measure a single child source in an image.
Struct to hold the results of SimpleShape when we don't run it as a plugin.
geom::Point2D center
Measured first moments, or the input center if !recentroid.
SimpleShapeResult()
Constructor; initializes everything to Nan.
Eigen::Matrix< double, 5, 5 > covariance
Matrix of uncertainties; ordered Ixx, Iyy, Ixy, Ix, Iy.
afw::geom::ellipses::Quadrupole ellipse
Measured second moments.
virtual void set(afw::table::BaseRecord &record, SimpleShapeResult const &value) const
virtual SimpleShapeResult get(afw::table::BaseRecord const &record) const
bool isValid() const
Return True if the key is valid.
bool operator==(SimpleShapeResultKey const &other) const
Compare the FunctorKey for equality with another, using the underlying Keys.
static SimpleShapeResultKey addFields(afw::table::Schema &schema, std::string const &name)
A range of pixels within one row of an Image.
int getMinX() const noexcept
Minimum x-value.
int getMaxX() const noexcept
Maximum x-value.
SpanPixelIterator Iterator
An iterator over points in the Span.
Iterator begin() const noexcept
Return an iterator to the first pixel in the Span.
int getY() const noexcept
Return the y-value.
Iterator end() const noexcept
Return an iterator to one past the last pixel in the Span.
#define INSTANTIATE_IMAGE(IMAGE)
Extent< double, 2 > Extent2D
Point< double, 2 > Point2D
Simple class used to define and document flags The name and doc constitute the identity of the FlagDe...
g2d::python::Image< double > Image