Loading [MathJax]/extensions/tex2jax.js
LSST Applications g04a91732dc+a3f7a6a005,g07dc498a13+5ab4d22ec3,g0fba68d861+870ee37b31,g1409bbee79+5ab4d22ec3,g1a7e361dbc+5ab4d22ec3,g1fd858c14a+11200c7927,g20f46db602+25d63fd678,g35bb328faa+fcb1d3bbc8,g4d2262a081+cc8af5cafb,g4d39ba7253+6b9d64fe03,g4e0f332c67+5d362be553,g53246c7159+fcb1d3bbc8,g60b5630c4e+6b9d64fe03,g78460c75b0+2f9a1b4bcd,g786e29fd12+cf7ec2a62a,g7b71ed6315+fcb1d3bbc8,g8048e755c2+a1301e4c20,g8852436030+a750987b4a,g89139ef638+5ab4d22ec3,g89e1512fd8+a86d53a4aa,g8d6b6b353c+6b9d64fe03,g9125e01d80+fcb1d3bbc8,g989de1cb63+5ab4d22ec3,g9f33ca652e+38ca901d1a,ga9baa6287d+6b9d64fe03,gaaedd4e678+5ab4d22ec3,gabe3b4be73+1e0a283bba,gb1101e3267+aa269f591c,gb58c049af0+f03b321e39,gb90eeb9370+af74afe682,gc741bbaa4f+7f5db660ea,gcf25f946ba+a750987b4a,gd315a588df+b78635c672,gd6cbbdb0b4+c8606af20c,gd9a9a58781+fcb1d3bbc8,gde0f65d7ad+5839af1903,ge278dab8ac+932305ba37,ge82c20c137+76d20ab76d,w.2025.11
LSST Data Management Base Package
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
_image.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 "pybind11/stl.h"
27#include "ndarray/pybind11.h"
28
31#include "lsst/afw/image/Mask.h"
32#include "lsst/afw/fits.h"
34
35namespace py = pybind11;
36using namespace pybind11::literals;
37
38namespace lsst {
39namespace afw {
40namespace image {
41
42namespace {
43
44template <typename PixelT>
45using PyImageBase = py::class_<ImageBase<PixelT>, std::shared_ptr<ImageBase<PixelT>>>;
46
47template <typename PixelT>
48using PyImage = py::class_<Image<PixelT>, std::shared_ptr<Image<PixelT>>, ImageBase<PixelT>>;
49
50template <typename PixelT>
51using PyDecoratedImage = py::class_<DecoratedImage<PixelT>, std::shared_ptr<DecoratedImage<PixelT>>>;
52
53template <typename MaskPixelT>
54using PyMask = py::class_<Mask<MaskPixelT>, std::shared_ptr<Mask<MaskPixelT>>, ImageBase<MaskPixelT>>;
55
64template <typename FromPixelT, typename ToPixelT>
65static void declareCastConstructor(PyImage<ToPixelT> &cls) {
66 cls.def(py::init<Image<FromPixelT> const &, bool const>(), "src"_a, "deep"_a);
67}
68
69template <typename PixelT>
70static void declareImageBase(lsst::cpputils::python::WrapperCollection &wrappers, std::string const &suffix) {
71 using Array = typename ImageBase<PixelT>::Array;
72 wrappers.wrapType(PyImageBase<PixelT>(wrappers.module, ("ImageBase" + suffix).c_str()), [](auto &mod,
73 auto &cls) {
74 cls.def(py::init<lsst::geom::Extent2I const &>(), "dimensions"_a = lsst::geom::Extent2I());
75 cls.def(py::init<ImageBase<PixelT> const &, bool>(), "src"_a, "deep"_a = false);
76 cls.def(py::init<ImageBase<PixelT> const &, lsst::geom::Box2I const &, ImageOrigin, bool>(), "src"_a,
77 "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
78 cls.def(py::init<Array const &, bool, lsst::geom::Point2I const &>(), "array"_a, "deep"_a = false,
79 "xy0"_a = lsst::geom::Point2I());
80
81 cls.def("assign", &ImageBase<PixelT>::assign, "rhs"_a, "bbox"_a = lsst::geom::Box2I(),
82 "origin"_a = PARENT,
83 py::is_operator()); // py::is_operator is a workaround for code in slicing.py
84 // that expects NotImplemented to be returned on failure.
85 cls.def("getWidth", &ImageBase<PixelT>::getWidth);
86 cls.def("getHeight", &ImageBase<PixelT>::getHeight);
87 cls.def("getX0", &ImageBase<PixelT>::getX0);
88 cls.def("getY0", &ImageBase<PixelT>::getY0);
89 cls.def("getXY0", &ImageBase<PixelT>::getXY0);
90 cls.def("positionToIndex", &ImageBase<PixelT>::positionToIndex, "position"_a, "xOrY"_a);
91 cls.def("indexToPosition", &ImageBase<PixelT>::indexToPosition, "index"_a, "xOrY"_a);
92 cls.def("getDimensions", &ImageBase<PixelT>::getDimensions);
93 cls.def("getArray", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray);
94 cls.def_property("array", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray,
95 [](ImageBase<PixelT> &self, ndarray::Array<PixelT const, 2, 0> const &array) {
96 if (array.isEmpty()) {
97 throw py::type_error("Image array may not be None.");
98 }
99 // Avoid self-assignment, which is invoked when a Python in-place operator is
100 // used.
101 if (array.shallow() != self.getArray().shallow()) {
102 self.getArray().deep() = array;
103 }
104 });
105 cls.def("setXY0",
107 "xy0"_a);
108 cls.def("setXY0", (void (ImageBase<PixelT>::*)(int const, int const)) & ImageBase<PixelT>::setXY0,
109 "x0"_a, "y0"_a);
110 cls.def("getBBox", &ImageBase<PixelT>::getBBox, "origin"_a = PARENT);
111
112 cls.def("set", [](ImageBase<PixelT> &img, PixelT val) { img = val; });
113 cls.def(
114 "_set",
115 [](ImageBase<PixelT> &img, geom::Point2I const &index, PixelT val, ImageOrigin origin) {
116 python::checkBounds(index, img.getBBox(origin));
117 img.get(index, origin) = val;
118 },
119 "index"_a, "value"_a, "origin"_a);
120 cls.def(
121 "_get",
122 [](ImageBase<PixelT> &img, geom::Point2I const &index, ImageOrigin origin) {
123 python::checkBounds(index, img.getBBox(origin));
124 return img.get(index, origin);
125 },
126 "index"_a, "origin"_a);
127 });
128}
129
130template <typename MaskPixelT>
131static void declareMask(lsst::cpputils::python::WrapperCollection &wrappers, std::string const &suffix) {
132 wrappers.wrapType(PyMask<MaskPixelT>(wrappers.module, ("Mask" + suffix).c_str()), [](auto &mod,
133 auto &cls) {
134 /* Constructors */
135 cls.def(py::init<unsigned int, unsigned int, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
136 "width"_a, "height"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
137 cls.def(py::init<unsigned int, unsigned int, MaskPixelT,
138 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
139 "width"_a, "height"_a, "initialValue"_a,
140 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
141 cls.def(py::init<lsst::geom::Extent2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
142 "dimensions"_a = lsst::geom::Extent2I(),
143 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
144 cls.def(py::init<lsst::geom::Extent2I const &, MaskPixelT,
145 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
146 "dimensions"_a = lsst::geom::Extent2I(), "initialValue"_a,
147 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
148 cls.def(py::init<lsst::geom::Box2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
149 "bbox"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
150 cls.def(py::init<lsst::geom::Box2I const &, MaskPixelT,
151 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
152 "bbox"_a, "initialValue"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
153 cls.def(py::init<const Mask<MaskPixelT> &, const bool>(), "src"_a, "deep"_a = false);
154 cls.def(py::init<const Mask<MaskPixelT> &, const lsst::geom::Box2I &, ImageOrigin const,
155 const bool>(),
156 "src"_a, "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
157 cls.def(py::init<ndarray::Array<MaskPixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
158 "array"_a, "deep"_a = false, "xy0"_a = lsst::geom::Point2I());
159 cls.def(py::init<std::string const &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
160 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
161 "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
162 "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "conformMasks"_a = false,
163 "allowUnsafe"_a = false);
164 cls.def(py::init<fits::MemFileManager &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
165 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
166 "manager"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
167 "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "conformMasks"_a = false,
168 "allowUnsafe"_a = false);
169 cls.def(py::init<fits::Fits &, std::shared_ptr<lsst::daf::base::PropertySet>,
170 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
171 "fitsFile"_a, "metadata"_a = nullptr, "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT,
172 "conformMasks"_a = false, "allowUnsafe"_a = false);
173
174 /* Operators */
175 cls.def("__ior__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self |= other; });
176 cls.def("__ior__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self |= other; });
177 cls.def("__ior__", [](Mask<MaskPixelT> &self, int other) { return self |= other; });
178 cls.def("__iand__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self &= other; });
179 cls.def("__iand__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self &= other; });
180 cls.def("__iand__", [](Mask<MaskPixelT> &self, int other) { return self &= other; });
181 cls.def("__ixor__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self ^= other; });
182 cls.def("__ixor__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self ^= other; });
183 cls.def("__ixor__", [](Mask<MaskPixelT> &self, int other) { return self ^= other; });
184
185 /* Members */
186 cls.def("swap", (void (Mask<MaskPixelT>::*)(Mask<MaskPixelT> &)) & Mask<MaskPixelT>::swap);
187 cls.def("writeFits",
188 (void (Mask<MaskPixelT>::*)(std::string const &,
189 daf::base::PropertySet const *,
190 std::string const &) const) &
192 "fileName"_a, "metadata"_a = nullptr, "mode"_a = "w");
193 cls.def("writeFits",
194 (void (Mask<MaskPixelT>::*)(fits::MemFileManager &,
195 daf::base::PropertySet const *,
196 std::string const &) const) &
198 "manager"_a, "metadata"_a = nullptr, "mode"_a = "w");
199 cls.def("writeFits",
200 (void (Mask<MaskPixelT>::*)(fits::Fits &, daf::base::PropertySet const *)
201 const) &
203 "fitsfile"_a, "metadata"_a = nullptr);
204 cls.def("writeFits",
205 (void (Mask<MaskPixelT>::*)(std::string const &, fits::ImageWriteOptions const &,
206 std::string const &,
207 daf::base::PropertySet const *) const) &
209 "filename"_a, "options"_a, "mode"_a = "w",
210 "header"_a = nullptr);
211 cls.def("writeFits",
212 (void (Mask<MaskPixelT>::*)(fits::MemFileManager &, fits::ImageWriteOptions const &,
213 std::string const &,
214 daf::base::PropertySet const *) const) &
216 "manager"_a, "options"_a, "mode"_a = "w",
217 "header"_a = nullptr);
218 cls.def("writeFits",
219 (void (Mask<MaskPixelT>::*)(fits::Fits &, fits::ImageWriteOptions const &,
220 daf::base::PropertySet const *) const) &
222 "fits"_a, "options"_a, "header"_a = nullptr);
223 cls.def_static("readFits", (Mask<MaskPixelT>(*)(std::string const &, int))Mask<MaskPixelT>::readFits,
224 "filename"_a, "hdu"_a = fits::DEFAULT_HDU);
225 cls.def_static("readFits",
226 (Mask<MaskPixelT>(*)(fits::MemFileManager &, int))Mask<MaskPixelT>::readFits,
227 "manager"_a, "hdu"_a = fits::DEFAULT_HDU);
228 cls.def_static("interpret", Mask<MaskPixelT>::interpret);
229 cls.def("subset", &Mask<MaskPixelT>::subset, "bbox"_a, "origin"_a = PARENT);
230 cls.def("getAsString", &Mask<MaskPixelT>::getAsString);
231 cls.def("clearAllMaskPlanes", &Mask<MaskPixelT>::clearAllMaskPlanes);
232 cls.def("clearMaskPlane", &Mask<MaskPixelT>::clearMaskPlane);
233 cls.def("setMaskPlaneValues", &Mask<MaskPixelT>::setMaskPlaneValues);
234 cls.def_static("parseMaskPlaneMetadata", Mask<MaskPixelT>::parseMaskPlaneMetadata);
235 cls.def_static("clearMaskPlaneDict", Mask<MaskPixelT>::clearMaskPlaneDict);
236 cls.def_static("removeMaskPlane", Mask<MaskPixelT>::removeMaskPlane);
237 cls.def("removeAndClearMaskPlane", &Mask<MaskPixelT>::removeAndClearMaskPlane, "name"_a,
238 "removeFromDefault"_a = false);
239 cls.def_static("getMaskPlane", Mask<MaskPixelT>::getMaskPlane);
240 cls.def_static("getPlaneBitMask",
241 (MaskPixelT(*)(const std::string &))Mask<MaskPixelT>::getPlaneBitMask);
242 cls.def_static("getPlaneBitMask",
243 (MaskPixelT(*)(const std::vector<std::string> &))Mask<MaskPixelT>::getPlaneBitMask);
244 cls.def_static("getNumPlanesMax", Mask<MaskPixelT>::getNumPlanesMax);
245 cls.def_static("getNumPlanesUsed", Mask<MaskPixelT>::getNumPlanesUsed);
246 cls.def("getMaskPlaneDict", &Mask<MaskPixelT>::getMaskPlaneDict);
247 cls.def("printMaskPlanes", &Mask<MaskPixelT>::printMaskPlanes);
248 cls.def_static("addMaskPlanesToMetadata", Mask<MaskPixelT>::addMaskPlanesToMetadata);
249 cls.def("conformMaskPlanes", &Mask<MaskPixelT>::conformMaskPlanes);
250 cls.def_static("addMaskPlane", (int (*)(const std::string &))Mask<MaskPixelT>::addMaskPlane);
251 });
252}
253
254template <typename PixelT>
255static PyImage<PixelT> declareImage(lsst::cpputils::python::WrapperCollection &wrappers,
256 const std::string &suffix) {
257 return wrappers.wrapType(PyImage<PixelT>(wrappers.module, ("Image" + suffix).c_str()), [](auto &mod,
258 auto &cls) {
259 /* Constructors */
260 cls.def(py::init<unsigned int, unsigned int, PixelT>(), "width"_a, "height"_a, "intialValue"_a = 0);
261 cls.def(py::init<lsst::geom::Extent2I const &, PixelT>(), "dimensions"_a = lsst::geom::Extent2I(),
262 "initialValue"_a = 0);
263 cls.def(py::init<lsst::geom::Box2I const &, PixelT>(), "bbox"_a, "initialValue"_a = 0);
264 cls.def(py::init<Image<PixelT> const &, lsst::geom::Box2I const &, ImageOrigin const, const bool>(),
265 "rhs"_a, "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
266 cls.def(py::init<ndarray::Array<PixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
267 "array"_a, "deep"_a = false, "xy0"_a = lsst::geom::Point2I());
268 cls.def(py::init<std::string const &, int, std::shared_ptr<daf::base::PropertySet>,
269 lsst::geom::Box2I const &, ImageOrigin, bool>(),
270 "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
271 "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "allowUnsafe"_a = false);
272 cls.def(py::init<fits::MemFileManager &, int, std::shared_ptr<daf::base::PropertySet>,
273 lsst::geom::Box2I const &, ImageOrigin, bool>(),
274 "manager"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
275 "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "allowUnsafe"_a = false);
276 cls.def(py::init<fits::Fits &, std::shared_ptr<daf::base::PropertySet>, lsst::geom::Box2I const &,
277 ImageOrigin, bool>(),
278 "fitsFile"_a, "metadata"_a = nullptr, "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT,
279 "allowUnsafe"_a = false);
280
281 /* Operators */
282 cls.def("__iadd__", [](Image<PixelT> &self, PixelT const &other) { return self += other; });
283 cls.def("__iadd__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self += other; });
284 cls.def("__iadd__", [](Image<PixelT> &self, lsst::afw::math::Function2<double> const &other) {
285 return self += other;
286 });
287 cls.def("__isub__", [](Image<PixelT> &self, PixelT const &other) { return self -= other; });
288 cls.def("__isub__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self -= other; });
289 cls.def("__isub__", [](Image<PixelT> &self, lsst::afw::math::Function2<double> const &other) {
290 return self -= other;
291 });
292 cls.def("__imul__", [](Image<PixelT> &self, PixelT const &other) { return self *= other; });
293 cls.def("__imul__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self *= other; });
294 cls.def("__itruediv__", [](Image<PixelT> &self, PixelT const &other) { return self /= other; });
295 cls.def("__itruediv__",
296 [](Image<PixelT> &self, Image<PixelT> const &other) { return self /= other; });
297
298 /* Members */
299 cls.def("scaledPlus", &Image<PixelT>::scaledPlus);
300 cls.def("scaledMinus", &Image<PixelT>::scaledMinus);
301 cls.def("scaledMultiplies", &Image<PixelT>::scaledMultiplies);
302 cls.def("scaledDivides", &Image<PixelT>::scaledDivides);
303
304 cls.def("subset", &Image<PixelT>::subset, "bbox"_a, "origin"_a = PARENT);
305
306 cls.def("writeFits",
307 (void (Image<PixelT>::*)(std::string const &, daf::base::PropertySet const *,
308 std::string const &) const) &
309 Image<PixelT>::writeFits,
310 "fileName"_a, "metadata"_a = nullptr, "mode"_a = "w");
311 cls.def("writeFits",
313 daf::base::PropertySet const *, std::string const &)
314 const) &
315 Image<PixelT>::writeFits,
316 "manager"_a, "metadata"_a = nullptr, "mode"_a = "w");
317 cls.def("writeFits",
318 (void (Image<PixelT>::*)(fits::Fits &, daf::base::PropertySet const *) const) &
319 Image<PixelT>::writeFits,
320 "fitsfile"_a, "metadata"_a = nullptr);
321 cls.def("writeFits",
322 (void (Image<PixelT>::*)(std::string const &, fits::ImageWriteOptions const &,
323 std::string const &, daf::base::PropertySet const *,
324 image::Mask<image::MaskPixel> const *) const) &
325 Image<PixelT>::writeFits,
326 "filename"_a, "options"_a, "mode"_a = "w",
327 "header"_a = nullptr,
328 "mask"_a = nullptr);
329 cls.def("writeFits",
331 std::string const &, daf::base::PropertySet const *,
332 image::Mask<image::MaskPixel> const *) const) &
333 Image<PixelT>::writeFits,
334 "manager"_a, "options"_a, "mode"_a = "w",
335 "header"_a = nullptr,
336 "mask"_a = nullptr);
337 cls.def("writeFits",
339 daf::base::PropertySet const *,
340 image::Mask<image::MaskPixel> const *) const) &
341 Image<PixelT>::writeFits,
342 "fits"_a, "options"_a, "header"_a = nullptr,
343 "mask"_a = nullptr);
344
345 cls.def_static("readFits", (Image<PixelT>(*)(std::string const &, int))Image<PixelT>::readFits,
346 "filename"_a, "hdu"_a = fits::DEFAULT_HDU);
347 cls.def_static("readFits", (Image<PixelT>(*)(fits::MemFileManager &, int))Image<PixelT>::readFits,
348 "manager"_a, "hdu"_a = fits::DEFAULT_HDU);
349 cls.def("sqrt", &Image<PixelT>::sqrt);
350 });
351}
352
353template <typename PixelT>
354static void declareDecoratedImage(lsst::cpputils::python::WrapperCollection &wrappers,
355 std::string const &suffix) {
356 wrappers.wrapType(
357 PyDecoratedImage<PixelT>(wrappers.module, ("DecoratedImage" + suffix).c_str()),
358 [](auto &mod, auto &cls) {
359 cls.def(py::init<const lsst::geom::Extent2I &>(), "dimensions"_a = lsst::geom::Extent2I());
360 cls.def(py::init<const lsst::geom::Box2I &>(), "bbox"_a);
361 cls.def(py::init<std::shared_ptr<Image<PixelT>>>(), "rhs"_a);
362 cls.def(py::init<DecoratedImage<PixelT> const &, const bool>(), "rhs"_a, "deep"_a = false);
363 cls.def(py::init<std::string const &, const int, lsst::geom::Box2I const &, ImageOrigin const,
364 bool>(),
365 "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "bbox"_a = lsst::geom::Box2I(),
366 "origin"_a = PARENT, "allowUnsafe"_a = false);
367
368 cls.def("getMetadata", &DecoratedImage<PixelT>::getMetadata);
369 cls.def("setMetadata", &DecoratedImage<PixelT>::setMetadata);
370 cls.def("getWidth", &DecoratedImage<PixelT>::getWidth);
371 cls.def("getHeight", &DecoratedImage<PixelT>::getHeight);
372 cls.def("getX0", &DecoratedImage<PixelT>::getX0);
373 cls.def("getY0", &DecoratedImage<PixelT>::getY0);
374 cls.def("getDimensions", &DecoratedImage<PixelT>::getDimensions);
375 cls.def("swap", &DecoratedImage<PixelT>::swap);
376 cls.def("writeFits",
377 py::overload_cast<std::string const &, daf::base::PropertySet const *,
378 std::string const &>(&DecoratedImage<PixelT>::writeFits,
379 py::const_),
380 "filename"_a, "metadata"_a = nullptr,
381 "mode"_a = "w");
382 cls.def("writeFits",
383 py::overload_cast<std::string const &, fits::ImageWriteOptions const &,
384 daf::base::PropertySet const *, std::string const &>(
385 &DecoratedImage<PixelT>::writeFits, py::const_),
386 "filename"_a, "options"_a, "metadata"_a = nullptr,
387 "mode"_a = "w");
388 cls.def("getImage", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
389 cls.def_property_readonly("image", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
390 cls.def("getGain", &DecoratedImage<PixelT>::getGain);
391 cls.def("setGain", &DecoratedImage<PixelT>::setGain);
392 });
393}
394
395/* Declare ImageSlice operators separately since they are only instantiated for float double */
396template <typename PixelT>
397static void addImageSliceOperators(
398 py::class_<Image<PixelT>, std::shared_ptr<Image<PixelT>>, ImageBase<PixelT>> &cls) {
399 cls.def(
400 "__add__",
401 [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self + other; },
402 py::is_operator());
403 cls.def(
404 "__sub__",
405 [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self - other; },
406 py::is_operator());
407 cls.def(
408 "__mul__",
409 [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self * other; },
410 py::is_operator());
411 cls.def(
412 "__truediv__",
413 [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self / other; },
414 py::is_operator());
415 cls.def("__iadd__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
416 self += other;
417 return self;
418 });
419 cls.def("__isub__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
420 self -= other;
421 return self;
422 });
423 cls.def("__imul__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
424 self *= other;
425 return self;
426 });
427 cls.def("__itruediv__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
428 self /= other;
429 return self;
430 });
431}
432
433template <typename PixelT, typename PyClass>
434static void addGeneralizedCopyConstructors(PyClass &cls) {
435 cls.def(py::init<Image<int> const &, const bool>(), "rhs"_a, "deep"_a = false);
436 cls.def(py::init<Image<float> const &, const bool>(), "rhs"_a, "deep"_a = false);
437 cls.def(py::init<Image<double> const &, const bool>(), "rhs"_a, "deep"_a = false);
438 cls.def(py::init<Image<std::uint16_t> const &, const bool>(), "rhs"_a, "deep"_a = false);
439 cls.def(py::init<Image<std::uint64_t> const &, const bool>(), "rhs"_a, "deep"_a = false);
440
441 cls.def("convertI", [](Image<PixelT> const &self) { return Image<int>(self, true); });
442 cls.def("convertF", [](Image<PixelT> const &self) { return Image<float>(self, true); });
443 cls.def("convertD", [](Image<PixelT> const &self) { return Image<double>(self, true); });
444 cls.def("convertU", [](Image<PixelT> const &self) { return Image<std::uint16_t>(self, true); });
445 cls.def("convertL", [](Image<PixelT> const &self) { return Image<std::uint64_t>(self, true); });
446
447 cls.def("convertFloat", [](Image<PixelT> const &self) { return Image<float>(self, true); });
448 cls.def("convertDouble", [](Image<PixelT> const &self) { return Image<double>(self, true); });
449}
450} // namespace
452 wrappers.addSignatureDependency("lsst.daf.base");
453 wrappers.addSignatureDependency("lsst.geom");
454 wrappers.wrapType(py::enum_<ImageOrigin>(wrappers.module, "ImageOrigin"), [](auto &mod, auto &enm) {
455 enm.value("PARENT", ImageOrigin::PARENT);
456 enm.value("LOCAL", ImageOrigin::LOCAL);
457 enm.export_values();
458 });
459
460 declareImageBase<int>(wrappers, "I");
461 declareImageBase<float>(wrappers, "F");
462 declareImageBase<double>(wrappers, "D");
463 declareImageBase<std::uint16_t>(wrappers, "U");
464 declareImageBase<std::uint64_t>(wrappers, "L");
465
466 // Mask must be declared before Image because a mask is used as a default value in at least one method
467 declareMask<MaskPixel>(wrappers, "X");
468
469 auto clsImageI = declareImage<int>(wrappers, "I");
470 auto clsImageF = declareImage<float>(wrappers, "F");
471 auto clsImageD = declareImage<double>(wrappers, "D");
472 auto clsImageU = declareImage<std::uint16_t>(wrappers, "U");
473 auto clsImageL = declareImage<std::uint64_t>(wrappers, "L");
474
475 // Add generalized copy constructors
476 addGeneralizedCopyConstructors<int>(clsImageI);
477 addGeneralizedCopyConstructors<float>(clsImageF);
478 addGeneralizedCopyConstructors<double>(clsImageD);
479 addGeneralizedCopyConstructors<std::uint16_t>(clsImageU);
480 addGeneralizedCopyConstructors<std::uint64_t>(clsImageL);
481
482 // Add slice operators only for float and double
483 addImageSliceOperators<float>(clsImageF);
484 addImageSliceOperators<double>(clsImageD);
485
486 declareDecoratedImage<int>(wrappers, "I");
487 declareDecoratedImage<float>(wrappers, "F");
488 declareDecoratedImage<double>(wrappers, "D");
489 declareDecoratedImage<std::uint16_t>(wrappers, "U");
490 declareDecoratedImage<std::uint64_t>(wrappers, "L");
491
492 // Declare constructors for casting all exposure types to to float and double
493 // (the only two types of casts that Python supports)
494 declareCastConstructor<int, float>(clsImageF);
495 declareCastConstructor<int, double>(clsImageD);
496
497 declareCastConstructor<float, double>(clsImageD);
498
499 declareCastConstructor<double, float>(clsImageF);
500
501 declareCastConstructor<std::uint16_t, float>(clsImageF);
502 declareCastConstructor<std::uint16_t, double>(clsImageD);
503
504 declareCastConstructor<std::uint64_t, float>(clsImageF);
505 declareCastConstructor<std::uint64_t, double>(clsImageD);
506
507 // Note: wrap both the Image and MaskedImage versions of imagesOverlap in the MaskedImage wrapper,
508 // as wrapping the Image version here results in it being invisible in lsst.afw.image
509 wrappers.wrap([](auto &mod) { mod.def("bboxFromMetadata", &bboxFromMetadata); });
510}
511} // namespace image
512} // namespace afw
513} // namespace lsst
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition fits.h:308
Lifetime-management for memory that goes into FITS memory files.
Definition fits.h:125
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition ImageBase.h:102
void setXY0(lsst::geom::Point2I const origin)
Set the ImageBase's origin.
Definition ImageBase.h:434
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition ImageBase.h:445
typename ndarray::Array< PixelT, 2, 1 > Array
A mutable ndarray representation of the image.
Definition ImageBase.h:149
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:82
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
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
Definition python.h:369
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
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition python.h:448
const int DEFAULT_HDU
Specify that the default HDU should be read.
void checkBounds(geom::Point2I const &index, geom::Box2I const &bbox)
Definition indexing.h:30
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
Definition Image.cc:681
void wrapImage(lsst::cpputils::python::WrapperCollection &wrappers)
Definition _image.cc:451
Point< int, 2 > Point2I
Definition Point.h:321
Options for writing an image to FITS.
Definition fits.h:223
g2d::python::Image< double > Image
Definition test_image.cc:14