24#include "pybind11/pybind11.h"
25#include "pybind11/stl.h"
27#include "ndarray/pybind11.h"
36using namespace pybind11::literals;
44template <
typename PixelT>
45using PyImageBase = py::classh<ImageBase<PixelT>>;
47template <
typename PixelT>
50template <
typename PixelT>
51using PyDecoratedImage = py::classh<DecoratedImage<PixelT>>;
53template <
typename MaskPixelT>
64template <
typename FromPixelT,
typename ToPixelT>
65static void declareCastConstructor(PyImage<ToPixelT> &cls) {
69template <
typename PixelT>
70static void declareImageBase(lsst::cpputils::python::WrapperCollection &wrappers, std::string
const &suffix) {
72 wrappers.
wrapType(PyImageBase<PixelT>(wrappers.
module, (
"ImageBase" + suffix).c_str()), [](
auto &mod,
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());
81 cls.def(
"assign", &ImageBase<PixelT>::assign,
"rhs"_a,
"bbox"_a = lsst::geom::Box2I(),
85 cls.def(
"getWidth", &ImageBase<PixelT>::getWidth);
86 cls.def(
"getHeight", &ImageBase<PixelT>::getHeight);
87 cls.def_property_readonly(
"width", &ImageBase<PixelT>::getWidth);
88 cls.def_property_readonly(
"height", &ImageBase<PixelT>::getHeight);
89 cls.def(
"getX0", &ImageBase<PixelT>::getX0);
90 cls.def(
"getY0", &ImageBase<PixelT>::getY0);
91 cls.def_property_readonly(
"x0", &ImageBase<PixelT>::getX0);
92 cls.def_property_readonly(
"y0", &ImageBase<PixelT>::getY0);
93 cls.def(
"getXY0", &ImageBase<PixelT>::getXY0);
94 cls.def(
"positionToIndex", &ImageBase<PixelT>::positionToIndex,
"position"_a,
"xOrY"_a);
95 cls.def(
"indexToPosition", &ImageBase<PixelT>::indexToPosition,
"index"_a,
"xOrY"_a);
96 cls.def(
"getDimensions", &ImageBase<PixelT>::getDimensions);
97 cls.def(
"getArray", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray);
98 cls.def_property(
"array", (Array(ImageBase<PixelT>::*)()) & ImageBase<PixelT>::getArray,
99 [](py::object &self, py::object value) {
100 if (value == py::none()) {
101 throw py::type_error(
"Cannot assign None to an array.");
103 py::array array = self.attr(
"array");
104 array[py::ellipsis()] = value;
118 img.get(index, origin) = val;
120 "index"_a,
"value"_a,
"origin"_a);
125 return img.get(index, origin);
127 "index"_a,
"origin"_a);
131template <
typename MaskPixelT>
132static void declareMask(lsst::cpputils::python::WrapperCollection &wrappers, std::string
const &suffix) {
133 wrappers.
wrapType(PyMask<MaskPixelT>(wrappers.
module, (
"Mask" + suffix).c_str()), [](
auto &mod,
136 cls.def(py::init<unsigned int, unsigned int, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
137 "width"_a,
"height"_a,
"planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
138 cls.def(py::init<unsigned int, unsigned int, MaskPixelT,
139 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
140 "width"_a,
"height"_a,
"initialValue"_a,
141 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
142 cls.def(py::init<lsst::geom::Extent2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
143 "dimensions"_a = lsst::geom::Extent2I(),
144 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
145 cls.def(py::init<lsst::geom::Extent2I const &, MaskPixelT,
146 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
147 "dimensions"_a = lsst::geom::Extent2I(),
"initialValue"_a,
148 "planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
149 cls.def(py::init<lsst::geom::Box2I const &, typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
150 "bbox"_a,
"planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
151 cls.def(py::init<lsst::geom::Box2I const &, MaskPixelT,
152 typename Mask<MaskPixelT>::MaskPlaneDict const &>(),
153 "bbox"_a,
"initialValue"_a,
"planeDefs"_a = typename Mask<MaskPixelT>::MaskPlaneDict());
154 cls.def(py::init<const Mask<MaskPixelT> &, const bool>(),
"src"_a,
"deep"_a = false);
155 cls.def(py::init<const Mask<MaskPixelT> &, const lsst::geom::Box2I &, ImageOrigin const,
157 "src"_a,
"bbox"_a,
"origin"_a = PARENT,
"deep"_a = false);
158 cls.def(py::init<ndarray::Array<MaskPixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
159 "array"_a,
"deep"_a = false,
"xy0"_a = lsst::geom::Point2I());
160 cls.def(py::init<std::string const &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
161 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
162 "fileName"_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::MemFileManager &, int, std::shared_ptr<lsst::daf::base::PropertySet>,
166 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
167 "manager"_a,
"hdu"_a = fits::DEFAULT_HDU,
"metadata"_a = nullptr,
168 "bbox"_a = lsst::geom::Box2I(),
"origin"_a = PARENT,
"conformMasks"_a = false,
169 "allowUnsafe"_a = false);
170 cls.def(py::init<fits::Fits &, std::shared_ptr<lsst::daf::base::PropertySet>,
171 lsst::geom::Box2I const &, ImageOrigin, bool, bool>(),
172 "fitsFile"_a,
"metadata"_a = nullptr,
"bbox"_a = lsst::geom::Box2I(),
"origin"_a = PARENT,
173 "conformMasks"_a = false,
"allowUnsafe"_a = false);
176 cls.def(
"__ior__", [](Mask<MaskPixelT> &self, Mask<MaskPixelT> &other) { return self |= other; });
177 cls.def(
"__ior__", [](
Mask<MaskPixelT> &self, MaskPixelT
const other) {
return self |= other; });
178 cls.def(
"__ior__", [](
Mask<MaskPixelT> &self,
int other) {
return self |= other; });
180 cls.def(
"__iand__", [](
Mask<MaskPixelT> &self, MaskPixelT
const other) {
return self &= other; });
181 cls.def(
"__iand__", [](
Mask<MaskPixelT> &self,
int other) {
return self &= other; });
183 cls.def(
"__ixor__", [](
Mask<MaskPixelT> &self, MaskPixelT
const other) {
return self ^= other; });
184 cls.def(
"__ixor__", [](
Mask<MaskPixelT> &self,
int other) {
return self ^= other; });
190 daf::base::PropertySet
const *,
191 std::string
const &)
const) &
193 "fileName"_a,
"metadata"_a =
nullptr,
"mode"_a =
"w");
196 daf::base::PropertySet
const *,
197 std::string
const &)
const) &
199 "manager"_a,
"metadata"_a =
nullptr,
"mode"_a =
"w");
204 "fitsfile"_a,
"metadata"_a =
nullptr);
206 (
void (
Mask<MaskPixelT>::*)(std::string
const &, fits::CompressionOptions
const *,
208 daf::base::PropertySet
const *)
const) &
210 "filename"_a,
"options"_a,
"mode"_a =
"w",
211 "header"_a =
nullptr);
213 (
void (
Mask<MaskPixelT>::*)(fits::MemFileManager &, fits::CompressionOptions
const *,
215 daf::base::PropertySet
const *)
const) &
217 "manager"_a,
"options"_a,
"mode"_a =
"w",
218 "header"_a =
nullptr);
221 daf::base::PropertySet
const *)
const) &
223 "fits"_a,
"options"_a,
"header"_a =
nullptr);
226 cls.def_static(
"readFits",
239 "removeFromDefault"_a =
false);
241 cls.def_static(
"getPlaneBitMask",
243 cls.def_static(
"getPlaneBitMask",
255template <
typename PixelT>
256static PyImage<PixelT> declareImage(lsst::cpputils::python::WrapperCollection &wrappers,
257 const std::string &suffix) {
258 return wrappers.
wrapType(PyImage<PixelT>(wrappers.
module, (
"Image" + suffix).c_str()), [](
auto &mod,
261 cls.def(py::init<unsigned int, unsigned int, PixelT>(),
"width"_a,
"height"_a,
"intialValue"_a = 0);
262 cls.def(py::init<lsst::geom::Extent2I const &, PixelT>(),
"dimensions"_a = lsst::geom::Extent2I(),
263 "initialValue"_a = 0);
264 cls.def(py::init<lsst::geom::Box2I const &, PixelT>(),
"bbox"_a,
"initialValue"_a = 0);
265 cls.def(py::init<Image<PixelT> const &, lsst::geom::Box2I const &, ImageOrigin const, const bool>(),
266 "rhs"_a,
"bbox"_a,
"origin"_a = PARENT,
"deep"_a = false);
267 cls.def(py::init<ndarray::Array<PixelT, 2, 1> const &, bool, lsst::geom::Point2I const &>(),
268 "array"_a,
"deep"_a = false,
"xy0"_a = lsst::geom::Point2I());
269 cls.def(py::init<std::string const &, int, std::shared_ptr<daf::base::PropertySet>,
270 lsst::geom::Box2I const &, ImageOrigin, bool>(),
271 "fileName"_a,
"hdu"_a = fits::DEFAULT_HDU,
"metadata"_a = nullptr,
272 "bbox"_a = lsst::geom::Box2I(),
"origin"_a = PARENT,
"allowUnsafe"_a = false);
273 cls.def(py::init<fits::MemFileManager &, int, std::shared_ptr<daf::base::PropertySet>,
274 lsst::geom::Box2I const &, ImageOrigin, bool>(),
275 "manager"_a,
"hdu"_a = fits::DEFAULT_HDU,
"metadata"_a = nullptr,
276 "bbox"_a = lsst::geom::Box2I(),
"origin"_a = PARENT,
"allowUnsafe"_a = false);
277 cls.def(py::init<fits::Fits &, std::shared_ptr<daf::base::PropertySet>, lsst::geom::Box2I const &,
278 ImageOrigin, bool>(),
279 "fitsFile"_a,
"metadata"_a = nullptr,
"bbox"_a = lsst::geom::Box2I(),
"origin"_a = PARENT,
280 "allowUnsafe"_a = false);
283 cls.def(
"__iadd__", [](Image<PixelT> &self, PixelT const &other) { return self += other; });
285 cls.def(
"__iadd__", [](
Image<PixelT> &self, lsst::afw::math::Function2<double>
const &other) {
286 return self += other;
288 cls.def(
"__isub__", [](
Image<PixelT> &self, PixelT
const &other) {
return self -= other; });
290 cls.def(
"__isub__", [](
Image<PixelT> &self, lsst::afw::math::Function2<double>
const &other) {
291 return self -= other;
293 cls.def(
"__imul__", [](
Image<PixelT> &self, PixelT
const &other) {
return self *= other; });
295 cls.def(
"__itruediv__", [](
Image<PixelT> &self, PixelT
const &other) {
return self /= other; });
296 cls.def(
"__itruediv__",
300 cls.def(
"scaledPlus", &Image<PixelT>::scaledPlus);
301 cls.def(
"scaledMinus", &Image<PixelT>::scaledMinus);
302 cls.def(
"scaledMultiplies", &Image<PixelT>::scaledMultiplies);
303 cls.def(
"scaledDivides", &Image<PixelT>::scaledDivides);
305 cls.def(
"subset", &Image<PixelT>::subset,
"bbox"_a,
"origin"_a = PARENT);
308 (
void (
Image<PixelT>::*)(std::string
const &, daf::base::PropertySet
const *,
309 std::string
const &)
const) &
310 Image<PixelT>::writeFits,
311 "fileName"_a,
"metadata"_a =
nullptr,
"mode"_a =
"w");
314 daf::base::PropertySet
const *, std::string
const &)
316 Image<PixelT>::writeFits,
317 "manager"_a,
"metadata"_a =
nullptr,
"mode"_a =
"w");
320 Image<PixelT>::writeFits,
321 "fitsfile"_a,
"metadata"_a =
nullptr);
324 std::string
const &, daf::base::PropertySet
const *,
326 Image<PixelT>::writeFits,
327 "filename"_a,
"options"_a,
"mode"_a =
"w",
328 "header"_a =
nullptr,
332 std::string
const &, daf::base::PropertySet
const *,
334 Image<PixelT>::writeFits,
335 "manager"_a,
"options"_a,
"mode"_a =
"w",
336 "header"_a =
nullptr,
340 daf::base::PropertySet
const *,
342 Image<PixelT>::writeFits,
343 "fits"_a,
"options"_a,
"header"_a =
nullptr,
346 cls.def_static(
"readFits", (
Image<PixelT>(*)(std::string
const &,
int))Image<PixelT>::readFits,
350 cls.def(
"sqrt", &Image<PixelT>::sqrt);
354template <
typename PixelT>
355static void declareDecoratedImage(lsst::cpputils::python::WrapperCollection &wrappers,
356 std::string
const &suffix) {
358 PyDecoratedImage<PixelT>(wrappers.
module, (
"DecoratedImage" + suffix).c_str()),
359 [](
auto &mod,
auto &cls) {
360 cls.def(py::init<const lsst::geom::Extent2I &>(),
"dimensions"_a = lsst::geom::Extent2I());
361 cls.def(py::init<const lsst::geom::Box2I &>(),
"bbox"_a);
362 cls.def(py::init<std::shared_ptr<Image<PixelT>>>(),
"rhs"_a);
363 cls.def(py::init<DecoratedImage<PixelT> const &, const bool>(),
"rhs"_a,
"deep"_a = false);
364 cls.def(py::init<std::string const &, const int, lsst::geom::Box2I const &, ImageOrigin const,
366 "fileName"_a,
"hdu"_a = fits::DEFAULT_HDU,
"bbox"_a = lsst::geom::Box2I(),
367 "origin"_a = PARENT,
"allowUnsafe"_a = false);
369 cls.def(
"getMetadata", &DecoratedImage<PixelT>::getMetadata);
370 cls.def(
"setMetadata", &DecoratedImage<PixelT>::setMetadata);
371 cls.def(
"getWidth", &DecoratedImage<PixelT>::getWidth);
372 cls.def(
"getHeight", &DecoratedImage<PixelT>::getHeight);
373 cls.def(
"getX0", &DecoratedImage<PixelT>::getX0);
374 cls.def(
"getY0", &DecoratedImage<PixelT>::getY0);
375 cls.def(
"getDimensions", &DecoratedImage<PixelT>::getDimensions);
376 cls.def(
"swap", &DecoratedImage<PixelT>::swap);
378 py::overload_cast<std::string const &, daf::base::PropertySet const *,
379 std::string const &>(&DecoratedImage<PixelT>::writeFits,
381 "filename"_a,
"metadata"_a = nullptr,
384 py::overload_cast<std::string const &, fits::CompressionOptions const *,
385 daf::base::PropertySet const *, std::string const &>(
386 &DecoratedImage<PixelT>::writeFits, py::const_),
387 "filename"_a,
"options"_a,
"metadata"_a = nullptr,
389 cls.def(
"getImage", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
390 cls.def_property_readonly(
"image", py::overload_cast<>(&DecoratedImage<PixelT>::getImage));
391 cls.def(
"getGain", &DecoratedImage<PixelT>::getGain);
392 cls.def(
"setGain", &DecoratedImage<PixelT>::setGain);
397template <
typename PixelT>
398static void addImageSliceOperators(
402 [](
Image<PixelT> const &self, ImageSlice<PixelT>
const &other) {
return self + other; },
406 [](
Image<PixelT> const &self, ImageSlice<PixelT>
const &other) {
return self - other; },
410 [](
Image<PixelT> const &self, ImageSlice<PixelT>
const &other) {
return self * other; },
414 [](
Image<PixelT> const &self, ImageSlice<PixelT>
const &other) {
return self / other; },
416 cls.def(
"__iadd__", [](
Image<PixelT> &self, ImageSlice<PixelT>
const &other) {
420 cls.def(
"__isub__", [](
Image<PixelT> &self, ImageSlice<PixelT>
const &other) {
424 cls.def(
"__imul__", [](
Image<PixelT> &self, ImageSlice<PixelT>
const &other) {
428 cls.def(
"__itruediv__", [](
Image<PixelT> &self, ImageSlice<PixelT>
const &other) {
434template <
typename PixelT,
typename PyClass>
435static void addGeneralizedCopyConstructors(PyClass &cls) {
436 cls.def(py::init<
Image<int> const &,
const bool>(),
"rhs"_a,
"deep"_a =
false);
437 cls.def(py::init<Image<float>
const &,
const bool>(),
"rhs"_a,
"deep"_a =
false);
438 cls.def(py::init<Image<double>
const &,
const bool>(),
"rhs"_a,
"deep"_a =
false);
443 cls.def(
"convertF", [](
Image<PixelT> const &self) {
return Image<float>(self,
true); });
444 cls.def(
"convertD", [](
Image<PixelT> const &self) {
return Image<double>(self,
true); });
448 cls.def(
"convertFloat", [](
Image<PixelT> const &self) {
return Image<float>(self,
true); });
449 cls.def(
"convertDouble", [](
Image<PixelT> const &self) {
return Image<double>(self,
true); });
455 wrappers.
wrapType(py::enum_<ImageOrigin>(wrappers.
module,
"ImageOrigin"), [](
auto &mod,
auto &enm) {
456 enm.value(
"PARENT", ImageOrigin::PARENT);
457 enm.value(
"LOCAL", ImageOrigin::LOCAL);
461 declareImageBase<int>(wrappers,
"I");
462 declareImageBase<float>(wrappers,
"F");
463 declareImageBase<double>(wrappers,
"D");
464 declareImageBase<std::uint16_t>(wrappers,
"U");
465 declareImageBase<std::uint64_t>(wrappers,
"L");
468 declareMask<MaskPixel>(wrappers,
"X");
470 auto clsImageI = declareImage<int>(wrappers,
"I");
471 auto clsImageF = declareImage<float>(wrappers,
"F");
472 auto clsImageD = declareImage<double>(wrappers,
"D");
473 auto clsImageU = declareImage<std::uint16_t>(wrappers,
"U");
474 auto clsImageL = declareImage<std::uint64_t>(wrappers,
"L");
477 addGeneralizedCopyConstructors<int>(clsImageI);
478 addGeneralizedCopyConstructors<float>(clsImageF);
479 addGeneralizedCopyConstructors<double>(clsImageD);
480 addGeneralizedCopyConstructors<std::uint16_t>(clsImageU);
481 addGeneralizedCopyConstructors<std::uint64_t>(clsImageL);
484 addImageSliceOperators<float>(clsImageF);
485 addImageSliceOperators<double>(clsImageD);
487 declareDecoratedImage<int>(wrappers,
"I");
488 declareDecoratedImage<float>(wrappers,
"F");
489 declareDecoratedImage<double>(wrappers,
"D");
490 declareDecoratedImage<std::uint16_t>(wrappers,
"U");
491 declareDecoratedImage<std::uint64_t>(wrappers,
"L");
495 declareCastConstructor<int, float>(clsImageF);
496 declareCastConstructor<int, double>(clsImageD);
498 declareCastConstructor<float, double>(clsImageD);
500 declareCastConstructor<double, float>(clsImageF);
502 declareCastConstructor<std::uint16_t, float>(clsImageF);
503 declareCastConstructor<std::uint16_t, double>(clsImageD);
505 declareCastConstructor<std::uint64_t, float>(clsImageF);
506 declareCastConstructor<std::uint64_t, double>(clsImageD);
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Lifetime-management for memory that goes into FITS memory files.
The base class for all image classed (Image, Mask, MaskedImage, ...)
void setXY0(lsst::geom::Point2I const origin)
Set the ImageBase's origin.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
typename ndarray::Array< PixelT, 2, 1 > Array
A mutable ndarray representation of the image.
A class to represent a 2-dimensional array of pixels.
Represent a 2-dimensional array of bitmask pixels.
A helper class for subdividing pybind11 module across multiple translation units (i....
void addSignatureDependency(std::string const &name)
Indicate an external module that provides a type used in function/method signatures.
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
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...
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
const int DEFAULT_HDU
Specify that the default HDU should be read.
void checkBounds(geom::Point2I const &index, geom::Box2I const &bbox)
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
void wrapImage(lsst::cpputils::python::WrapperCollection &wrappers)
Options controlling image compression with FITS.
g2d::python::Image< double > Image