LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
HeavyFootprint.cc
Go to the documentation of this file.
1/*
2 * LSST Data Management System
3 * Copyright 2008, 2009, 2010 LSST Corporation.
4 *
5 * This product includes software developed by the
6 * LSST Project (http://www.lsst.org/).
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the LSST License Statement and
19 * the GNU General Public License along with this program. If not,
20 * see <http://www.lsstcorp.org/LegalNotices/>.
21 */
22
23#include <cstdint>
24#include <string>
25#include <memory>
26
27#include "lsst/pex/exceptions.h"
36
37namespace lsst {
38namespace afw {
39namespace detection {
40namespace {
41
42template <typename T>
43struct FlattenWithSetter {
44 FlattenWithSetter(T val) : _val(val) {}
45
46 void operator()(lsst::geom::Point2I const& point, T& out, T& in) {
47 out = in;
48 in = _val;
49 }
50
51private:
52 T _val;
53};
54
55template <>
56struct FlattenWithSetter<lsst::afw::image::MaskPixel> {
58 FlattenWithSetter(T val) : _mask(~val) {}
59
60 void operator()(lsst::geom::Point2I const& point, T& out, T& in) {
61 out = in;
62 in &= _mask;
63 }
64
65private:
66 T _mask;
67};
68} // namespace
69
70template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
73 HeavyFootprintCtrl const* ctrl)
74 : Footprint(foot),
75 _image(ndarray::allocate(ndarray::makeVector(foot.getArea()))),
76 _mask(ndarray::allocate(ndarray::makeVector(foot.getArea()))),
77 _variance(ndarray::allocate(ndarray::makeVector(foot.getArea()))) {
79
80 if (!ctrl) {
81 ctrl = &ctrl_s;
82 }
83
84 switch (ctrl->getModifySource()) {
86 getSpans()->flatten(_image, mimage.getImage()->getArray(), mimage.getXY0());
87 getSpans()->flatten(_mask, mimage.getMask()->getArray(), mimage.getXY0());
88 getSpans()->flatten(_variance, mimage.getVariance()->getArray(), mimage.getXY0());
89 break;
91 ImagePixelT const ival = ctrl->getImageVal();
92 MaskPixelT const mval = ctrl->getMaskVal();
93 VariancePixelT const vval = ctrl->getVarianceVal();
94
95 getSpans()->applyFunctor(FlattenWithSetter<ImagePixelT>(ival), ndarray::ndFlat(_image),
96 ndarray::ndImage(mimage.getImage()->getArray(), mimage.getXY0()));
97 getSpans()->applyFunctor(FlattenWithSetter<MaskPixelT>(mval), ndarray::ndFlat(_mask),
98 ndarray::ndImage(mimage.getMask()->getArray(), mimage.getXY0()));
99 getSpans()->applyFunctor(FlattenWithSetter<VariancePixelT>(vval), ndarray::ndFlat(_variance),
100 ndarray::ndImage(mimage.getVariance()->getArray(), mimage.getXY0()));
101 break;
102 }
103 }
104}
105
106template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
108 HeavyFootprintCtrl const* ctrl)
109 : Footprint(foot),
110 _image(ndarray::allocate(ndarray::makeVector(foot.getArea()))),
111 _mask(ndarray::allocate(ndarray::makeVector(foot.getArea()))),
112 _variance(ndarray::allocate(ndarray::makeVector(foot.getArea()))) {}
113
114template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
117 getSpans()->unflatten(mimage.getImage()->getArray(), _image, mimage.getXY0());
118 getSpans()->unflatten(mimage.getMask()->getArray(), _mask, mimage.getXY0());
119 getSpans()->unflatten(mimage.getVariance()->getArray(), _variance, mimage.getXY0());
120}
121
122template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
124 getSpans()->unflatten(image.getArray(), _image, image.getXY0());
125}
126
127template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
131 // Merge the Footprints (by merging the Spans)
133
134 // Find the union bounding-box
136 bbox.include(h2.getBBox());
137
138 // Create union-bb-sized images and insert the heavies
141 h1.insert(im1);
142 h2.insert(im2);
143 // Add the pixels
144 im1 += im2;
145
146 // Build new HeavyFootprint from the merged spans and summed pixels.
147 return std::make_shared<HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT>>(*foot, im1);
148}
149
150template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
153 // Coordinated cycling through the iterators while juggling the offsets into the arrays
154 using ArrayIter = typename ndarray::Array<const ImagePixelT, 1, 1>::Iterator;
155 ArrayIter lhsArray = getImageArray().begin(), rhsArray = rhs.getImageArray().begin();
156 auto lhsIter = getSpans()->begin(), rhsIter = rhs.getSpans()->begin();
157 auto const lhsEnd = getSpans()->end(), rhsEnd = rhs.getSpans()->end();
158 double sum = 0.0;
159 while (lhsIter != lhsEnd && rhsIter != rhsEnd) {
160 geom::Span const &lhsSpan = *lhsIter, rhsSpan = *rhsIter;
161 int const yLhs = lhsSpan.getY(), yRhs = rhsSpan.getY();
162 if (yLhs == yRhs) {
163 int const x0Lhs = lhsSpan.getX0(), x1Lhs = lhsSpan.getX1();
164 int const x0Rhs = rhsSpan.getX0(), x1Rhs = rhsSpan.getX1();
165 int const xMin = std::max(x0Lhs, x0Rhs), xMax = std::min(x1Lhs, x1Rhs);
166 if (xMin <= xMax) {
167 lhsArray += xMin - x0Lhs;
168 rhsArray += xMin - x0Rhs;
169 for (int x = xMin; x <= xMax; ++x, ++lhsArray, ++rhsArray) {
170 sum += (*lhsArray) * (*rhsArray);
171 }
172 // Rewind to the start of the span, for easier sync between spans and arrays
173 lhsArray -= xMax + 1 - x0Lhs;
174 rhsArray -= xMax + 1 - x0Rhs;
175 }
176 if (x1Lhs <= x1Rhs) {
177 lhsArray += lhsSpan.getWidth();
178 ++lhsIter;
179 } else {
180 rhsArray += rhsSpan.getWidth();
181 ++rhsIter;
182 }
183 continue;
184 } else if (yLhs < yRhs) {
185 while (lhsIter != lhsEnd && lhsIter->getY() < yRhs) {
186 lhsArray += lhsIter->getWidth();
187 ++lhsIter;
188 }
189 continue;
190 } else { // yLhs > yRhs
191 while (rhsIter != rhsEnd && rhsIter->getY() < yLhs) {
192 rhsArray += rhsIter->getWidth();
193 ++rhsIter;
194 }
195 continue;
196 }
197 }
198 return sum;
199}
200
201// Persistence (using afw::table::io)
202//
203
204namespace {
205
206// Schema and Keys used to persist the pixels of a HeavyFootprint (Spans and Peaks are handled by the
207// Footprint base class). This is a singleton, but a different one for each template instantiation.
208template <typename ImagePixelT, typename MaskPixelT = image::MaskPixel,
209 typename VariancePixelT = image::VariancePixel>
210struct HeavyFootprintPersistenceHelper {
211 afw::table::Schema schema;
212 afw::table::Key<afw::table::Array<ImagePixelT>> image;
213 afw::table::Key<afw::table::Array<MaskPixelT>> mask;
214 afw::table::Key<afw::table::Array<VariancePixelT>> variance;
215
216 static HeavyFootprintPersistenceHelper const& get() {
217 static HeavyFootprintPersistenceHelper const instance;
218 return instance;
219 }
220
221private:
222 HeavyFootprintPersistenceHelper()
223 : schema(),
224 image(schema.addField<afw::table::Array<ImagePixelT>>(
225 "image", "image pixels for HeavyFootprint", "count")),
226 mask(schema.addField<afw::table::Array<MaskPixelT>>("mask", "mask pixels for HeavyFootprint")),
227 variance(schema.addField<afw::table::Array<VariancePixelT>>(
228 "variance", "variance pixels for HeavyFootprint", "count^2")) {}
229};
230
231// These suffix-computing structs are used to compute the string name associated with a HeavyFootprint
232// for Persistence.
233// We don't instantiate HeavyFootprints with anything other than defaults for Mask and Variance, so we
234// don't bother figuring out what suffixes to use for them for now. If we change that, we just need
235// to add more explicit specializations of this template.
236template <typename ImagePixelT, typename MaskPixelT = image::MaskPixel,
237 typename VariancePixelT = image::VariancePixel>
238struct ComputeSuffix;
239template <>
240struct ComputeSuffix<std::uint16_t> {
241 static std::string apply() { return "U"; }
242};
243template <>
244struct ComputeSuffix<float> {
245 static std::string apply() { return "F"; }
246};
247template <>
248struct ComputeSuffix<double> {
249 static std::string apply() { return "D"; }
250};
251template <>
252struct ComputeSuffix<int> {
253 static std::string apply() { return "I"; }
254};
255
256} // namespace
257
258template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
260 return "HeavyFootprint" + ComputeSuffix<ImagePixelT, MaskPixelT, VariancePixelT>::apply();
261}
262
263template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
265 HeavyFootprintPersistenceHelper<ImagePixelT, MaskPixelT, VariancePixelT> const& keys =
266 HeavyFootprintPersistenceHelper<ImagePixelT, MaskPixelT, VariancePixelT>::get();
267 // delegate to Footprint::write to handle spans and peaks
268 Footprint::write(handle);
269 // add one more catalog for pixel values
270 afw::table::BaseCatalog cat = handle.makeCatalog(keys.schema);
272 // We could deep-copy the arrays instead of const-casting them, which might be marginally safer,
273 // but we always save an OutputArchive to disk immediately after we create it, so there's really
274 // no chance that we could get the HeavyFootprint in trouble by having this view modified.
275 record->set(keys.image, ndarray::const_array_cast<ImagePixelT>(getImageArray()));
276 record->set(keys.mask, ndarray::const_array_cast<MaskPixelT>(getMaskArray()));
277 record->set(keys.variance, ndarray::const_array_cast<VariancePixelT>(getVarianceArray()));
278 handle.saveCatalog(cat);
279}
280
281template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
282class HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT>::Factory
284public:
285 explicit Factory(std::string const& name) : afw::table::io::PersistableFactory(name) {}
286
288 CatalogVector const& catalogs) const override {
289 HeavyFootprintPersistenceHelper<ImagePixelT, MaskPixelT, VariancePixelT> const& keys =
290 HeavyFootprintPersistenceHelper<ImagePixelT, MaskPixelT, VariancePixelT>::get();
291 HeavyFootprintPersistenceHelper<ImagePixelT, std::uint16_t, VariancePixelT> const& legacyKeys =
292 HeavyFootprintPersistenceHelper<ImagePixelT, std::uint16_t, VariancePixelT>::get();
293 LSST_ARCHIVE_ASSERT(catalogs.size() == 3u);
294
295 // Read in the SpanSet into a new Footprint object
296 std::shared_ptr<Footprint> loadedFootprint = readSpanSet(catalogs[0], archive);
297 // Now read in the PeakCatalog records
298 readPeaks(catalogs[1], *loadedFootprint);
299 afw::table::BaseRecord const& record = catalogs[2].front();
300
301 // Create the HeavyFootprint from the above Footprint
302 auto result =
303 std::make_shared<HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT>>(*loadedFootprint);
304 result->_image = ndarray::const_array_cast<ImagePixelT>(record.get(keys.image));
305
306 // Handle legacy Masks prior to change to int32
307 if (catalogs[2].getSchema() == legacyKeys.schema) {
308 auto legacyMask = ndarray::const_array_cast<std::uint16_t>(record.get(legacyKeys.mask));
309 result->_mask.deep() = legacyMask;
310 } else {
311 result->_mask = ndarray::const_array_cast<MaskPixelT>(record.get(keys.mask));
312 }
313 result->_variance = ndarray::const_array_cast<VariancePixelT>(record.get(keys.variance));
314 return result;
315 }
316
318};
319
320// initialize static instance, registering the factory with the persistence mechanism at the same time
321template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
324 "HeavyFootprint" + ComputeSuffix<ImagePixelT, MaskPixelT, VariancePixelT>::apply());
325} // namespace detection
326
327//
328// Explicit instantiations
329//
330//
331#define INSTANTIATE(TYPE) \
332 template std::shared_ptr<detection::HeavyFootprint<TYPE>> \
333 table::io::PersistableFacade<detection::HeavyFootprint<TYPE>>::dynamicCast( \
334 std::shared_ptr<table::io::Persistable> const&); \
335 template class detection::HeavyFootprint<TYPE>; \
336 template std::shared_ptr<detection::HeavyFootprint<TYPE>> detection::mergeHeavyFootprints<TYPE>( \
337 detection::HeavyFootprint<TYPE> const&, detection::HeavyFootprint<TYPE> const&);
338
340INSTANTIATE(double);
341INSTANTIATE(float);
342INSTANTIATE(int);
343} // namespace afw
344} // namespace lsst
py::object result
Definition: _schema.cc:429
table::Key< std::string > name
Definition: Amplifier.cc:116
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
double x
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:509
afw::table::Key< afw::table::Array< MaskPixelT > > mask
afw::table::Key< afw::table::Array< VariancePixelT > > variance
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
table::Schema schema
Definition: python.h:134
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:63
static std::unique_ptr< Footprint > readSpanSet(afw::table::BaseCatalog const &, afw::table::io::InputArchive const &)
Static method used to unpersist the SpanSet member of the Footprint class.
Definition: Footprint.cc:286
void write(OutputArchiveHandle &handle) const override
Write an instance of a Footprint to an output Archive.
Definition: Footprint.cc:271
lsst::geom::Box2I getBBox() const
Return the Footprint's bounding box.
Definition: Footprint.h:208
std::shared_ptr< geom::SpanSet > getSpans() const
Return a shared pointer to the SpanSet.
Definition: Footprint.h:115
static void readPeaks(afw::table::BaseCatalog const &, Footprint &)
Static method used to unpersist the PeakCatalog member of the Footprint class.
Definition: Footprint.cc:310
std::shared_ptr< afw::table::io::Persistable > read(InputArchive const &archive, CatalogVector const &catalogs) const override
Construct a new object from the given InputArchive and vector of catalogs.
A control object for HeavyFootprints.
Definition: FootprintCtrl.h:99
A set of pixels in an Image, including those pixels' actual values.
void write(OutputArchiveHandle &handle) const override
Write an instance of a Footprint to an output Archive.
double dot(HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > const &other) const
Dot product between HeavyFootprints.
ndarray::Array< ImagePixelT, 1, 1 > getImageArray()
HeavyFootprint()=default
Default constructor for HeavyFootprint.
void insert(lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage) const
Replace all the pixels in the image with the values in the HeavyFootprint.
std::string getPersistenceName() const override
Return the name correspoinging ot the persistence type.
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:51
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:74
lsst::geom::Point2I getXY0() const
Return the image's origin.
Definition: MaskedImage.h:1083
VariancePtr getVariance() const
Return a (shared_ptr to) the MaskedImage's variance.
Definition: MaskedImage.h:1052
MaskPtr getMask() const
Return a (shared_ptr to) the MaskedImage's mask.
Definition: MaskedImage.h:1031
ImagePtr getImage() const
Return a (shared_ptr to) the MaskedImage's image.
Definition: MaskedImage.h:1019
Base class for all records.
Definition: BaseRecord.h:31
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition: Catalog.h:490
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:31
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
A base class for factory classes used to reconstruct objects from records.
Definition: Persistable.h:228
An integer coordinate rectangle.
Definition: Box.h:55
T front(T... args)
T max(T... args)
T min(T... args)
std::shared_ptr< HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > mergeHeavyFootprints(HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > const &h1, HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > const &h2)
Sum the two given HeavyFootprints h1 and h2, returning a HeavyFootprint with the union footprint,...
std::shared_ptr< Footprint > mergeFootprints(Footprint const &footprint1, Footprint const &footprint2)
Merges two Footprints – appends their peaks, and unions their spans, returning a new Footprint.
Definition: Footprint.cc:341
float VariancePixel
default type for MaskedImage variance images
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
details::ImageNdGetter< T, inA, inB > ndImage(ndarray::Array< T, inA, inB > const &array, lsst::geom::Point2I xy0=lsst::geom::Point2I())
Marks a ndarray to be interpreted as an image when applying a functor from a SpanSet.
details::FlatNdGetter< T, inA, inB > ndFlat(ndarray::Array< T, inA, inB > const &array)
Marks a ndarray to be interpreted as a 1D vector when applying a functor from a SpanSet.
STL namespace.
T size(T... args)
ImageT val
Definition: CR.cc:146