LSSTApplications  20.0.0
LSSTDataManagementBasePackage
spanSet.cc
Go to the documentation of this file.
1 
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2016 AURA/LSST.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <https://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #include "pybind11/pybind11.h"
25 #include "pybind11/stl.h"
26 
27 #include <cstdint>
28 #include <sstream>
29 #include <string>
30 #include <iostream>
31 
32 #include "ndarray/pybind11.h"
33 
35 #include "lsst/afw/geom/SpanSet.h"
36 #include "lsst/afw/table/io/python.h" // for addPersistableMethods
37 
38 namespace py = pybind11;
39 using namespace pybind11::literals;
40 
41 namespace lsst {
42 namespace afw {
43 namespace geom {
44 
45 namespace {
46 
47 using PySpanSet = py::class_<SpanSet, std::shared_ptr<SpanSet>>;
48 
49 template <typename Pixel, typename PyClass>
50 void declareFlattenMethod(PyClass &cls) {
51  cls.def("flatten",
52  (ndarray::Array<Pixel, 1, 1>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &,
53  lsst::geom::Point2I const &) const) &
54  SpanSet::flatten<Pixel, 2, 0>,
55  "input"_a, "xy0"_a = lsst::geom::Point2I());
56  cls.def("flatten",
57  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &,
58  lsst::geom::Point2I const &) const) &
59  SpanSet::flatten<Pixel, 3, 0>,
60  "input"_a, "xy0"_a = lsst::geom::Point2I());
61  cls.def("flatten",
62  (void (SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
63  lsst::geom::Point2I const &) const) &
64  SpanSet::flatten<Pixel, Pixel, 2, 0, 0>,
65  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
66  cls.def("flatten",
67  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 3, 0> const &,
68  lsst::geom::Point2I const &) const) &
69  SpanSet::flatten<Pixel, Pixel, 3, 0, 0>,
70  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
71 }
72 
73 template <typename Pixel, typename PyClass>
74 void declareUnflattenMethod(PyClass &cls) {
75  cls.def("unflatten",
76  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &input) const) &
77  SpanSet::unflatten<Pixel, 1, 0>);
78  cls.def("unflatten",
79  (ndarray::Array<Pixel, 3, 3>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &input) const) &
80  SpanSet::unflatten<Pixel, 2, 0>);
81  cls.def("unflatten",
82  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 1, 0> const &,
83  lsst::geom::Point2I const &) const) &
84  SpanSet::unflatten<Pixel, Pixel, 1, 0, 0>,
85  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
86  cls.def("unflatten",
87  (void (SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
88  lsst::geom::Point2I const &) const) &
89  SpanSet::unflatten<Pixel, Pixel, 2, 0, 0>,
90  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
91 }
92 
93 template <typename Pixel, typename PyClass>
94 void declareSetMaskMethod(PyClass &cls) {
95  cls.def("setMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::setMask);
96 }
97 
98 template <typename Pixel, typename PyClass>
99 void declareClearMaskMethod(PyClass &cls) {
100  cls.def("clearMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::clearMask);
101 }
102 
103 template <typename Pixel, typename PyClass>
104 void declareIntersectMethod(PyClass &cls) {
105  cls.def("intersect",
106  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
107  SpanSet::intersect,
108  "other"_a, "bitmask"_a);
109  // Default to compare any bit set
110  cls.def("intersect",
111  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
112  auto tempSpanSet = SpanSet::fromMask(mask);
113  return self.intersect(*tempSpanSet);
114  },
115  "other"_a);
116 }
117 
118 template <typename Pixel, typename PyClass>
119 void declareIntersectNotMethod(PyClass &cls) {
120  cls.def("intersectNot",
121  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
122  SpanSet::intersectNot,
123  "other"_a, "bitmask"_a);
124  // Default to compare any bit set
125  cls.def("intersectNot",
126  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
127  auto tempSpanSet = SpanSet::fromMask(mask);
128  return self.intersectNot(*tempSpanSet);
129  },
130  "other"_a);
131 }
132 
133 template <typename Pixel, typename PyClass>
134 void declareUnionMethod(PyClass &cls) {
135  cls.def("union",
136  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) & SpanSet::union_,
137  "other"_a, "bitmask"_a);
138  // Default to compare any bit set
139  cls.def("union",
140  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
141  auto tempSpanSet = SpanSet::fromMask(mask);
142  return self.union_(*tempSpanSet);
143  },
144  "other"_a);
145 }
146 
147 template <typename ImageT, typename PyClass>
148 void declareCopyImage(PyClass &cls) {
149  cls.def("copyImage", &SpanSet::copyImage<ImageT>);
150 }
151 
152 template <typename ImageT, typename PyClass>
153 void declareCopyMaskedImage(PyClass &cls) {
154  using MaskPixel = image::MaskPixel;
156  cls.def("copyMaskedImage", &SpanSet::copyMaskedImage<ImageT, MaskPixel, VariancePixel>);
157 }
158 
159 template <typename ImageT, typename PyClass>
160 void declareSetImage(PyClass &cls) {
161  cls.def("setImage",
162  (void (SpanSet::*)(image::Image<ImageT> &, ImageT, lsst::geom::Box2I const &, bool) const) &
163  SpanSet::setImage,
164  "image"_a, "val"_a, "region"_a = lsst::geom::Box2I(), "doClip"_a = false);
165 }
166 
167 template <typename MaskPixel, typename PyClass>
168 void declarefromMask(PyClass &cls) {
169  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask) { return SpanSet::fromMask(mask); });
170  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask, MaskPixel const &bitmask) {
171  return SpanSet::fromMask(mask, bitmask);
172  });
173 }
174 
175 template <typename Pixel, typename PyClass>
176 void declareMaskMethods(PyClass &cls) {
177  declareSetMaskMethod<Pixel>(cls);
178  declareClearMaskMethod<Pixel>(cls);
179  declareIntersectMethod<Pixel>(cls);
180  declareIntersectNotMethod<Pixel>(cls);
181  declareUnionMethod<Pixel>(cls);
182 }
183 
184 template <typename Pixel, typename PyClass>
185 void declareImageTypes(PyClass &cls) {
186  declareFlattenMethod<Pixel>(cls);
187  declareUnflattenMethod<Pixel>(cls);
188  declareCopyImage<Pixel>(cls);
189  declareCopyMaskedImage<Pixel>(cls);
190  declareSetImage<Pixel>(cls);
191 }
192 
193 } // end anonymous namespace
194 
195 PYBIND11_MODULE(spanSet, mod) {
196  using MaskPixel = image::MaskPixel;
197 
198  py::module::import("lsst.geom");
199  py::module::import("lsst.afw.geom.span");
200 
201  py::enum_<Stencil>(mod, "Stencil")
202  .value("CIRCLE", Stencil::CIRCLE)
203  .value("BOX", Stencil::BOX)
204  .value("MANHATTAN", Stencil::MANHATTAN);
205 
206  PySpanSet cls(mod, "SpanSet");
207 
208  /* SpanSet Constructors */
209  cls.def(py::init<>());
210  cls.def(py::init<lsst::geom::Box2I>(), "box"_a);
211  cls.def(py::init<std::vector<Span>, bool>(), "spans"_a, "normalize"_a = true);
212 
213  table::io::python::addPersistableMethods<SpanSet>(cls);
214 
215  /* SpanSet Methods */
216  cls.def("getArea", &SpanSet::getArea);
217  cls.def("getBBox", &SpanSet::getBBox);
218  cls.def("isContiguous", &SpanSet::isContiguous);
219  cls.def("shiftedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(int, int) const) & SpanSet::shiftedBy);
220  cls.def("shiftedBy",
221  (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::Extent2I const &) const) & SpanSet::shiftedBy);
222  cls.def("clippedTo", &SpanSet::clippedTo);
223  cls.def("transformedBy",
225  SpanSet::transformedBy);
226  cls.def("transformedBy",
228  SpanSet::transformedBy);
229  cls.def("transformedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(TransformPoint2ToPoint2 const &) const) &
230  SpanSet::transformedBy);
231  cls.def("overlaps", &SpanSet::overlaps);
232  cls.def("contains", (bool (SpanSet::*)(SpanSet const &) const) & SpanSet::contains);
233  cls.def("contains", (bool (SpanSet::*)(lsst::geom::Point2I const &) const) & SpanSet::contains);
234  cls.def("computeCentroid", &SpanSet::computeCentroid);
235  cls.def("computeShape", &SpanSet::computeShape);
236  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::dilated,
237  "radius"_a, "stencil"_a = Stencil::CIRCLE);
238  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::dilated);
239  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::eroded,
240  "radius"_a, "stencil"_a = Stencil::CIRCLE);
241  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::eroded);
242  cls.def("intersect", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersect);
243  cls.def("intersectNot",
244  (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersectNot);
245  cls.def("union", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::union_);
246  cls.def_static("fromShape",
247  (std::shared_ptr<SpanSet>(*)(int, Stencil, lsst::geom::Point2I)) & SpanSet::fromShape,
248  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = lsst::geom::Point2I());
249  cls.def_static("fromShape",
250  [](int r, Stencil s, std::pair<int, int> point) {
251  return SpanSet::fromShape(r, s, lsst::geom::Point2I(point.first, point.second));
252  },
253  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = std::pair<int, int>(0, 0));
254  cls.def_static("fromShape",
255  (std::shared_ptr<SpanSet>(*)(geom::ellipses::Ellipse const &)) & SpanSet::fromShape);
256  cls.def("split", &SpanSet::split);
257  cls.def("findEdgePixels", &SpanSet::findEdgePixels);
258  cls.def("indices", [](SpanSet const &self) -> std::pair<std::vector<int>, std::vector<int>> {
259  std::vector<int> yind;
260  std::vector<int> xind;
261  yind.reserve(self.getArea());
262  xind.reserve(self.getArea());
263  for (auto const &span : self) {
264  auto y = span.getY();
265  for (int x = span.getX0(); x <= span.getX1(); ++x) {
266  yind.push_back(y);
267  xind.push_back(x);
268  }
269  }
270  return std::make_pair(yind, xind);
271  });
272 
273  /* SpanSet Operators */
274  cls.def("__eq__", [](SpanSet const &self, SpanSet const &other) -> bool { return self == other; },
275  py::is_operator());
276  cls.def("__ne__", [](SpanSet const &self, SpanSet const &other) -> bool { return self != other; },
277  py::is_operator());
278  cls.def("__iter__", [](SpanSet &self) { return py::make_iterator(self.begin(), self.end()); },
279  py::keep_alive<0, 1>());
280  cls.def("__len__", [](SpanSet const &self) -> decltype(self.size()) { return self.size(); });
281  cls.def("__contains__", [](SpanSet &self, SpanSet const &other) -> bool { return self.contains(other); });
282  cls.def("__contains__",
283  [](SpanSet &self, lsst::geom::Point2I &other) -> bool { return self.contains(other); });
284  cls.def("__repr__", [](SpanSet const &self) -> std::string {
286  image::Mask<MaskPixel> tempMask(self.getBBox());
287  self.setMask(tempMask, static_cast<MaskPixel>(1));
288  auto array = tempMask.getArray();
289  auto dims = array.getShape();
290  for (std::size_t i = 0; i < dims[0]; ++i) {
291  os << "[";
292  for (std::size_t j = 0; j < dims[1]; ++j) {
293  os << array[i][j];
294  if (j != dims[1] - 1) {
295  os << ", ";
296  }
297  }
298  os << "]" << std::endl;
299  }
300  return os.str();
301  });
302  cls.def("__str__", [](SpanSet const &self) -> std::string {
304  for (auto const &span : self) {
305  os << span.getY() << ": " << span.getMinX() << ".." << span.getMaxX() << std::endl;
306  }
307  return os.str();
308  });
309  // Instantiate all the templates
310 
311  declareMaskMethods<MaskPixel>(cls);
312 
313  declareImageTypes<std::uint16_t>(cls);
314  declareImageTypes<std::uint64_t>(cls);
315  declareImageTypes<int>(cls);
316  declareImageTypes<float>(cls);
317  declareImageTypes<double>(cls);
318 
319  // Extra instantiation for flatten unflatten methods
320  declareFlattenMethod<long>(cls);
321  declareUnflattenMethod<long>(cls);
322 
323  declarefromMask<MaskPixel>(cls);
324 }
325 } // namespace geom
326 } // namespace afw
327 } // namespace lsst
y
int y
Definition: SpanSet.cc:49
std::string
STL class.
std::shared_ptr
STL class.
lsst::afw::image::Mask
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
lsst::afw::geom::Transform
Transform LSST spatial data, such as lsst::geom::Point2D and lsst::geom::SpherePoint,...
Definition: Transform.h:68
std::pair< int, int >
std::vector::reserve
T reserve(T... args)
lsst::meas::modelfit::Pixel
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
lsst::afw::geom::PYBIND11_MODULE
PYBIND11_MODULE(spanSet, mod)
Definition: spanSet.cc:195
std::vector
STL class.
lsst::geom::LinearTransform
A 2D linear coordinate transformation.
Definition: LinearTransform.h:69
lsst::afw
Definition: imageAlgorithm.dox:1
Quadrupole.h
mask
afw::table::Key< afw::table::Array< MaskPixelT > > mask
Definition: HeavyFootprint.cc:217
end
int end
Definition: BoundedField.cc:105
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
std::vector::push_back
T push_back(T... args)
lsst::geom::AffineTransform
An affine coordinate transformation consisting of a linear transformation and an offset.
Definition: AffineTransform.h:75
lsst::afw::geom::SpanSet
A compact representation of a collection of pixels.
Definition: SpanSet.h:78
astshim.fitsChanContinued.contains
def contains(self, name)
Definition: fitsChanContinued.py:127
x
double x
Definition: ChebyshevBoundedField.cc:277
other
ItemVariant const * other
Definition: Schema.cc:56
lsst::afw::image::VariancePixel
float VariancePixel
default type for MaskedImage variance images
Definition: LsstImageTypes.h:35
PyClass
py::class_< ProductBoundedField, std::shared_ptr< ProductBoundedField >, BoundedField > PyClass
Definition: productBoundedField.cc:32
lsst::afw::image::ImageBase< lsst::afw::image::MaskPixel >::getArray
Array getArray()
Definition: ImageBase.h:513
lsst::afw::image::MaskPixel
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
Definition: LsstImageTypes.h:34
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
SpanSet.h
lsst::afw::geom::ellipses::Ellipse
An ellipse defined by an arbitrary BaseCore and a center point.
Definition: Ellipse.h:51
std::ostringstream
STL class.
lsst::geom
Definition: geomOperators.dox:4
os
std::ostream * os
Definition: Schema.cc:746
std::endl
T endl(T... args)
python.h
lsst::geom::Point< int, 2 >
lsst::geom::Box2I
An integer coordinate rectangle.
Definition: Box.h:55
pybind11
Definition: _GenericMap.cc:40
std::size_t
std::make_pair
T make_pair(T... args)
lsst::afw::image::Image< ImageT >
lsst::utils.tests.init
def init()
Definition: tests.py:58
lsst::geom::Extent< int, 2 >
lsst::afw::geom::Stencil
Stencil
An enumeration class which describes the shapes.
Definition: SpanSet.h:66