LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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 
36 #include "lsst/afw/geom/SpanSet.h"
37 #include "lsst/afw/table/io/python.h" // for addPersistableMethods
38 
39 namespace py = pybind11;
40 using namespace pybind11::literals;
41 
42 namespace lsst {
43 namespace afw {
44 namespace geom {
45 
46 namespace {
47 
48 using PySpanSet = py::class_<SpanSet, std::shared_ptr<SpanSet>>;
49 
50 template <typename Pixel, typename PyClass>
51 void declareFlattenMethod(PyClass &cls) {
52  cls.def("flatten",
53  (ndarray::Array<Pixel, 1, 1>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &,
54  lsst::geom::Point2I const &) const) &
55  SpanSet::flatten<Pixel, 2, 0>,
56  "input"_a, "xy0"_a = lsst::geom::Point2I());
57  cls.def("flatten",
58  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &,
59  lsst::geom::Point2I const &) const) &
60  SpanSet::flatten<Pixel, 3, 0>,
61  "input"_a, "xy0"_a = lsst::geom::Point2I());
62  cls.def("flatten",
63  (void (SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
64  lsst::geom::Point2I const &) const) &
65  SpanSet::flatten<Pixel, Pixel, 2, 0, 0>,
66  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
67  cls.def("flatten",
68  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 3, 0> const &,
69  lsst::geom::Point2I const &) const) &
70  SpanSet::flatten<Pixel, Pixel, 3, 0, 0>,
71  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
72 }
73 
74 template <typename Pixel, typename PyClass>
75 void declareUnflattenMethod(PyClass &cls) {
76  cls.def("unflatten",
77  (ndarray::Array<Pixel, 2, 2>(SpanSet::*)(ndarray::Array<Pixel, 1, 0> const &input) const) &
78  SpanSet::unflatten<Pixel, 1, 0>);
79  cls.def("unflatten",
80  (ndarray::Array<Pixel, 3, 3>(SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &input) const) &
81  SpanSet::unflatten<Pixel, 2, 0>);
82  cls.def("unflatten",
83  (void (SpanSet::*)(ndarray::Array<Pixel, 2, 0> const &, ndarray::Array<Pixel, 1, 0> const &,
84  lsst::geom::Point2I const &) const) &
85  SpanSet::unflatten<Pixel, Pixel, 1, 0, 0>,
86  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
87  cls.def("unflatten",
88  (void (SpanSet::*)(ndarray::Array<Pixel, 3, 0> const &, ndarray::Array<Pixel, 2, 0> const &,
89  lsst::geom::Point2I const &) const) &
90  SpanSet::unflatten<Pixel, Pixel, 2, 0, 0>,
91  "output"_a, "input"_a, "xy0"_a = lsst::geom::Point2I());
92 }
93 
94 template <typename Pixel, typename PyClass>
95 void declareSetMaskMethod(PyClass &cls) {
96  cls.def("setMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::setMask);
97 }
98 
99 template <typename Pixel, typename PyClass>
100 void declareClearMaskMethod(PyClass &cls) {
101  cls.def("clearMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::clearMask);
102 }
103 
104 template <typename Pixel, typename PyClass>
105 void declareIntersectMethod(PyClass &cls) {
106  cls.def("intersect",
107  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
108  SpanSet::intersect,
109  "other"_a, "bitmask"_a);
110  // Default to compare any bit set
111  cls.def(
112  "intersect",
113  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
114  auto tempSpanSet = SpanSet::fromMask(mask);
115  return self.intersect(*tempSpanSet);
116  },
117  "other"_a);
118 }
119 
120 template <typename Pixel, typename PyClass>
121 void declareIntersectNotMethod(PyClass &cls) {
122  cls.def("intersectNot",
123  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) &
124  SpanSet::intersectNot,
125  "other"_a, "bitmask"_a);
126  // Default to compare any bit set
127  cls.def(
128  "intersectNot",
129  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
130  auto tempSpanSet = SpanSet::fromMask(mask);
131  return self.intersectNot(*tempSpanSet);
132  },
133  "other"_a);
134 }
135 
136 template <typename Pixel, typename PyClass>
137 void declareUnionMethod(PyClass &cls) {
138  cls.def("union",
139  (std::shared_ptr<SpanSet>(SpanSet::*)(image::Mask<Pixel> const &, Pixel) const) & SpanSet::union_,
140  "other"_a, "bitmask"_a);
141  // Default to compare any bit set
142  cls.def(
143  "union",
144  [](SpanSet const &self, image::Mask<Pixel> const &mask) {
145  auto tempSpanSet = SpanSet::fromMask(mask);
146  return self.union_(*tempSpanSet);
147  },
148  "other"_a);
149 }
150 
151 template <typename ImageT, typename PyClass>
152 void declareCopyImage(PyClass &cls) {
153  cls.def("copyImage", &SpanSet::copyImage<ImageT>);
154 }
155 
156 template <typename ImageT, typename PyClass>
157 void declareCopyMaskedImage(PyClass &cls) {
158  using MaskPixel = image::MaskPixel;
160  cls.def("copyMaskedImage", &SpanSet::copyMaskedImage<ImageT, MaskPixel, VariancePixel>);
161 }
162 
163 template <typename ImageT, typename PyClass>
164 void declareSetImage(PyClass &cls) {
165  cls.def("setImage",
166  (void (SpanSet::*)(image::Image<ImageT> &, ImageT, lsst::geom::Box2I const &, bool) const) &
167  SpanSet::setImage,
168  "image"_a, "val"_a, "region"_a = lsst::geom::Box2I(), "doClip"_a = false);
169 }
170 
171 template <typename MaskPixel, typename PyClass>
172 void declarefromMask(PyClass &cls) {
173  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask) { return SpanSet::fromMask(mask); });
174  cls.def_static("fromMask", [](image::Mask<MaskPixel> mask, MaskPixel const &bitmask) {
175  return SpanSet::fromMask(mask, bitmask);
176  });
177 }
178 
179 template <typename Pixel, typename PyClass>
180 void declareMaskMethods(PyClass &cls) {
181  declareSetMaskMethod<Pixel>(cls);
182  declareClearMaskMethod<Pixel>(cls);
183  declareIntersectMethod<Pixel>(cls);
184  declareIntersectNotMethod<Pixel>(cls);
185  declareUnionMethod<Pixel>(cls);
186 }
187 
188 template <typename Pixel, typename PyClass>
189 void declareImageTypes(PyClass &cls) {
190  declareFlattenMethod<Pixel>(cls);
191  declareUnflattenMethod<Pixel>(cls);
192  declareCopyImage<Pixel>(cls);
193  declareCopyMaskedImage<Pixel>(cls);
194  declareSetImage<Pixel>(cls);
195 }
196 
197 void declareStencil(lsst::utils::python::WrapperCollection &wrappers) {
198  wrappers.wrapType(py::enum_<Stencil>(wrappers.module, "Stencil"), [](auto &mod, auto &enm) {
199  enm.value("CIRCLE", Stencil::CIRCLE);
200  enm.value("BOX", Stencil::BOX);
201  enm.value("MANHATTAN", Stencil::MANHATTAN);
202  });
203 }
204 
205 void declareSpanSet(lsst::utils::python::WrapperCollection &wrappers) {
206  using MaskPixel = image::MaskPixel;
207 
208  wrappers.wrapType(PySpanSet(wrappers.module, "SpanSet"), [](auto &mod, auto &cls) {
209  /* SpanSet Constructors */
210  cls.def(py::init<>());
211  cls.def(py::init<lsst::geom::Box2I>(), "box"_a);
212  cls.def(py::init<std::vector<Span>, bool>(), "spans"_a, "normalize"_a = true);
213 
214  table::io::python::addPersistableMethods<SpanSet>(cls);
215 
216  /* SpanSet Methods */
217  cls.def("getArea", &SpanSet::getArea);
218  cls.def("getBBox", &SpanSet::getBBox);
219  cls.def("isContiguous", &SpanSet::isContiguous);
220  cls.def("shiftedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(int, int) const) & SpanSet::shiftedBy);
221  cls.def("shiftedBy", (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::Extent2I const &) const) &
222  SpanSet::shiftedBy);
223  cls.def("clippedTo", &SpanSet::clippedTo);
224  cls.def("transformedBy",
225  (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::LinearTransform const &) const) &
226  SpanSet::transformedBy);
227  cls.def("transformedBy",
228  (std::shared_ptr<SpanSet>(SpanSet::*)(lsst::geom::AffineTransform const &) const) &
229  SpanSet::transformedBy);
230  cls.def("transformedBy",
231  (std::shared_ptr<SpanSet>(SpanSet::*)(TransformPoint2ToPoint2 const &) const) &
232  SpanSet::transformedBy);
233  cls.def("overlaps", &SpanSet::overlaps);
234  cls.def("contains", (bool (SpanSet::*)(SpanSet const &) const) & SpanSet::contains);
235  cls.def("contains", (bool (SpanSet::*)(lsst::geom::Point2I const &) const) & SpanSet::contains);
236  cls.def("computeCentroid", &SpanSet::computeCentroid);
237  cls.def("computeShape", &SpanSet::computeShape);
238  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::dilated,
239  "radius"_a, "stencil"_a = Stencil::CIRCLE);
240  cls.def("dilated", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::dilated);
241  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(int, Stencil) const) & SpanSet::eroded,
242  "radius"_a, "stencil"_a = Stencil::CIRCLE);
243  cls.def("eroded", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::eroded);
244  cls.def("intersect",
245  (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersect);
246  cls.def("intersectNot",
247  (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::intersectNot);
248  cls.def("union", (std::shared_ptr<SpanSet>(SpanSet::*)(SpanSet const &) const) & SpanSet::union_);
249  cls.def_static("fromShape",
250  (std::shared_ptr<SpanSet>(*)(int, Stencil, lsst::geom::Point2I)) & SpanSet::fromShape,
251  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = lsst::geom::Point2I());
252  cls.def_static(
253  "fromShape",
254  [](int r, Stencil s, std::pair<int, int> point) {
255  return SpanSet::fromShape(r, s, lsst::geom::Point2I(point.first, point.second));
256  },
257  "radius"_a, "stencil"_a = Stencil::CIRCLE, "offset"_a = std::pair<int, int>(0, 0));
258  cls.def_static("fromShape",
259  (std::shared_ptr<SpanSet>(*)(geom::ellipses::Ellipse const &)) & SpanSet::fromShape);
260  cls.def("split", &SpanSet::split);
261  cls.def("findEdgePixels", &SpanSet::findEdgePixels);
262  cls.def("indices", [](SpanSet const &self) -> std::pair<std::vector<int>, std::vector<int>> {
263  std::vector<int> yind;
264  std::vector<int> xind;
265  yind.reserve(self.getArea());
266  xind.reserve(self.getArea());
267  for (auto const &span : self) {
268  auto y = span.getY();
269  for (int x = span.getX0(); x <= span.getX1(); ++x) {
270  yind.push_back(y);
271  xind.push_back(x);
272  }
273  }
274  return std::make_pair(yind, xind);
275  });
276 
277  /* SpanSet Operators */
278  cls.def(
279  "__eq__", [](SpanSet const &self, SpanSet const &other) -> bool { return self == other; },
280  py::is_operator());
281  cls.def(
282  "__ne__", [](SpanSet const &self, SpanSet const &other) -> bool { return self != other; },
283  py::is_operator());
284  cls.def(
285  "__iter__", [](SpanSet &self) { return py::make_iterator(self.begin(), self.end()); },
286  py::keep_alive<0, 1>());
287  cls.def("__len__", [](SpanSet const &self) -> decltype(self.size()) { return self.size(); });
288  cls.def("__contains__",
289  [](SpanSet &self, SpanSet const &other) -> bool { return self.contains(other); });
290  cls.def("__contains__",
291  [](SpanSet &self, lsst::geom::Point2I &other) -> bool { return self.contains(other); });
292  cls.def("__repr__", [](SpanSet const &self) -> std::string {
294  image::Mask<MaskPixel> tempMask(self.getBBox());
295  self.setMask(tempMask, static_cast<MaskPixel>(1));
296  auto array = tempMask.getArray();
297  auto dims = array.getShape();
298  for (std::size_t i = 0; i < dims[0]; ++i) {
299  os << "[";
300  for (std::size_t j = 0; j < dims[1]; ++j) {
301  os << array[i][j];
302  if (j != dims[1] - 1) {
303  os << ", ";
304  }
305  }
306  os << "]" << std::endl;
307  }
308  return os.str();
309  });
310  cls.def("__str__", [](SpanSet const &self) -> std::string {
312  for (auto const &span : self) {
313  os << span.getY() << ": " << span.getMinX() << ".." << span.getMaxX() << std::endl;
314  }
315  return os.str();
316  });
317  // Instantiate all the templates
318 
319  declareMaskMethods<MaskPixel>(cls);
320 
321  declareImageTypes<std::uint16_t>(cls);
322  declareImageTypes<std::uint64_t>(cls);
323  declareImageTypes<int>(cls);
324  declareImageTypes<float>(cls);
325  declareImageTypes<double>(cls);
326 
327  // Extra instantiation for flatten unflatten methods
328  declareFlattenMethod<long>(cls);
329  declareUnflattenMethod<long>(cls);
330 
331  declarefromMask<MaskPixel>(cls);
332  });
333 }
334 } // end anonymous namespace
335 void wrapSpanSet(lsst::utils::python::WrapperCollection &wrappers) {
336  wrappers.addSignatureDependency("lsst.afw.table.io");
337  wrappers.addSignatureDependency("lsst.afw.geom.ellipses");
338  declareStencil(wrappers);
339  declareSpanSet(wrappers);
340 }
341 } // namespace geom
342 } // namespace afw
343 } // namespace lsst
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)
T make_pair(T... args)
void wrapSpanSet(lsst::utils::python::WrapperCollection &)
Definition: _spanSet.cc:335
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.
T reserve(T... args)