30 namespace lsst {
namespace meas {
namespace extensions {
namespace simpleShape {
32 base::FlagDefinitionList flagDefinitions;
38 return flagDefinitions;
54 Span clipSpan(Span
const & span,
geom::Box2I const & box) {
55 if (span.getY() < box.
getMinY() || span.getY() > box.
getMaxY())
return Span();
56 return Span(span.getY(),
62 template <
typename Function,
typename Iterator>
63 void iterateSpan(Function &
function, Iterator pixIter, Span
const & span) {
65 Span::Iterator pointIter = span.begin(), pointEnd = span.end();
66 pointIter != pointEnd;
67 ++pointIter, ++pixIter
69 function(*pointIter, *pixIter);
73 template <
typename Function,
typename Image,
typename Region>
74 void 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);
99 image.x_at(span.getMinX() -
image.getX0(), span.getY() -
image.getY0()),
118 enum { Q0=0, QXX, QYY, QXY, QX, QY, N_Q };
119 enum { MXX=0, MYY, MXY, MX, MY, N_M };
121 typedef Eigen::Matrix<double,N_Q,1> VectorQ;
122 typedef Eigen::Matrix<double,N_Q,N_Q> MatrixQ;
123 typedef Eigen::Matrix<double,N_M,1> VectorM;
124 typedef Eigen::Matrix<double,N_M,N_M> MatrixM;
125 typedef Eigen::Matrix<double,N_M,N_Q> MatrixMQ;
127 struct 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();
141 covariance.selfadjointView<Eigen::Lower>().rankUpdate(q,
pixel.variance());
144 explicit RawMomentAccumulator(afw::geom::ellipses::Ellipse
const & weightEllipse) :
147 _center(weightEllipse.getCenter()),
148 _gt(weightEllipse.getCore().getGridTransform())
155 geom::LinearTransform _gt;
160 template <
typename T>
178 RawMomentAccumulator functor(weight);
179 iterateRegion(functor,
image, region);
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);
356 record.
set(_centroidResult, value.
center);
364 return _shapeResult ==
other._shapeResult &&
365 _centroidResult ==
other._centroidResult &&
366 _uncertantyResult ==
other._uncertantyResult;
371 return _shapeResult.
isValid() &&
406 #define INSTANTIATE_IMAGE(IMAGE) \
407 template SimpleShapeResult SimpleShape::computeMoments(\
408 afw::geom::ellipses::Ellipse const &, \