LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
SpanSet.h
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008-2016 AURA/LSST.
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 <https://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 #ifndef LSST_AFW_GEOM_SPANSET_H
26 #define LSST_AFW_GEOM_SPANSET_H
27 
28 #include <vector>
29 #include <algorithm>
30 #include <functional>
31 #include <memory>
32 #include <utility>
33 #include "lsst/pex/exceptions.h"
34 #include "lsst/afw/geom/Span.h"
35 #include "lsst/geom/Box.h"
36 #include "lsst/afw/image/Mask.h"
42 #include "lsst/afw/image/Image.h"
44 
45 namespace lsst {
46 namespace afw {
47 namespace geom {
48 namespace details {
49 
50 /* Functor object to be used with fromMask function
51  */
52 template <typename T>
54 public:
55  bool operator()(T pixelValue) { return pixelValue != 0; }
56 };
57 
58 } // namespace details
59 
66 enum class Stencil { CIRCLE, BOX, MANHATTAN };
67 
77 class SpanSet : public afw::table::io::PersistableFacade<lsst::afw::geom::SpanSet>,
79 public:
82  typedef Span value_type;
83  typedef value_type const &const_reference;
84 
85  // Expose properties of the underlying vector containing spans such that the
86  // SpanSet can be considered a container.
87  // Return the constant versions as SpanSets should be immutable
88  const_iterator begin() const { return _spanVector.cbegin(); }
89  const_iterator end() const { return _spanVector.cend(); }
90  const_iterator cbegin() const { return _spanVector.cbegin(); }
91  const_iterator cend() const { return _spanVector.cend(); }
92  const_reference front() const { return const_cast<geom::Span &>(_spanVector.front()); }
93  const_reference back() const { return const_cast<geom::Span &>(_spanVector.back()); }
94  size_type size() const { return _spanVector.size(); }
95  bool empty() const { return _spanVector.empty(); }
96 
101  SpanSet();
102 
107  explicit SpanSet(lsst::geom::Box2I const &box);
108 
122  template <typename iter>
123  SpanSet(iter begin, iter end, bool normalize = true) : _spanVector(begin, end) {
124  // Return a null SpanSet if spanVector is 0
125  if (_spanVector.size() == 0) {
126  _bbox = lsst::geom::Box2I();
127  _area = 0;
128  } else {
129  if (normalize) {
130  _runNormalize();
131  }
132  _initialize();
133  }
134  }
135 
147  explicit SpanSet(std::vector<Span> const &vec, bool normalize = true);
148 
160  explicit SpanSet(std::vector<Span> &&vec, bool normalize = true);
161 
162  // Explicitly delete copy and move constructors
163  SpanSet(SpanSet const &other) = delete;
164  SpanSet(SpanSet &&other) = delete;
165  ~SpanSet() override = default;
166 
167  SpanSet &operator=(SpanSet const &) = default;
168  // Delegate to copy-assignment for backwards compatibility
169  SpanSet &operator=(SpanSet &&other) { return *this = other; }
170 
171  // Define class methods
174  size_type getArea() const;
175 
178  lsst::geom::Box2I getBBox() const;
179 
187  bool isContiguous() const;
188 
194  std::shared_ptr<SpanSet> shiftedBy(int x, int y) const;
195 
200  std::shared_ptr<SpanSet> shiftedBy(lsst::geom::Extent2I const &offset) const;
201 
206  std::shared_ptr<SpanSet> clippedTo(lsst::geom::Box2I const &box) const;
207 
212  std::shared_ptr<SpanSet> transformedBy(lsst::geom::LinearTransform const &t) const;
213 
218  std::shared_ptr<SpanSet> transformedBy(lsst::geom::AffineTransform const &t) const;
219 
224  std::shared_ptr<SpanSet> transformedBy(TransformPoint2ToPoint2 const &t) const;
225 
230  bool overlaps(SpanSet const &other) const;
231 
236  bool contains(SpanSet const &other) const;
237 
242  bool contains(lsst::geom::Point2I const &point) const;
243 
246  lsst::geom::Point2D computeCentroid() const;
247 
250  ellipses::Quadrupole computeShape() const;
251 
260  std::shared_ptr<SpanSet> dilated(int r, Stencil s = Stencil::CIRCLE) const;
261 
268  std::shared_ptr<SpanSet> dilated(SpanSet const &other) const;
269 
278  std::shared_ptr<SpanSet> eroded(int r, Stencil s = Stencil::CIRCLE) const;
279 
286  std::shared_ptr<SpanSet> eroded(SpanSet const &other) const;
287 
302  template <typename Pixel, int inN, int inC>
304  ndarray::Array<Pixel, inN, inC> const &input,
305  lsst::geom::Point2I const &xy0 = lsst::geom::Point2I()) const {
306  // Populate a lower dimensional array with the values from input taken at the points of SpanSet
307  auto outputShape = ndarray::concatenate(ndarray::makeVector(getArea()),
308  input.getShape().template last<inN - 2>());
309  ndarray::Array<typename std::remove_const<Pixel>::type, inN - 1, inN - 1> outputArray =
310  ndarray::allocate(outputShape);
311  outputArray.deep() = 0;
312  flatten(outputArray, input, xy0);
313  return outputArray;
314  }
315 
335  template <typename PixelIn, typename PixelOut, int inA, int outC, int inC>
336  void flatten(ndarray::Array<PixelOut, inA - 1, outC> const &output,
337  ndarray::Array<PixelIn, inA, inC> const &input,
338  lsst::geom::Point2I const &xy0 = lsst::geom::Point2I()) const {
339  auto ndAssigner = [](lsst::geom::Point2I const &point,
340  typename details::FlatNdGetter<PixelOut, inA - 1, outC>::Reference out,
341  typename details::ImageNdGetter<PixelIn, inA, inC>::Reference in) { out = in; };
342  // Populate array output with values from input at positions given by SpanSet
343  applyFunctor(ndAssigner, ndarray::ndFlat(output), ndarray::ndImage(input, xy0));
344  }
345 
359  template <typename Pixel, int inA, int inC>
361  ndarray::Array<Pixel, inA, inC> const &input) const {
362  // Create a higher dimensional array the size of the bounding box and extra dimensions of input.
363  // Populate values from input, placed at locations corresponding to SpanSet, offset by the
364  // lower corner of the bounding box
365  auto existingShape = input.getShape();
366  typename decltype(existingShape)::Element height = _bbox.getHeight();
367  typename decltype(existingShape)::Element width = _bbox.getWidth();
368  auto outputShape = ndarray::concatenate(ndarray::makeVector(height, width),
369  input.getShape().template last<inA - 1>());
370  ndarray::Array<typename std::remove_const<Pixel>::type, inA + 1, inA + 1> outputArray =
371  ndarray::allocate(outputShape);
372  outputArray.deep() = 0;
373  unflatten(outputArray, input, lsst::geom::Point2I(_bbox.getMinX(), _bbox.getMinY()));
374  return outputArray;
375  }
376 
396  template <typename PixelIn, typename PixelOut, int inA, int outC, int inC>
397  void unflatten(ndarray::Array<PixelOut, inA + 1, outC> const &output,
398  ndarray::Array<PixelIn, inA, inC> const &input,
399  lsst::geom::Point2I const &xy0 = lsst::geom::Point2I()) const {
400  // Populate 2D ndarray output with values from input, at locations defined by SpanSet, optionally
401  // offset by xy0
402  auto ndAssigner = [](lsst::geom::Point2I const &point,
404  typename details::FlatNdGetter<PixelIn, inA, inC>::Reference in) { out = in; };
405  applyFunctor(ndAssigner, ndarray::ndImage(output, xy0), ndarray::ndFlat(input));
406  }
407 
415  template <typename ImageT>
417  auto copyFunc = [](lsst::geom::Point2I const &point, ImageT const &srcPix, ImageT &destPix) {
418  destPix = srcPix;
419  };
420  applyFunctor(copyFunc, src, dest);
421  }
422 
432  template <typename ImageT, typename MaskT, typename VarT>
435  auto copyFunc = [](lsst::geom::Point2I const &point, ImageT const &srcPix, MaskT const &srcMask,
436  VarT const &srcVar, ImageT &destPix, MaskT &destMask, VarT &destVar) {
437  destPix = srcPix;
438  destMask = srcMask;
439  destVar = srcVar;
440  };
441  applyFunctor(copyFunc, *(src.getImage()), *(src.getMask()), *(src.getVariance()), *(dest.getImage()),
442  *(dest.getMask()), *(dest.getVariance()));
443  }
444 
458  template <typename ImageT>
459  void setImage(image::Image<ImageT> &image, ImageT val,
460  lsst::geom::Box2I const &region = lsst::geom::Box2I(), bool doClip = false) const;
461 
507  template <typename Functor, typename... Args>
508  // Normally std::forward would be used with a universal reference, however
509  // this function does not use one because without std::forward the
510  // compiler is forced to keep any r-value references alive for the
511  // duration of the function call
512  void applyFunctor(Functor &&func, Args &&... args) const {
513  /* Use a variadic template to take a functor object, and an arbitrary number
514  of parameters. For each of the arguments, construct a Getter class using
515  a function (makeGetter) which is overloaded to all the types applyFunctorImpl
516  supports: Images, MaskedImages, Exposures, ndarrays, numeric values, and
517  iterators. The functor and the getters are then passed to the implementation of
518  applyFunctor where the values of the input arguments are intelligently
519  generated at each point in SpanSet, and passed to the functor object for evaluation.
520  */
521  applyFunctorImpl(func, details::makeGetter(args)...);
522  }
523 
531  template <typename T>
532  void setMask(lsst::afw::image::Mask<T> &target, T bitmask) const;
533 
541  template <typename T>
542  void clearMask(lsst::afw::image::Mask<T> &target, T bitmask) const;
543 
544  // SpanSet functions
549  std::shared_ptr<SpanSet> intersect(SpanSet const &other) const;
550 
558  template <typename T>
559  std::shared_ptr<SpanSet> intersect(image::Mask<T> const &other, T bitmask) const;
560 
566  std::shared_ptr<SpanSet> intersectNot(SpanSet const &other) const;
567 
576  template <typename T>
577  std::shared_ptr<SpanSet> intersectNot(image::Mask<T> const &other, T bitmask) const;
578 
583  std::shared_ptr<SpanSet> union_(SpanSet const &other) const;
584 
592  template <typename T>
593  std::shared_ptr<SpanSet> union_(image::Mask<T> const &other, T bitmask) const;
594 
595  // Comparison Operators
596 
601  bool operator==(SpanSet const &other) const;
602 
603  /* Compute inequality between two SpanSets
604  *
605  * @param other The SpanSet for which inequality will be computed
606  */
607  bool operator!=(SpanSet const &other) const;
608 
618  static std::shared_ptr<geom::SpanSet> fromShape(int r, Stencil s = Stencil::CIRCLE,
620 
626 
643  template <typename T, typename UnaryPredicate = details::AnyBitSetFunctor<T>>
645  image::Mask<T> const &mask, UnaryPredicate comparator = details::AnyBitSetFunctor<T>()) {
646  // Create a vector which will hold all the spans created from the mask
647  std::vector<Span> tempVec;
648  // Grab some variables that will be used in the loop, so that they do not need to be fetched
649  // every iteration.
650  auto const maskArray = mask.getArray();
651  auto const minPoint = mask.getBBox().getMin();
652  auto const dimensions = maskArray.getShape();
653  auto const minY = minPoint.getY();
654  auto const minX = minPoint.getX();
655  auto const dimMinusOne = dimensions[1] - 1;
656  auto const yDim = dimensions[0];
657  auto const xDim = dimensions[1];
658  auto arrIter = maskArray.begin();
659  for (size_t y = 0; y < yDim; ++y) {
660  auto yWithOffset = y + minY;
661  bool inSpan = false; // are we currently in a span of interest?
662  std::size_t start; // starting x value of span we're currently in
663  for (size_t x = 0; x < xDim; ++x) {
664  bool compareValue = comparator((*arrIter)[x]);
665  if (inSpan) {
666  // If we were in a span but now the condition isn't satisfied, it means the Span stops
667  // at the previous pixel.
668  if (!compareValue) {
669  tempVec.push_back(Span(yWithOffset, start + minX, x - 1 + minX));
670  inSpan = false;
671  }
672  } else if (compareValue) {
673  // If we weren't in a span but now the condition is satisfied, we start a new span.
674  inSpan = true;
675  start = x;
676  }
677  }
678  // Since the x loop is over, if we're still in a span, this means the Span was not
679  // closed out and added to the vector. The last pixel should be included in the Span
680  // and the Span should be closed and added to the vector of spans.
681  if (inSpan) {
682  tempVec.push_back(Span(yWithOffset, start + minX, dimMinusOne + minX));
683  }
684  ++arrIter;
685  }
686 
687  // construct a SpanSet from the spans determined above
688  return std::make_shared<SpanSet>(std::move(tempVec), false);
689  }
690 
700  template <typename T>
702  return fromMask(mask, [bitmask](T const &bitPattern) { return bitPattern & bitmask; });
703  }
704 
708 
709  bool isPersistable() const noexcept override { return true; }
710 
715  std::shared_ptr<geom::SpanSet> findEdgePixels() const;
716 
717 private:
718  /* Returns the name used by the persistence layer to identify the SpanSet class
719  */
720  std::string getPersistenceName() const override;
721 
722  /* Return a string corresponding to the python module that SpanSets lives in
723  */
724  inline std::string getPythonModule() const override { return "lsst.afw.geom"; }
725 
726  /* Writes the representation of the class out to an output archive
727  */
728  void write(OutputArchiveHandle &handle) const override;
729 
730  /* A class which is used by the persistence layer to restore SpanSets from an archive
731  */
732  friend class SpansSetFactory;
733 
734  /* A function to combine overlapping Spans in a SpanSet into a single Span
735  */
736  void _runNormalize();
737 
738  /* Initializes the SpanSet class. Contains code that is common to multiple constructors
739  */
740  void _initialize();
741 
742  /* Label Spans according to contiguous group. If the SpanSet is contiguous, all Spans will be labeled 1.
743  * If there is more than one group each group will receive a label one higher than the previous.
744  */
745  void _label(geom::Span const &spn, std::vector<std::size_t> &labelVector, std::size_t currentLabel,
747  std::pair<std::vector<std::size_t>, std::size_t> _makeLabels() const;
748 
749  std::shared_ptr<SpanSet> makeShift(int x, int y) const;
750 
751  template <typename F, typename... T>
752  void applyFunctorImpl(F &&f, T... args) const {
753  /* Implementation for applying functors, loop over each of the spans, and then
754  * each point. Use the get method in the getters to fetch the value and pass
755  * the point, and the values to the functor
756  */
757  // make sure that the SpanSet is within the bounds of functor arguments
758  details::variadicBoundChecker(_bbox, _area, args...);
759  for (auto const &spn : _spanVector) {
760  // Set the current span in the getter, useful for optimizing value lookups
762  for (int x = spn.getX0(); x <= spn.getX1(); ++x) {
763  lsst::geom::Point2I point(x, spn.getY());
764  f(point, args.get()...);
766  }
767  }
768  }
769 
770  // Vector to hold the Spans contained in the SpanSet
771  std::vector<Span> _spanVector;
772 
773  // Box that is large enough to bound all pixels in the SpanSet
774  lsst::geom::Box2I _bbox;
775 
776  // Number of pixels in the SpanSet
777  std::size_t _area;
778 };
779 } // namespace geom
780 } // namespace afw
781 } // namespace lsst
782 
783 #endif // LSST_AFW_GEOM_SPANSET_H
An ellipse core with quadrupole moments as parameters.
Definition: Quadrupole.h:47
def write(self, patchRef, catalog)
Write the output.
VariancePtr getVariance() const
Return a (shared_ptr to) the MaskedImage&#39;s variance.
Definition: MaskedImage.h:1090
void variadicSpanSetter(Span const spn, T &x)
void unflatten(ndarray::Array< PixelOut, inA+1, outC > const &output, ndarray::Array< PixelIn, inA, inC > const &input, lsst::geom::Point2I const &xy0=lsst::geom::Point2I()) const
Expand an array by one spatial dimension at points given by SpanSet.
Definition: SpanSet.h:397
Stencil
An enumeration class which describes the shapes.
Definition: SpanSet.h:66
Key< Flag > const & target
size_type size() const
Definition: SpanSet.h:94
afw::table::Key< afw::table::Array< MaskPixelT > > mask
const_iterator end() const
Definition: SpanSet.h:89
An object passed to Persistable::write to allow it to persist itself.
An affine coordinate transformation consisting of a linear transformation and an offset.
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, UnaryPredicate comparator=details::AnyBitSetFunctor< T >())
Create a SpanSet from a mask.
Definition: SpanSet.h:644
A compact representation of a collection of pixels.
Definition: SpanSet.h:77
A range of pixels within one row of an Image.
Definition: Span.h:47
void applyFunctor(Functor &&func, Args &&... args) const
Apply functor on individual elements from the supplied parameters.
Definition: SpanSet.h:512
int y
Definition: SpanSet.cc:49
typename ndarray::Array< T, N, C >::Reference::Reference Reference
const_iterator cbegin() const
Definition: SpanSet.h:90
ImageT val
Definition: CR.cc:146
typename ndarray::Array< T, inA, inC >::Reference Reference
const_iterator begin() const
Definition: SpanSet.h:88
ItemVariant const * other
Definition: Schema.cc:56
void copyImage(image::Image< ImageT > const &src, image::Image< ImageT > &dest)
Copy contents of source Image into destination image at the positions defined in the SpanSet...
Definition: SpanSet.h:416
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, T bitmask)
Create a SpanSet from a mask.
Definition: SpanSet.h:701
ImagePtr getImage() const
Return a (shared_ptr to) the MaskedImage&#39;s image.
Definition: MaskedImage.h:1057
STL class.
A base class for objects that can be persisted via afw::table::io Archive classes.
Definition: Persistable.h:74
void copyMaskedImage(image::MaskedImage< ImageT, MaskT, VarT > const &src, image::MaskedImage< ImageT, MaskT, VarT > &dest)
Copy contents of source MaskedImage into destination image at the positions defined in the SpanSet...
Definition: SpanSet.h:433
Point2I const getMin() const noexcept
Definition: Box.h:156
value_type const & const_reference
Definition: SpanSet.h:83
T push_back(T... args)
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:49
const_iterator cend() const
Definition: SpanSet.h:91
A base class for image defects.
table::Key< int > type
Definition: Detector.cc:163
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition: ImageBase.h:482
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
std::shared_ptr< RecordT > src
Definition: Match.cc:48
An ellipse defined by an arbitrary BaseCore and a center point.
Definition: Ellipse.h:51
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:73
void variadicBoundChecker(lsst::geom::Box2I const box, int area, T const &x)
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.
FlatNdGetter< T, inA, inC > makeGetter(FlatNdGetter< T, inA, inC > &getter)
bool empty() const
Definition: SpanSet.h:95
const_reference front() const
Definition: SpanSet.h:92
SpanSet(iter begin, iter end, bool normalize=true)
Construct a SpanSet from an iterator.
Definition: SpanSet.h:123
T move(T... args)
double x
SpanSet & operator=(SpanSet &&other)
Definition: SpanSet.h:169
MaskPtr getMask() const
Return a (shared_ptr to) the MaskedImage&#39;s mask.
Definition: MaskedImage.h:1069
bool isPersistable() const noexcept override
Return true if this particular object can be persisted using afw::table::io.
Definition: SpanSet.h:709
STL class.
std::vector< Span >::const_iterator const_iterator
Definition: SpanSet.h:80
std::vector< Span >::size_type size_type
Definition: SpanSet.h:81
ndarray::Array< typename std::remove_const< Pixel >::type, inN - 1, inN - 1 > flatten(ndarray::Array< Pixel, inN, inC > const &input, lsst::geom::Point2I const &xy0=lsst::geom::Point2I()) const
Reduce the pixel dimensionality from 2 to 1 of an array at points given by SpanSet.
Definition: SpanSet.h:303
ndarray::Array< typename std::remove_const< Pixel >::type, inA+1, inA+1 > unflatten(ndarray::Array< Pixel, inA, inC > const &input) const
Expand an array by one spatial dimension at points given by SpanSet.
Definition: SpanSet.h:360
const_reference back() const
Definition: SpanSet.h:93
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
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.
A CRTP facade class for subclasses of Persistable.
Definition: Persistable.h:176
An integer coordinate rectangle.
Definition: Box.h:55
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:58
int end
A 2D linear coordinate transformation.
Transform LSST spatial data, such as lsst::geom::Point2D and lsst::geom::SpherePoint, using an AST mapping.
Definition: Transform.h:67
void flatten(ndarray::Array< PixelOut, inA - 1, outC > const &output, ndarray::Array< PixelIn, inA, inC > const &input, lsst::geom::Point2I const &xy0=lsst::geom::Point2I()) const
Reduce the pixel dimensionality from 2 to 1 of an array at points given by SpanSet.
Definition: SpanSet.h:336