LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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 
37 namespace lsst {
38 namespace afw {
39 namespace detection {
40 namespace {
41 
42 template <typename T>
43 struct 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 
51 private:
52  T _val;
53 };
54 
55 template <>
56 struct 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 
65 private:
66  T _mask;
67 };
68 } // namespace
69 
70 template <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 
106 template <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 
114 template <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 
122 template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
124  getSpans()->unflatten(image.getArray(), _image, image.getXY0());
125 }
126 
127 template <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 
150 template <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 
204 namespace {
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.
208 template <typename ImagePixelT, typename MaskPixelT = image::MaskPixel,
209  typename VariancePixelT = image::VariancePixel>
210 struct 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 
221 private:
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.
236 template <typename ImagePixelT, typename MaskPixelT = image::MaskPixel,
237  typename VariancePixelT = image::VariancePixel>
238 struct ComputeSuffix;
239 template <>
240 struct ComputeSuffix<std::uint16_t> {
241  static std::string apply() { return "U"; }
242 };
243 template <>
244 struct ComputeSuffix<float> {
245  static std::string apply() { return "F"; }
246 };
247 template <>
248 struct ComputeSuffix<double> {
249  static std::string apply() { return "D"; }
250 };
251 template <>
252 struct ComputeSuffix<int> {
253  static std::string apply() { return "I"; }
254 };
255 
256 } // namespace
257 
258 template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
260  return "HeavyFootprint" + ComputeSuffix<ImagePixelT, MaskPixelT, VariancePixelT>::apply();
261 }
262 
263 template <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 
281 template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
282 class HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT>::Factory
284 public:
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
321 template <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 
340 INSTANTIATE(double);
341 INSTANTIATE(float);
342 INSTANTIATE(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
afw::table::Key< afw::table::Array< ImagePixelT > > image
afw::table::Schema schema
afw::table::Key< afw::table::Array< MaskPixelT > > mask
afw::table::Key< afw::table::Array< VariancePixelT > > variance
#define INSTANTIATE(TYPE)
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition: Persistable.h:48
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:272
void write(OutputArchiveHandle &handle) const override
Write an instance of a Footprint to an output Archive.
Definition: Footprint.cc:257
std::shared_ptr< geom::SpanSet > getSpans() const
Return a shared pointer to the SpanSet.
Definition: Footprint.h:115
lsst::geom::Box2I getBBox() const
Return the Footprint's bounding box.
Definition: Footprint.h:208
static void readPeaks(afw::table::BaseCatalog const &, Footprint &)
Static method used to unpersist the PeakCatalog member of the Footprint class.
Definition: Footprint.cc:296
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.
HeavyFootprint()=default
Default constructor for HeavyFootprint.
ndarray::Array< ImagePixelT, 1, 1 > getImageArray()
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:73
lsst::geom::Point2I getXY0() const
Return the image's origin.
Definition: MaskedImage.h:1082
VariancePtr getVariance() const
Return a (shared_ptr to) the MaskedImage's variance.
Definition: MaskedImage.h:1051
MaskPtr getMask() const
Return a (shared_ptr to) the MaskedImage's mask.
Definition: MaskedImage.h:1030
ImagePtr getImage() const
Return a (shared_ptr to) the MaskedImage's image.
Definition: MaskedImage.h:1018
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:327
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
float VariancePixel
default type for MaskedImage variance images
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
FastFinder::Iterator Iterator
Definition: FastFinder.cc:178
A base class for image defects.
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.
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.
STL namespace.
T size(T... args)
ImageT val
Definition: CR.cc:146