lsst.meas.algorithms g1581cd22ba+2a89f360ba
Loading...
Searching...
No Matches
SpanSetMoments.cc
Go to the documentation of this file.
1// -*- LSST-C++ -*-
2
3/*
4 * LSST Data Management System
5 * Copyright 2008, 2009, 2010 LSST Corporation.
6 *
7 * This product includes software developed by the
8 * LSST Project (http://www.lsst.org/).
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the LSST License Statement and
21 * the GNU General Public License along with this program. If not,
22 * see <http://www.lsstcorp.org/LegalNotices/>.
23 */
24
25#include <limits>
26#include "Eigen/Dense"
28#include "ndarray/eigen.h"
30#include <Eigen/src/Core/util/Constants.h>
32
33namespace lsst {
34namespace meas {
35namespace algorithms {
36
37ndarray::Array<float, 1, 1> SpanSetMoments::get_x_array() const {
38 ndarray::Array<float, 1, 1> result = ndarray::allocate(spans->getArea());
39 spans->applyFunctor([](geom::Point2I const& point, float& out) { out = point.getX(); },
40 ndarray::ndFlat(result));
41 return result;
42}
43
44ndarray::Array<float, 1, 1> SpanSetMoments::get_y_array() const {
45 ndarray::Array<float, 1, 1> result = ndarray::allocate(spans->getArea());
46 spans->applyFunctor([](geom::Point2I const& point, float& out) { out = point.getY(); },
47 ndarray::ndFlat(result));
48 return result;
49}
50
52 afw::image::MaskedImage<float> const& masked_image,
53 afw::image::MaskPixel bad_bitmask,
54 double bad_pixel_max_fraction,
55 double bad_pixel_exclusion_radius) {
56 double const nan = std::numeric_limits<double>::quiet_NaN();
59 auto area = spans.getArea();
60 auto bbox = spans.getBBox();
61 auto bad_spans = afw::geom::SpanSet::fromMask((*masked_image.getMask())[bbox], bad_bitmask);
62 result->spans = spans.intersectNot(*bad_spans);
63 if ((area - result->spans->getArea()) > (bad_pixel_max_fraction * area)) {
64 result->too_many_bad_pixels = true;
65 return result;
66 }
67 // Compute the variance of the flux.
68 result->variance = 0.0;
69 result->spans->applyFunctor(
70 [&result](geom::Point2I const& point, float data) { result->variance += data; },
71 *masked_image.getVariance());
72 // Compute the flux (zeroth moment) and center (first moments).
73 result->flux = 0.0;
74 double qx = 0.0;
75 double qy = 0.0;
76 result->spans->applyFunctor(
77 [&result, &qx, &qy](geom::Point2I const& point, float data) {
78 result->flux += data;
79 qx += point.getX() * data;
80 qy += point.getY() * data;
81 },
82 *masked_image.getImage());
83 result->center.setX(qx / result->flux);
84 result->center.setY(qy / result->flux);
85 // Check to see if the center is plausible, and that it is not too close
86 // to a bad pixel.
87 if (!spans.contains(geom::Point2I(result->center))) {
88 result->center_out_of_bounds = true;
89 return result;
90 }
91 double min_bad_pixel_center_distance_squared = std::numeric_limits<double>::infinity();
92 for (auto const& span : *bad_spans) {
93 for (auto point : span) {
94 min_bad_pixel_center_distance_squared =
95 std::min(geom::Point2D(point).distanceSquared(result->center),
96 min_bad_pixel_center_distance_squared);
97 }
98 }
99 if (min_bad_pixel_center_distance_squared < bad_pixel_exclusion_radius * bad_pixel_exclusion_radius) {
100 result->bad_pixel_in_center = true;
101 return result;
102 }
103 // Compute the second moments.
104 double qxx = 0.0;
105 double qyy = 0.0;
106 double qxy = 0.0;
107 result->spans->applyFunctor(
108 [&result, &qxx, &qyy, &qxy](geom::Point2I const& point, float data) {
109 double dx = point.getX() - result->center.getX();
110 double dy = point.getY() - result->center.getY();
111 qxx += dx * dx * data;
112 qyy += dy * dy * data;
113 qxy += dx * dy * data;
114 },
115 *masked_image.getImage());
116 result->shape.setIxx(qxx / result->flux);
117 result->shape.setIyy(qyy / result->flux);
118 result->shape.setIxy(qxy / result->flux);
119 if (result->shape.getDeterminant() <= 0.0 || !std::isfinite(result->shape.getTraceRadius())) {
120 result->singular_second_moments = true;
121 return result;
122 }
123 return result;
124}
125
127 afw::image::MaskedImage<float> const& masked_image,
128 std::vector<std::shared_ptr<SpanSetMoments>> const& sources, int order, double scale) {
129 std::size_t n_pixels = std::accumulate(sources.begin(), sources.end(), 0,
130 [](std::size_t n, std::shared_ptr<SpanSetMoments> const& source) {
131 return n + source->spans->getArea();
132 });
133 std::size_t n_coeff = shapelet::computeSize(order);
134 ndarray::Array<float, 1, 1> data_array = ndarray::allocate(n_pixels);
135 data_array.deep() = 0.0;
136 // We allocate the design matrix via its transpose, because that yields
137 // the memory order expected by the shapelet library and the better
138 // memory order for the least-squares solver.
139 ndarray::Array<float, 2, -2> design_matrix =
140 ndarray::Array<float, 2, 2>(ndarray::allocate(n_coeff, n_pixels)).transpose();
141 design_matrix.deep() = 0.0;
142 std::size_t start = 0;
143 for (auto const& source : sources) {
144 shapelet::MatrixBuilder<float> builder(source->get_x_array(), source->get_y_array(), order);
145 std::size_t stop = start + builder.getDataSize();
146 auto source_data_array = data_array[ndarray::view(start, stop)].shallow();
147 ndarray::Array<float, 1, 1> source_weight_array = ndarray::allocate(builder.getDataSize());
148 source->spans->applyFunctor(
149 [](geom::Point2I const& point, float& data, float& weight, float img, float var) {
150 weight = 1.0 / std::sqrt(var);
151 data = img * weight;
152 },
153 ndFlat(source_data_array), ndFlat(source_weight_array), *masked_image.getImage(),
154 *masked_image.getVariance());
155 auto source_design_matrix = design_matrix[ndarray::view(start, stop)()].shallow();
156 afw::geom::ellipses::Ellipse ellipse(source->shape, source->center);
157 ellipse.scale(scale);
158 builder(source_design_matrix, ellipse);
159 asEigenArray(source_design_matrix) *= source->flux;
160 asEigenArray(source_design_matrix).colwise() *= asEigenArray(source_weight_array);
161 start = stop;
162 }
164 asEigenMatrix(result.getCoefficients()) = asEigenMatrix(design_matrix)
165 .bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV)
166 .solve(asEigenMatrix(data_array)).cast<double>();
167 return result;
168}
169
170} // namespace algorithms
171} // namespace meas
172} // namespace lsst
T accumulate(T... args)
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, UnaryPredicate comparator=details::AnyBitSetFunctor< T >())
VariancePtr getVariance() const
ndarray::Array< double, 1, 1 > const getCoefficients()
T infinity(T... args)
T isfinite(T... args)
T min(T... args)
std::int32_t MaskPixel
Point< double, 2 > Point2D
Point< int, 2 > Point2I
int computeSize(int order)
details::FlatNdGetter< T, inA, inB > ndFlat(ndarray::Array< T, inA, inB > const &array)
T quiet_NaN(T... args)
T sqrt(T... args)
A struct that computes the unweighted moments of the pixels in an lsst.afw.geom.SpanSet.
static shapelet::ShapeletFunction fit_shapelets(afw::image::MaskedImage< float > const &masked_image, std::vector< std::shared_ptr< SpanSetMoments > > const &moments, int order, double scale)
Fit a common shapelet expansion to multiple sources whose moments have already been computed.
ndarray::Array< float, 1, 1 > get_y_array() const
Return a flattened array of the y coordinates in spans.
static std::shared_ptr< SpanSetMoments > compute(afw::geom::SpanSet const &spans, afw::image::MaskedImage< float > const &masked_image, afw::image::MaskPixel bad_bitmask, double bad_pixel_max_fraction, double bad_pixel_exclusion_radius)
Compute the unweighted moments of an image within a SpanSet.
std::shared_ptr< afw::geom::SpanSet > spans
The pixels actually used to compute the moments.
ndarray::Array< float, 1, 1 > get_x_array() const
Return a flattened array of the x coordinates in spans.