LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
_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"
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
38#include "lsst/afw/table/io/python.h" // for addPersistableMethods
39
40namespace py = pybind11;
41using namespace pybind11::literals;
42
43namespace lsst {
44namespace afw {
45namespace geom {
46
47namespace {
48
49using PySpanSet = py::class_<SpanSet, std::shared_ptr<SpanSet>>;
50
51template <typename Pixel, typename PyClass>
52void 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
75template <typename Pixel, typename PyClass>
76void 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
95template <typename Pixel, typename PyClass>
96void declareSetMaskMethod(PyClass &cls) {
97 cls.def("setMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::setMask);
98}
99
100template <typename Pixel, typename PyClass>
101void declareClearMaskMethod(PyClass &cls) {
102 cls.def("clearMask", (void (SpanSet::*)(image::Mask<Pixel> &, Pixel) const) & SpanSet::clearMask);
103}
104
105template <typename Pixel, typename PyClass>
106void 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
121template <typename Pixel, typename PyClass>
122void 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
137template <typename Pixel, typename PyClass>
138void 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
152template <typename ImageT, typename PyClass>
153void declareCopyImage(PyClass &cls) {
154 cls.def("copyImage", &SpanSet::copyImage<ImageT>);
155}
156
157template <typename ImageT, typename PyClass>
158void declareCopyMaskedImage(PyClass &cls) {
159 using MaskPixel = image::MaskPixel;
161 cls.def("copyMaskedImage", &SpanSet::copyMaskedImage<ImageT, MaskPixel, VariancePixel>);
162}
163
164template <typename ImageT, typename PyClass>
165void 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
172template <typename MaskPixel, typename PyClass>
173void 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
180template <typename Pixel, typename PyClass>
181void 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
189template <typename Pixel, typename PyClass>
190void 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
198void declareStencil(lsst::cpputils::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
206void declareSpanSet(lsst::cpputils::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
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
afw::table::Key< afw::table::Array< MaskPixelT > > mask
std::ostream * os
Definition Schema.cc:557
int y
Definition SpanSet.cc:48
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
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
Definition SpanSet.cc:688
std::vector< std::shared_ptr< geom::SpanSet > > split() const
Split a discontinuous SpanSet into multiple SpanSets which are contiguous.
Definition SpanSet.cc:382
std::shared_ptr< geom::SpanSet > findEdgePixels() const
Select pixels within the SpanSet which touch its edge.
Definition SpanSet.cc:411
Represent a 2-dimensional array of bitmask pixels.
Definition Mask.h:81
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition python.h:242
void addSignatureDependency(std::string const &name)
Indicate an external module that provides a type used in function/method signatures.
Definition python.h:357
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() i...
Definition python.h:391
T endl(T... args)
void wrapSpanSet(lsst::cpputils::python::WrapperCollection &)
Definition _spanSet.cc:336
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
float VariancePixel
default type for MaskedImage variance images
Point< int, 2 > Point2I
Definition Point.h:321
float Pixel
Typedefs to be used for pixel values.
Definition common.h:37
g2d::python::Image< double > Image
Definition test_image.cc:14
g2d::python::Image< bool > Mask
Definition test_image.cc:16