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
_spanSet.cc
Go to the documentation of this file.
1 /*
2  * This file is part of afw.
3  *
4  * Developed for the LSST Data Management System.
5  * This product includes software developed by the LSST Project
6  * (https://www.lsst.org).
7  * See the COPYRIGHT file at the top-level directory of this distribution
8  * for details of code ownership.
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 GNU General Public License
21  * along with this program. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include "pybind11/pybind11.h"
25 #include <lsst/utils/python.h>
26 #include "pybind11/stl.h"
27 
28 #include <cstdint>
29 #include <sstream>
30 #include <string>
31 #include <iostream>
32 
33 #include "ndarray/pybind11.h"
34 #include "ndarray/Array.h"
35 
37 #include "lsst/afw/geom/SpanSet.h"
38 #include "lsst/afw/table/io/python.h" // for addPersistableMethods
39 
40 namespace py = pybind11;
41 using namespace pybind11::literals;
42 
43 namespace lsst {
44 namespace afw {
45 namespace geom {
46 
47 namespace {
48 
49 using PySpanSet = py::class_<SpanSet, std::shared_ptr<SpanSet>>;
50 
51 template <typename Pixel, typename PyClass>
52 void declareFlattenMethod(PyClass &cls) {
53  cls.def("flatten",
54  (ndarray::Array<Pixel, 1, 1>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &,
55  lsst::geom::Point2I const &) const) &
56  SpanSet::flatten<Pixel, 2, 0>,
57  "input"_a, "xy0"_a = lsst::geom::Point2I());
58  cls.def("flatten",
59  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &,
60  lsst::geom::Point2I const &) const) &
61  SpanSet::flatten<Pixel, 3, 0>,
62  "input"_a, "xy0"_a = lsst::geom::Point2I());
63  cls.def("flatten",
64  (void (SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
65  lsst::geom::Point2I const &) const) &
66  SpanSet::flatten<Pixel, Pixel, 2, 0, 0>,
67  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
68  cls.def("flatten",
69  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 3, 0> const &,
70  lsst::geom::Point2I const &) const) &
71  SpanSet::flatten<Pixel, Pixel, 3, 0, 0>,
72  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
73 }
74 
75 template <typename Pixel, typename PyClass>
76 void declareUnflattenMethod(PyClass &cls) {
77  cls.def("unflatten",
78  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &input) const) &
79  SpanSet::unflatten<Pixel, 1, 0>);
80  cls.def("unflatten",
81  (ndarray::Array<Pixel, 3, 3>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &input) const) &
82  SpanSet::unflatten<Pixel, 2, 0>);
83  cls.def("unflatten",
84  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 1, 0> const &,
85  lsst::geom::Point2I const &) const) &
86  SpanSet::unflatten<Pixel, Pixel, 1, 0, 0>,
87  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
88  cls.def("unflatten",
89  (void (SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
90  lsst::geom::Point2I const &) const) &
91  SpanSet::unflatten<Pixel, Pixel, 2, 0, 0>,
92  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
93 }
94 
95 template <typename Pixel, typename PyClass>
96 void declareSetMaskMethod(PyClass &cls) {
97  cls.def("setMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::setMask);
98 }
99 
100 template <typename Pixel, typename PyClass>
101 void declareClearMaskMethod(PyClass &cls) {
102  cls.def("clearMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::clearMask);
103 }
104 
105 template <typename Pixel, typename PyClass>
106 void declareIntersectMethod(PyClass &cls) {
107  cls.def("intersect",
108  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
109  SpanSet::intersect,
110  "other"_a, "bitmask"_a);
111  // Default to compare any bit set
112  cls.def(
113  "intersect",
114  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
115  auto tempSpanSet = SpanSet::fromMask(mask);
116  return self.intersect(*tempSpanSet);
117  },
118  "other"_a);
119 }
120 
121 template <typename Pixel, typename PyClass>
122 void declareIntersectNotMethod(PyClass &cls) {
123  cls.def("intersectNot",
124  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
125  SpanSet::intersectNot,
126  "other"_a, "bitmask"_a);
127  // Default to compare any bit set
128  cls.def(
129  "intersectNot",
130  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
131  auto tempSpanSet = SpanSet::fromMask(mask);
132  return self.intersectNot(*tempSpanSet);
133  },
134  "other"_a);
135 }
136 
137 template <typename Pixel, typename PyClass>
138 void declareUnionMethod(PyClass &cls) {
139  cls.def("union",
140  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) & SpanSet::union_,
141  "other"_a, "bitmask"_a);
142  // Default to compare any bit set
143  cls.def(
144  "union",
145  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
146  auto tempSpanSet = SpanSet::fromMask(mask);
147  return self.union_(*tempSpanSet);
148  },
149  "other"_a);
150 }
151 
152 template <typename ImageT, typename PyClass>
153 void declareCopyImage(PyClass &cls) {
154  cls.def("copyImage", &SpanSet::copyImage<ImageT>);
155 }
156 
157 template <typename ImageT, typename PyClass>
158 void declareCopyMaskedImage(PyClass &cls) {
159  using MaskPixel = image::MaskPixel;
161  cls.def("copyMaskedImage", &SpanSet::copyMaskedImage<ImageT, MaskPixel, VariancePixel>);
162 }
163 
164 template <typename ImageT, typename PyClass>
165 void declareSetImage(PyClass &cls) {
166  cls.def("setImage",
167  (void (SpanSet::*)(image::Image<ImageT> &, ImageT, lsst::geom::Box2I const &, bool) const) &
168  SpanSet::setImage,
169  "image"_a, "val"_a, "region"_a = lsst::geom::Box2I(), "doClip"_a = false);
170 }
171 
172 template <typename MaskPixel, typename PyClass>
173 void declarefromMask(PyClass &cls) {
174  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask) { return SpanSet::fromMask(mask); });
175  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask, MaskPixel const &bitmask) {
176  return SpanSet::fromMask(mask, bitmask);
177  });
178 }
179 
180 template <typename Pixel, typename PyClass>
181 void declareMaskMethods(PyClass &cls) {
182  declareSetMaskMethod<Pixel>(cls);
183  declareClearMaskMethod<Pixel>(cls);
184  declareIntersectMethod<Pixel>(cls);
185  declareIntersectNotMethod<Pixel>(cls);
186  declareUnionMethod<Pixel>(cls);
187 }
188 
189 template <typename Pixel, typename PyClass>
190 void declareImageTypes(PyClass &cls) {
191  declareFlattenMethod<Pixel>(cls);
192  declareUnflattenMethod<Pixel>(cls);
193  declareCopyImage<Pixel>(cls);
194  declareCopyMaskedImage<Pixel>(cls);
195  declareSetImage<Pixel>(cls);
196 }
197 
198 void declareStencil(lsst::utils::python::WrapperCollection &wrappers) {
199  wrappers.wrapType(py::enum_<Stencil>(wrappers.module, "Stencil"), [](auto &mod, auto &enm) {
200  enm.value("CIRCLE", Stencil::CIRCLE);
201  enm.value("BOX", Stencil::BOX);
202  enm.value("MANHATTAN", Stencil::MANHATTAN);
203  });
204 }
205 
206 void declareSpanSet(lsst::utils::python::WrapperCollection &wrappers) {
207  using MaskPixel = image::MaskPixel;
208 
209  wrappers.wrapType(PySpanSet(wrappers.module, "SpanSet"), [](auto &mod, auto &cls) {
210  /* SpanSet Constructors */
211  cls.def(py::init<>());
212  cls.def(py::init<lsst::geom::Box2I>(), "box"_a);
213  cls.def(py::init<std::vector<Span>, bool>(), "spans"_a, "normalize"_a = true);
214 
215  table::io::python::addPersistableMethods<SpanSet>(cls);
216 
217  /* SpanSet Methods */
218  cls.def("getArea", &SpanSet::getArea);
219  cls.def("getBBox", &SpanSet::getBBox);
220  cls.def("isContiguous", &SpanSet::isContiguous);
221  cls.def("shiftedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(int, int) const) & SpanSet::shiftedBy);
222  cls.def("shiftedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::Extent2I const &) const) &
223  SpanSet::shiftedBy);
224  cls.def("clippedTo", &SpanSet::clippedTo);
225  cls.def("transformedBy",
226  (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::LinearTransform const &) const) &
227  SpanSet::transformedBy);
228  cls.def("transformedBy",
229  (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::AffineTransform const &) const) &
230  SpanSet::transformedBy);
231  cls.def("transformedBy",
232  (std::shared_ptr<SpanSet>(SpanSet::*)(TransformPoint2ToPoint2 const &) const) &
233  SpanSet::transformedBy);
234  cls.def("overlaps", &SpanSet::overlaps);
235  cls.def("contains", (bool (SpanSet::*)(SpanSet const &) const) & SpanSet::contains);
236  cls.def("contains", (bool (SpanSet::*)(lsst::geom::Point2I const &) const) & SpanSet::contains);
237  cls.def("computeCentroid", &SpanSet::computeCentroid);
238  cls.def("computeShape", &SpanSet::computeShape);
239  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::dilated,
240  "radius"_a, "stencil"_a = Stencil::CIRCLE);
241  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::dilated);
242  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::eroded,
243  "radius"_a, "stencil"_a = Stencil::CIRCLE);
244  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::eroded);
245  cls.def("intersect",
246  (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersect);
247  cls.def("intersectNot",
248  (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersectNot);
249  cls.def("union", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::union_);
250  cls.def_static("fromShape",
251  (std::shared_ptr<SpanSet>(*)(int, Stencil, lsst::geom::Point2I)) & SpanSet::fromShape,
252  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = lsst::geom::Point2I());
253  cls.def_static(
254  "fromShape",
255  [](int r, Stencil s, std::pair<int, int> point) {
256  return SpanSet::fromShape(r, s, lsst::geom::Point2I(point.first, point.second));
257  },
258  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = std::pair<int, int>(0, 0));
259  cls.def_static("fromShape",
260  (std::shared_ptr<SpanSet>(*)(geom::ellipses::Ellipse const &)) & SpanSet::fromShape);
261  cls.def("split", &SpanSet::split);
262  cls.def("findEdgePixels", &SpanSet::findEdgePixels);
263  cls.def("indices", [](SpanSet const &self) -> ndarray::Array<int, 2, 2> {
264  unsigned long dims = 2;
265  ndarray::Array<int, 2, 2> inds = ndarray::allocate(ndarray::makeVector(dims, self.getArea()));
266  int element = 0;
267  for (auto const &span : self) {
268  auto y = span.getY();
269  for (int x = span.getX0(); x <= span.getX1(); ++x) {
270  inds[0][element] = y;
271  inds[1][element] = x;
272  element++;
273  }
274  }
275  return inds;
276  });
277 
278  /* SpanSet Operators */
279  cls.def(
280  "__eq__", [](SpanSet const &self, SpanSet const &other) -> bool { return self == other; },
281  py::is_operator());
282  cls.def(
283  "__ne__", [](SpanSet const &self, SpanSet const &other) -> bool { return self != other; },
284  py::is_operator());
285  cls.def(
286  "__iter__", [](SpanSet &self) { return py::make_iterator(self.begin(), self.end()); },
287  py::keep_alive<0, 1>());
288  cls.def("__len__", [](SpanSet const &self) -> decltype(self.size()) { return self.size(); });
289  cls.def("__contains__",
290  [](SpanSet &self, SpanSet const &other) -> bool { return self.contains(other); });
291  cls.def("__contains__",
292  [](SpanSet &self, lsst::geom::Point2I &other) -> bool { return self.contains(other); });
293  cls.def("__repr__", [](SpanSet const &self) -> std::string {
295  image::Mask<MaskPixel> tempMask(self.getBBox());
296  self.setMask(tempMask, static_cast<MaskPixel>(1));
297  auto array = tempMask.getArray();
298  auto dims = array.getShape();
299  for (std::size_t i = 0; i < dims[0]; ++i) {
300  os << "[";
301  for (std::size_t j = 0; j < dims[1]; ++j) {
302  os << array[i][j];
303  if (j != dims[1] - 1) {
304  os << ", ";
305  }
306  }
307  os << "]" << std::endl;
308  }
309  return os.str();
310  });
311  cls.def("__str__", [](SpanSet const &self) -> std::string {
313  for (auto const &span : self) {
314  os << span.getY() << ": " << span.getMinX() << ".." << span.getMaxX() << std::endl;
315  }
316  return os.str();
317  });
318  // Instantiate all the templates
319 
320  declareMaskMethods<MaskPixel>(cls);
321 
322  declareImageTypes<std::uint16_t>(cls);
323  declareImageTypes<std::uint64_t>(cls);
324  declareImageTypes<int>(cls);
325  declareImageTypes<float>(cls);
326  declareImageTypes<double>(cls);
327 
328  // Extra instantiation for flatten unflatten methods
329  declareFlattenMethod<long>(cls);
330  declareUnflattenMethod<long>(cls);
331 
332  declarefromMask<MaskPixel>(cls);
333  });
334 }
335 } // end anonymous namespace
336 void wrapSpanSet(lsst::utils::python::WrapperCollection &wrappers) {
337  wrappers.addSignatureDependency("lsst.afw.table.io");
338  wrappers.addSignatureDependency("lsst.afw.geom.ellipses");
339  declareStencil(wrappers);
340  declareSpanSet(wrappers);
341 }
342 } // namespace geom
343 } // namespace afw
344 } // namespace lsst
double element[2]
Definition: BaseTable.cc:90
int end
double x
afw::table::Key< afw::table::Array< MaskPixelT > > mask
std::ostream * os
Definition: Schema.cc:557
int y
Definition: SpanSet.cc:48
T begin(T... args)
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:51
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
An integer coordinate rectangle.
Definition: Box.h:55
T endl(T... args)
void wrapSpanSet(lsst::utils::python::WrapperCollection &)
Definition: _spanSet.cc:336
float VariancePixel
default type for MaskedImage variance images
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
py::class_< PixelAreaBoundedField, std::shared_ptr< PixelAreaBoundedField >, BoundedField > PyClass
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
A base class for image defects.