LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
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
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) &
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) &
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",
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) {
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) &
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::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
206void declareSpanSet(lsst::utils::python::WrapperCollection &wrappers) {
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
336void 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)
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
void setImage(image::Image< ImageT > &image, ImageT val, lsst::geom::Box2I const &region=lsst::geom::Box2I(), bool doClip=false) const
Set the values of an Image at points defined by the SpanSet.
Definition: SpanSet.cc:904
std::shared_ptr< SpanSet > union_(SpanSet const &other) const
Create a new SpanSet that contains all points from two SpanSets.
Definition: SpanSet.cc:826
std::shared_ptr< SpanSet > intersect(SpanSet const &other) const
Determine the common points between two SpanSets, and create a new SpanSet.
Definition: SpanSet.cc:720
void setMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Set a Mask at pixels defined by the SpanSet.
Definition: SpanSet.cc:927
std::vector< std::shared_ptr< geom::SpanSet > > split() const
Split a discontinuous SpanSet into multiple SpanSets which are contiguous.
Definition: SpanSet.cc:382
void clearMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Unset a Mask at pixels defined by the SpanSet.
Definition: SpanSet.cc:938
std::shared_ptr< geom::SpanSet > findEdgePixels() const
Select pixels within the SpanSet which touch its edge.
Definition: SpanSet.cc:411
std::shared_ptr< SpanSet > intersectNot(SpanSet const &other) const
Determine the common points between a SpanSet and the logical inverse of a second SpanSet and return ...
Definition: SpanSet.cc:745
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.