LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+4b710797af,21.0.0-1-gfc31b0f+3b24369756,21.0.0-10-g2408eff+50e97f2f47,21.0.0-10-g560fb7b+0803ad37c5,21.0.0-10-g5daeb2b+f9b8dc6d5a,21.0.0-10-g8d1d15d+77a6b82ebf,21.0.0-10-gcf60f90+c961be884d,21.0.0-11-g25eff31+7692554667,21.0.0-17-g6590b197+a14a01c114,21.0.0-2-g103fe59+b79afc2051,21.0.0-2-g1367e85+1003a3501c,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+1003a3501c,21.0.0-2-g7f82c8f+c2a1919b98,21.0.0-2-g8f08a60+fd0b970de5,21.0.0-2-ga326454+c2a1919b98,21.0.0-2-gde069b7+ca45a81b40,21.0.0-2-gecfae73+afcaaec585,21.0.0-2-gfc62afb+1003a3501c,21.0.0-21-g5d80ea29e+5e3c9a3766,21.0.0-3-g357aad2+c67f36f878,21.0.0-3-g4be5c26+1003a3501c,21.0.0-3-g65f322c+02b1f88459,21.0.0-3-g7d9da8d+3b24369756,21.0.0-3-ge02ed75+a423c2ae7a,21.0.0-4-g591bb35+a423c2ae7a,21.0.0-4-g65b4814+0803ad37c5,21.0.0-4-g88306b8+199c7497e5,21.0.0-4-gccdca77+a631590478,21.0.0-4-ge8a399c+b923ff878e,21.0.0-5-gd00fb1e+d8b1e95daa,21.0.0-53-ge728e5d5+3cb64fea8e,21.0.0-6-g2d4f3f3+04719a4bac,21.0.0-7-g04766d7+8d320c19d5,21.0.0-7-g98eecf7+205433fbda,21.0.0-9-g39e06b5+a423c2ae7a,master-gac4afde19b+a423c2ae7a,w.2021.11
LSST Data Management Base Package
image.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008-2016 AURA/LSST.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <https://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 #include "pybind11/pybind11.h"
24 #include "pybind11/stl.h"
25 #include "lsst/utils/python.h"
26 #include "ndarray/pybind11.h"
27 
28 #include "lsst/afw/image/Image.h"
30 #include "lsst/afw/image/Mask.h"
31 #include "lsst/afw/fits.h"
33 
34 namespace py = pybind11;
35 using namespace pybind11::literals;
36 
37 namespace lsst {
38 namespace afw {
39 namespace image {
40 
41 namespace {
42 
43 template <typename PixelT>
44 using PyImageBase = py::class_<ImageBase<PixelT>, std::shared_ptr<ImageBase<PixelT>>>;
45 
46 template <typename PixelT>
47 using PyImage = py::class_<Image<PixelT>, std::shared_ptr<Image<PixelT>>, ImageBase<PixelT>>;
48 
49 template <typename PixelT>
50 using PyDecoratedImage = py::class_<DecoratedImage<PixelT>, std::shared_ptr<DecoratedImage<PixelT>>>;
51 
52 template <typename MaskPixelT>
53 using PyMask = py::class_<Mask<MaskPixelT>, std::shared_ptr<Mask<MaskPixelT>>, ImageBase<MaskPixelT>>;
54 
63 template <typename FromPixelT, typename ToPixelT>
64 static void declareCastConstructor(PyImage<ToPixelT> &cls) {
65  cls.def(py::init<Image<FromPixelT> const &, bool const>(), "src"_a, "deep"_a);
66 }
67 
68 template <typename PixelT>
69 static void declareImageBase(lsst::utils::python::WrapperCollection &wrappers, std::string const &suffix) {
70  using Array = typename ImageBase<PixelT>::Array;
71  wrappers.wrapType(PyImageBase<PixelT>(wrappers.module, ("ImageBase" + suffix).c_str()), [](auto &mod,
72  auto &cls) {
73  cls.def(py::init<lsst::geom::Extent2I const &>(), "dimensions"_a = lsst::geom::Extent2I());
74  cls.def(py::init<ImageBase<PixelT> const &, bool>(), "src"_a, "deep"_a = false);
75  cls.def(py::init<ImageBase<PixelT> const &, lsst::geom::Box2I const &, ImageOrigin, bool>(), "src"_a,
76  "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
77  cls.def(py::init<Array const &, bool, lsst::geom::Point2I const &>(), "array"_a, "deep"_a = false,
78  "xy0"_a = lsst::geom::Point2I());
79 
80  cls.def("assign", &ImageBase<PixelT>::assign, "rhs"_a, "bbox"_a = lsst::geom::Box2I(),
81  "origin"_a = PARENT,
82  py::is_operator()); // py::is_operator is a workaround for code in slicing.py
83  // that expects NotImplemented to be returned on failure.
84  cls.def("getWidth", &ImageBase<PixelT>::getWidth);
85  cls.def("getHeight", &ImageBase<PixelT>::getHeight);
86  cls.def("getX0", &ImageBase<PixelT>::getX0);
87  cls.def("getY0", &ImageBase<PixelT>::getY0);
88  cls.def("getXY0", &ImageBase<PixelT>::getXY0);
89  cls.def("positionToIndex", &ImageBase<PixelT>::positionToIndex, "position"_a, "xOrY"_a);
90  cls.def("indexToPosition", &ImageBase<PixelT>::indexToPosition, "index"_a, "xOrY"_a);
91  cls.def("getDimensions", &ImageBase<PixelT>::getDimensions);
92  cls.def("getArray", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray);
93  cls.def_property("array", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray,
94  [](ImageBase<PixelT> &self, ndarray::Array<PixelT const, 2, 0> const &array) {
95  // Avoid self-assignment, which is invoked when a Python in-place operator is
96  // used.
97  if (array.shallow() != self.getArray().shallow()) {
98  self.getArray().deep() = array;
99  }
100  });
101  cls.def("setXY0",
102  (void (ImageBase<PixelT>::*)(lsst::geom::Point2I const)) & ImageBase<PixelT>::setXY0,
103  "xy0"_a);
104  cls.def("setXY0", (void (ImageBase<PixelT>::*)(int const, int const)) & ImageBase<PixelT>::setXY0,
105  "x0"_a, "y0"_a);
106  cls.def("getBBox", &ImageBase<PixelT>::getBBox, "origin"_a = PARENT);
107 
108  cls.def("set", [](ImageBase<PixelT> &img, PixelT val) { img = val; });
109  cls.def(
110  "_set",
111  [](ImageBase<PixelT> &img, geom::Point2I const &index, PixelT val, ImageOrigin origin) {
112  python::checkBounds(index, img.getBBox(origin));
113  img.get(index, origin) = val;
114  },
115  "index"_a, "value"_a, "origin"_a);
116  cls.def(
117  "_get",
118  [](ImageBase<PixelT> &img, geom::Point2I const &index, ImageOrigin origin) {
119  python::checkBounds(index, img.getBBox(origin));
120  return img.get(index, origin);
121  },
122  "index"_a, "origin"_a);
123  });
124 }
125 
126 template <typename MaskPixelT>
127 static void declareMask(lsst::utils::python::WrapperCollection &wrappers, std::string const &suffix) {
128  wrappers.wrapType(PyMask<MaskPixelT>(wrappers.module, ("Mask" + suffix).c_str()), [](auto &mod,
129  auto &cls) {
130  /* Constructors */
131  cls.def(py::init<unsigned int, unsigned int, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
132  "width"_a, "height"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
133  cls.def(py::init<unsigned int, unsigned int, MaskPixelT,
134  typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
135  "width"_a, "height"_a, "initialValue"_a,
136  "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
137  cls.def(py::init<lsst::geom::Extent2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
138  "dimensions"_a = lsst::geom::Extent2I(),
139  "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
140  cls.def(py::init<lsst::geom::Extent2I const &, MaskPixelT,
141  typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
142  "dimensions"_a = lsst::geom::Extent2I(), "initialValue"_a,
143  "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
144  cls.def(py::init<lsst::geom::Box2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
145  "bbox"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
146  cls.def(py::init<lsst::geom::Box2I const &, MaskPixelT,
147  typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
148  "bbox"_a, "initialValue"_a, "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
149  cls.def(py::init<const Mask<MaskPixelT> &, const bool>(), "src"_a, "deep"_a = false);
150  cls.def(py::init<const Mask<MaskPixelT> &, const lsst::geom::Box2I &, ImageOrigin const,
151  const bool>(),
152  "src"_a, "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
153  cls.def(py::init<ndarray::Array<MaskPixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
154  "array"_a, "deep"_a = false, "xy0"_a = lsst::geom::Point2I());
155  cls.def(py::init<std::string const &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
156  lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
157  "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
158  "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "conformMasks"_a = false,
159  "allowUnsafe"_a = false);
160  cls.def(py::init<fits::MemFileManager &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
161  lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
162  "manager"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
163  "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "conformMasks"_a = false,
164  "allowUnsafe"_a = false);
165  cls.def(py::init<fits::Fits &, std::shared_ptr<lsst::daf::base::PropertySet>,
166  lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
167  "fitsFile"_a, "metadata"_a = nullptr, "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT,
168  "conformMasks"_a = false, "allowUnsafe"_a = false);
169 
170  /* Operators */
171  cls.def("__ior__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self |= other; });
172  cls.def("__ior__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self |= other; });
173  cls.def("__ior__", [](Mask<MaskPixelT> &self, int other) { return self |= other; });
174  cls.def("__iand__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self &= other; });
175  cls.def("__iand__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self &= other; });
176  cls.def("__iand__", [](Mask<MaskPixelT> &self, int other) { return self &= other; });
177  cls.def("__ixor__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self ^= other; });
178  cls.def("__ixor__", [](Mask<MaskPixelT> &self, MaskPixelT const other) { return self ^= other; });
179  cls.def("__ixor__", [](Mask<MaskPixelT> &self, int other) { return self ^= other; });
180 
181  /* Members */
182  cls.def("swap", (void (Mask<MaskPixelT>::*)(Mask<MaskPixelT> &)) & Mask<MaskPixelT>::swap);
183  cls.def("writeFits",
184  (void (Mask<MaskPixelT>::*)(std::string const &,
186  std::string const &) const) &
188  "fileName"_a, "metadata"_a = std::shared_ptr<lsst::daf::base::PropertySet>(), "mode"_a = "w");
189  cls.def("writeFits",
190  (void (Mask<MaskPixelT>::*)(fits::MemFileManager &,
192  std::string const &) const) &
194  "manager"_a, "metadata"_a = std::shared_ptr<lsst::daf::base::PropertySet>(), "mode"_a = "w");
195  cls.def("writeFits",
196  (void (Mask<MaskPixelT>::*)(fits::Fits &, std::shared_ptr<lsst::daf::base::PropertySet const>)
197  const) &
199  "fitsfile"_a, "metadata"_a = std::shared_ptr<lsst::daf::base::PropertySet const>());
200  cls.def("writeFits",
201  (void (Mask<MaskPixelT>::*)(std::string const &, fits::ImageWriteOptions const &,
202  std::string const &,
205  "filename"_a, "options"_a, "mode"_a = "w",
207  cls.def("writeFits",
208  (void (Mask<MaskPixelT>::*)(fits::MemFileManager &, fits::ImageWriteOptions const &,
209  std::string const &,
212  "manager"_a, "options"_a, "mode"_a = "w",
214  cls.def("writeFits",
215  (void (Mask<MaskPixelT>::*)(fits::Fits &, fits::ImageWriteOptions const &,
218  "fits"_a, "options"_a, "header"_a = std::shared_ptr<daf::base::PropertyList>());
219  cls.def_static("readFits", (Mask<MaskPixelT>(*)(std::string const &, int))Mask<MaskPixelT>::readFits,
220  "filename"_a, "hdu"_a = fits::DEFAULT_HDU);
221  cls.def_static("readFits",
222  (Mask<MaskPixelT>(*)(fits::MemFileManager &, int))Mask<MaskPixelT>::readFits,
223  "manager"_a, "hdu"_a = fits::DEFAULT_HDU);
224  cls.def_static("interpret", Mask<MaskPixelT>::interpret);
225  cls.def("subset", &Mask<MaskPixelT>::subset, "bbox"_a, "origin"_a = PARENT);
226  cls.def("getAsString", &Mask<MaskPixelT>::getAsString);
227  cls.def("clearAllMaskPlanes", &Mask<MaskPixelT>::clearAllMaskPlanes);
228  cls.def("clearMaskPlane", &Mask<MaskPixelT>::clearMaskPlane);
229  cls.def("setMaskPlaneValues", &Mask<MaskPixelT>::setMaskPlaneValues);
230  cls.def_static("parseMaskPlaneMetadata", Mask<MaskPixelT>::parseMaskPlaneMetadata);
231  cls.def_static("clearMaskPlaneDict", Mask<MaskPixelT>::clearMaskPlaneDict);
232  cls.def_static("removeMaskPlane", Mask<MaskPixelT>::removeMaskPlane);
233  cls.def("removeAndClearMaskPlane", &Mask<MaskPixelT>::removeAndClearMaskPlane, "name"_a,
234  "removeFromDefault"_a = false);
235  cls.def_static("getMaskPlane", Mask<MaskPixelT>::getMaskPlane);
236  cls.def_static("getPlaneBitMask",
237  (MaskPixelT(*)(const std::string &))Mask<MaskPixelT>::getPlaneBitMask);
238  cls.def_static("getPlaneBitMask",
239  (MaskPixelT(*)(const std::vector<std::string> &))Mask<MaskPixelT>::getPlaneBitMask);
240  cls.def_static("getNumPlanesMax", Mask<MaskPixelT>::getNumPlanesMax);
241  cls.def_static("getNumPlanesUsed", Mask<MaskPixelT>::getNumPlanesUsed);
242  cls.def("getMaskPlaneDict", &Mask<MaskPixelT>::getMaskPlaneDict);
243  cls.def("printMaskPlanes", &Mask<MaskPixelT>::printMaskPlanes);
244  cls.def_static("addMaskPlanesToMetadata", Mask<MaskPixelT>::addMaskPlanesToMetadata);
245  cls.def("conformMaskPlanes", &Mask<MaskPixelT>::conformMaskPlanes);
246  cls.def_static("addMaskPlane", (int (*)(const std::string &))Mask<MaskPixelT>::addMaskPlane);
247  });
248 }
249 
250 template <typename PixelT>
251 static PyImage<PixelT> declareImage(lsst::utils::python::WrapperCollection &wrappers,
252  const std::string &suffix) {
253  return wrappers.wrapType(PyImage<PixelT>(wrappers.module, ("Image" + suffix).c_str()), [](auto &mod,
254  auto &cls) {
255  /* Constructors */
256  cls.def(py::init<unsigned int, unsigned int, PixelT>(), "width"_a, "height"_a, "intialValue"_a = 0);
257  cls.def(py::init<lsst::geom::Extent2I const &, PixelT>(), "dimensions"_a = lsst::geom::Extent2I(),
258  "initialValue"_a = 0);
259  cls.def(py::init<lsst::geom::Box2I const &, PixelT>(), "bbox"_a, "initialValue"_a = 0);
260  cls.def(py::init<Image<PixelT> const &, lsst::geom::Box2I const &, ImageOrigin const, const bool>(),
261  "rhs"_a, "bbox"_a, "origin"_a = PARENT, "deep"_a = false);
262  cls.def(py::init<ndarray::Array<PixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
263  "array"_a, "deep"_a = false, "xy0"_a = lsst::geom::Point2I());
264  cls.def(py::init<std::string const &, int, std::shared_ptr<daf::base::PropertySet>,
265  lsst::geom::Box2I const &, ImageOrigin, bool>(),
266  "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "metadata"_a = nullptr,
267  "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT, "allowUnsafe"_a = false);
268  cls.def(py::init<fits::MemFileManager &, int, std::shared_ptr<daf::base::PropertySet>,
269  lsst::geom::Box2I const &, ImageOrigin, bool>(),
270  "manager"_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::Fits &, std::shared_ptr<daf::base::PropertySet>, lsst::geom::Box2I const &,
273  ImageOrigin, bool>(),
274  "fitsFile"_a, "metadata"_a = nullptr, "bbox"_a = lsst::geom::Box2I(), "origin"_a = PARENT,
275  "allowUnsafe"_a = false);
276 
277  /* Operators */
278  cls.def("__iadd__", [](Image<PixelT> &self, PixelT const &other) { return self += other; });
279  cls.def("__iadd__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self += other; });
280  cls.def("__iadd__", [](Image<PixelT> &self, lsst::afw::math::Function2<double> const &other) {
281  return self += other;
282  });
283  cls.def("__isub__", [](Image<PixelT> &self, PixelT const &other) { return self -= other; });
284  cls.def("__isub__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self -= other; });
285  cls.def("__isub__", [](Image<PixelT> &self, lsst::afw::math::Function2<double> const &other) {
286  return self -= other;
287  });
288  cls.def("__imul__", [](Image<PixelT> &self, PixelT const &other) { return self *= other; });
289  cls.def("__imul__", [](Image<PixelT> &self, Image<PixelT> const &other) { return self *= other; });
290  cls.def("__itruediv__", [](Image<PixelT> &self, PixelT const &other) { return self /= other; });
291  cls.def("__itruediv__",
292  [](Image<PixelT> &self, Image<PixelT> const &other) { return self /= other; });
293 
294  /* Members */
295  cls.def("scaledPlus", &Image<PixelT>::scaledPlus);
296  cls.def("scaledMinus", &Image<PixelT>::scaledMinus);
297  cls.def("scaledMultiplies", &Image<PixelT>::scaledMultiplies);
298  cls.def("scaledDivides", &Image<PixelT>::scaledDivides);
299 
300  cls.def("subset", &Image<PixelT>::subset, "bbox"_a, "origin"_a = PARENT);
301 
302  cls.def("writeFits",
303  (void (Image<PixelT>::*)(std::string const &, std::shared_ptr<daf::base::PropertySet const>,
304  std::string const &) const) &
306  "fileName"_a, "metadata"_a = std::shared_ptr<daf::base::PropertySet const>(), "mode"_a = "w");
307  cls.def("writeFits",
308  (void (Image<PixelT>::*)(fits::MemFileManager &,
310  const) &
312  "manager"_a, "metadata"_a = std::shared_ptr<daf::base::PropertySet const>(), "mode"_a = "w");
313  cls.def("writeFits",
314  (void (Image<PixelT>::*)(fits::Fits &, std::shared_ptr<daf::base::PropertySet const>) const) &
316  "fitsfile"_a, "metadata"_a = std::shared_ptr<daf::base::PropertySet const>());
317  cls.def("writeFits",
318  (void (Image<PixelT>::*)(std::string const &, fits::ImageWriteOptions const &,
322  "filename"_a, "options"_a, "mode"_a = "w",
325  cls.def("writeFits",
326  (void (Image<PixelT>::*)(fits::MemFileManager &, fits::ImageWriteOptions const &,
330  "manager"_a, "options"_a, "mode"_a = "w",
333  cls.def("writeFits",
334  (void (Image<PixelT>::*)(fits::Fits &, fits::ImageWriteOptions const &,
338  "fits"_a, "options"_a, "header"_a = std::shared_ptr<daf::base::PropertyList>(),
340 
341  cls.def_static("readFits", (Image<PixelT>(*)(std::string const &, int))Image<PixelT>::readFits,
342  "filename"_a, "hdu"_a = fits::DEFAULT_HDU);
343  cls.def_static("readFits", (Image<PixelT>(*)(fits::MemFileManager &, int))Image<PixelT>::readFits,
344  "manager"_a, "hdu"_a = fits::DEFAULT_HDU);
345  cls.def("sqrt", &Image<PixelT>::sqrt);
346  });
347 }
348 
349 template <typename PixelT>
350 static void declareDecoratedImage(lsst::utils::python::WrapperCollection &wrappers,
351  std::string const &suffix) {
352  wrappers.wrapType(
353  PyDecoratedImage<PixelT>(wrappers.module, ("DecoratedImage" + suffix).c_str()),
354  [](auto &mod, auto &cls) {
355  cls.def(py::init<const lsst::geom::Extent2I &>(), "dimensions"_a = lsst::geom::Extent2I());
356  cls.def(py::init<const lsst::geom::Box2I &>(), "bbox"_a);
357  cls.def(py::init<std::shared_ptr<Image<PixelT>>>(), "rhs"_a);
358  cls.def(py::init<DecoratedImage<PixelT> const &, const bool>(), "rhs"_a, "deep"_a = false);
359  cls.def(py::init<std::string const &, const int, lsst::geom::Box2I const &, ImageOrigin const,
360  bool>(),
361  "fileName"_a, "hdu"_a = fits::DEFAULT_HDU, "bbox"_a = lsst::geom::Box2I(),
362  "origin"_a = PARENT, "allowUnsafe"_a = false);
363 
364  cls.def("getMetadata", &DecoratedImage<PixelT>::getMetadata);
365  cls.def("setMetadata", &DecoratedImage<PixelT>::setMetadata);
366  cls.def("getWidth", &DecoratedImage<PixelT>::getWidth);
367  cls.def("getHeight", &DecoratedImage<PixelT>::getHeight);
368  cls.def("getX0", &DecoratedImage<PixelT>::getX0);
369  cls.def("getY0", &DecoratedImage<PixelT>::getY0);
370  cls.def("getDimensions", &DecoratedImage<PixelT>::getDimensions);
371  cls.def("swap", &DecoratedImage<PixelT>::swap);
372  cls.def("writeFits",
373  py::overload_cast<std::string const &, std::shared_ptr<daf::base::PropertySet const>,
374  std::string const &>(&DecoratedImage<PixelT>::writeFits,
375  py::const_),
376  "filename"_a, "metadata"_a = std::shared_ptr<daf::base::PropertyList>(),
377  "mode"_a = "w");
378  cls.def("writeFits",
379  py::overload_cast<std::string const &, fits::ImageWriteOptions const &,
380  std::shared_ptr<daf::base::PropertySet const>, std::string const &>(
381  &DecoratedImage<PixelT>::writeFits, py::const_),
382  "filename"_a, "options"_a, "metadata"_a = std::shared_ptr<daf::base::PropertyList>(),
383  "mode"_a = "w");
384  cls.def("getImage", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
385  cls.def_property_readonly("image", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
386  cls.def("getGain", &DecoratedImage<PixelT>::getGain);
387  cls.def("setGain", &DecoratedImage<PixelT>::setGain);
388  });
389 }
390 
391 /* Declare ImageSlice operators separately since they are only instantiated for float double */
392 template <typename PixelT>
393 static void addImageSliceOperators(
394  py::class_<Image<PixelT>, std::shared_ptr<Image<PixelT>>, ImageBase<PixelT>> &cls) {
395  cls.def(
396  "__add__",
397  [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self + other; },
398  py::is_operator());
399  cls.def(
400  "__sub__",
401  [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self - other; },
402  py::is_operator());
403  cls.def(
404  "__mul__",
405  [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self * other; },
406  py::is_operator());
407  cls.def(
408  "__truediv__",
409  [](Image<PixelT> const &self, ImageSlice<PixelT> const &other) { return self / other; },
410  py::is_operator());
411  cls.def("__iadd__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
412  self += other;
413  return self;
414  });
415  cls.def("__isub__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
416  self -= other;
417  return self;
418  });
419  cls.def("__imul__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
420  self *= other;
421  return self;
422  });
423  cls.def("__itruediv__", [](Image<PixelT> &self, ImageSlice<PixelT> const &other) {
424  self /= other;
425  return self;
426  });
427 }
428 
429 template <typename PixelT, typename PyClass>
430 static void addGeneralizedCopyConstructors(PyClass &cls) {
431  cls.def(py::init<Image<int> const &, const bool>(), "rhs"_a, "deep"_a = false);
432  cls.def(py::init<Image<float> const &, const bool>(), "rhs"_a, "deep"_a = false);
433  cls.def(py::init<Image<double> const &, const bool>(), "rhs"_a, "deep"_a = false);
434  cls.def(py::init<Image<std::uint16_t> const &, const bool>(), "rhs"_a, "deep"_a = false);
435  cls.def(py::init<Image<std::uint64_t> const &, const bool>(), "rhs"_a, "deep"_a = false);
436 
437  cls.def("convertI", [](Image<PixelT> const &self) { return Image<int>(self, true); });
438  cls.def("convertF", [](Image<PixelT> const &self) { return Image<float>(self, true); });
439  cls.def("convertD", [](Image<PixelT> const &self) { return Image<double>(self, true); });
440  cls.def("convertU", [](Image<PixelT> const &self) { return Image<std::uint16_t>(self, true); });
441  cls.def("convertL", [](Image<PixelT> const &self) { return Image<std::uint64_t>(self, true); });
442 
443  cls.def("convertFloat", [](Image<PixelT> const &self) { return Image<float>(self, true); });
444  cls.def("convertDouble", [](Image<PixelT> const &self) { return Image<double>(self, true); });
445 }
446 
447 PYBIND11_MODULE(image, mod) {
448  lsst::utils::python::WrapperCollection wrappers(mod, "lsst.afw.image.image");
449  wrappers.addInheritanceDependency("lsst.daf.base");
450 
451  wrappers.wrapType(py::enum_<ImageOrigin>(wrappers.module, "ImageOrigin"), [](auto &mod, auto &enm) {
452  enm.value("PARENT", ImageOrigin::PARENT);
453  enm.value("LOCAL", ImageOrigin::LOCAL);
454  enm.export_values();
455  });
456 
457  declareImageBase<int>(wrappers, "I");
458  declareImageBase<float>(wrappers, "F");
459  declareImageBase<double>(wrappers, "D");
460  declareImageBase<std::uint16_t>(wrappers, "U");
461  declareImageBase<std::uint64_t>(wrappers, "L");
462 
463  // Mask must be declared before Image because a mask is used as a default value in at least one method
464  declareMask<MaskPixel>(wrappers, "X");
465 
466  auto clsImageI = declareImage<int>(wrappers, "I");
467  auto clsImageF = declareImage<float>(wrappers, "F");
468  auto clsImageD = declareImage<double>(wrappers, "D");
469  auto clsImageU = declareImage<std::uint16_t>(wrappers, "U");
470  auto clsImageL = declareImage<std::uint64_t>(wrappers, "L");
471 
472  // Add generalized copy constructors
473  addGeneralizedCopyConstructors<int>(clsImageI);
474  addGeneralizedCopyConstructors<float>(clsImageF);
475  addGeneralizedCopyConstructors<double>(clsImageD);
476  addGeneralizedCopyConstructors<std::uint16_t>(clsImageU);
477  addGeneralizedCopyConstructors<std::uint64_t>(clsImageL);
478 
479  // Add slice operators only for float and double
480  addImageSliceOperators<float>(clsImageF);
481  addImageSliceOperators<double>(clsImageD);
482 
483  declareDecoratedImage<int>(wrappers, "I");
484  declareDecoratedImage<float>(wrappers, "F");
485  declareDecoratedImage<double>(wrappers, "D");
486  declareDecoratedImage<std::uint16_t>(wrappers, "U");
487  declareDecoratedImage<std::uint64_t>(wrappers, "L");
488 
489  // Declare constructors for casting all exposure types to to float and double
490  // (the only two types of casts that Python supports)
491  declareCastConstructor<int, float>(clsImageF);
492  declareCastConstructor<int, double>(clsImageD);
493 
494  declareCastConstructor<float, double>(clsImageD);
495 
496  declareCastConstructor<double, float>(clsImageF);
497 
498  declareCastConstructor<std::uint16_t, float>(clsImageF);
499  declareCastConstructor<std::uint16_t, double>(clsImageD);
500 
501  declareCastConstructor<std::uint64_t, float>(clsImageF);
502  declareCastConstructor<std::uint64_t, double>(clsImageD);
503 
504  // Note: wrap both the Image and MaskedImage versions of imagesOverlap in the MaskedImage wrapper,
505  // as wrapping the Image version here results in it being invisible in lsst.afw.image
506  wrappers.wrap([](auto &mod) { mod.def("bboxFromMetadata", &bboxFromMetadata); });
507  wrappers.finish();
508 }
509 } // namespace
510 } // namespace image
511 } // namespace afw
512 } // namespace lsst
ItemVariant const * other
Definition: Schema.cc:56
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
A Function taking two arguments.
Definition: Function.h:259
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition: python.h:242
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition: python.h:448
void finish()
Invoke all deferred wrapper-declaring callables.
Definition: python.h:435
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
void addInheritanceDependency(std::string const &name)
Indicate an external module that provides a base class for a subsequent addType call.
Definition: python.h:343
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
Definition: python.h:369
PYBIND11_MODULE(imageUtils, mod)
Definition: imageUtils.cc:33
void swap(CameraSys &a, CameraSys &b)
Definition: CameraSys.h:157
const int DEFAULT_HDU
Specify that the default HDU should be read.
Definition: fitsDefaults.h:18
void checkBounds(geom::Point2I const &index, geom::Box2I const &bbox)
Definition: indexing.h:30
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
Definition: Image.cc:694
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
py::class_< PixelAreaBoundedField, std::shared_ptr< PixelAreaBoundedField >, BoundedField > PyClass
def writeFits(filename, stamp_ims, metadata, write_mask, write_variance)
Definition: stamps.py:38
def init()
Definition: tests.py:59
A base class for image defects.
ImageT val
Definition: CR.cc:146