31 #include <type_traits>
32 #include "boost/mpl/vector.hpp"
33 #pragma clang diagnostic push
34 #pragma clang diagnostic ignored "-Wunused-variable"
35 #pragma clang diagnostic pop
36 #include "boost/format.hpp"
37 #include "boost/filesystem/path.hpp"
39 #include "boost/version.hpp"
40 #if BOOST_VERSION < 106900
41 #include "boost/gil/gil_all.hpp"
43 #include "boost/gil.hpp"
57 template <
typename PixelT>
59 Manager::Ptr& manager) {
62 str(boost::format(
"Both width and height must be non-negative: %d, %d") %
67 str(boost::format(
"Image dimensions (%d x %d) too large; int overflow detected.") %
74 (
typename _view_t::value_type*)r.second,
77 template <
typename PixelT>
80 const _view_t& view) {
81 if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() +
dimensions.getX() > view.width() ||
82 offset.getY() +
dimensions.getY() > view.height()) {
86 "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
91 return boost::gil::subimage_view(view, offset.getX(), offset.getY(),
dimensions.getX(),
95 template <
typename PixelT>
97 : _origin(0, 0), _manager(), _gilView(_allocateView(
dimensions, _manager)) {}
99 template <
typename PixelT>
101 : _origin(
bbox.getMin()), _manager(), _gilView(_allocateView(
bbox.getDimensions(), _manager)) {}
103 template <
typename PixelT>
107 : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
115 template <
typename PixelT>
118 template <
typename PixelT>
124 _manager(rhs._manager),
125 _gilView(_makeSubView(
bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
133 template <
typename PixelT>
136 _manager(array.getManager()),
137 _gilView(
boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
138 (typename _view_t::value_type*)array.getData(),
139 array.template getStride<0>() * sizeof(PixelT))) {
146 template <
typename PixelT>
154 template <
typename PixelT>
159 template <
typename PixelT>
161 auto lhsDim =
bbox.isEmpty() ? getDimensions() :
bbox.getDimensions();
164 (boost::format(
"Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
168 if (
bbox.isEmpty()) {
169 copy_pixels(rhs._gilView, _gilView);
172 auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
173 copy_pixels(rhs._gilView, lhsGilView);
177 template <
typename PixelT>
183 template <
typename PixelT>
186 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
188 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
189 (getWidth() - 1) % (getHeight() - 1))
197 template <
typename PixelT>
199 return _gilView(
x,
y)[0];
202 template <
typename PixelT>
205 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
207 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
208 (this->getWidth() - 1) % (this->getHeight() - 1))
212 return _gilView(
x,
y)[0];
215 template <
typename PixelT>
218 int x = index.getX();
219 int y = index.getY();
224 return _gilView(
x,
y)[0];
227 template <
typename PixelT>
230 int x = index.getX();
231 int y = index.getY();
236 return _gilView(
x,
y)[0];
239 template <
typename PixelT>
243 swap(_manager, rhs._manager);
244 swap(_gilView, rhs._gilView);
245 swap(_origin, rhs._origin);
248 template <
typename PixelT>
256 template <
typename PixelT>
258 return _gilView.begin();
261 template <
typename PixelT>
263 return _gilView.end();
266 template <
typename PixelT>
268 return _gilView.rbegin();
271 template <
typename PixelT>
273 return _gilView.rend();
276 template <
typename PixelT>
278 return _gilView.at(
x,
y);
281 template <
typename PixelT>
286 if (!this->isContiguous()) {
293 template <
typename PixelT>
298 if (!this->isContiguous()) {
302 return row_end(getHeight() - 1);
305 template <
typename PixelT>
307 fill_pixels(_gilView, rhs);
315 template <
typename PixelT>
318 *
this = initialValue;
321 template <
typename PixelT>
324 *
this = initialValue;
327 template <
typename PixelT>
329 *
this = initialValue;
332 template <
typename PixelT>
335 template <
typename PixelT>
338 template <
typename PixelT>
343 template <
typename PixelT>
350 template <
typename PixelT>
357 template <
typename PixelT>
364 template <
typename PixelT>
368 *
this = reader.
read<PixelT>(
bbox, origin, allowUnsafe);
374 template <
typename PixelT>
379 *
this = reader.
read<PixelT>(
bbox, origin, allowUnsafe);
385 template <
typename PixelT>
389 *
this = reader.
read<PixelT>(
bbox, origin, allowUnsafe);
395 template <
typename PixelT>
400 writeFits(fitsfile, metadata_i);
403 template <
typename PixelT>
408 writeFits(fitsfile, metadata_i);
411 template <
typename PixelT>
414 fitsfile.writeImage(*
this, fits::ImageWriteOptions(*
this), metadata);
417 template <
typename PixelT>
422 writeFits(fitsfile, options, header,
mask);
425 template <
typename PixelT>
430 writeFits(fitsfile, options, header,
mask);
433 template <
typename PixelT>
437 fitsfile.writeImage(*
this, options, header,
mask);
442 template <
typename PixelT>
449 template <
typename PixelT>
455 template <
typename PixelT>
457 transform_pixels(_getRawView(), _getRawView(),
458 [](PixelT
const& l) -> PixelT {
return static_cast<PixelT
>(
std::sqrt(l)); });
461 template <
typename PixelT>
463 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l + rhs; });
467 template <
typename PixelT>
471 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
475 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
476 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l + r; });
480 template <
typename PixelT>
482 for (
int y = 0;
y != this->getHeight(); ++
y) {
487 *ptr +=
function(xPos, yPos);
493 template <
typename PixelT>
497 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
503 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l +
static_cast<PixelT
>(c * r); });
506 template <
typename PixelT>
508 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l - rhs; });
512 template <
typename PixelT>
516 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
520 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
521 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l - r; });
525 template <
typename PixelT>
529 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
535 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l -
static_cast<PixelT
>(c * r); });
538 template <
typename PixelT>
540 for (
int y = 0;
y != this->getHeight(); ++
y) {
545 *ptr -=
function(xPos, yPos);
551 template <
typename PixelT>
553 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l * rhs; });
557 template <
typename PixelT>
561 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
565 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
566 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l * r; });
570 template <
typename PixelT>
574 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
580 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l *
static_cast<PixelT
>(c * r); });
583 template <
typename PixelT>
585 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l / rhs; });
593 double const irhs = 1 / rhs;
600 float const irhs = 1 / rhs;
605 template <
typename PixelT>
609 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
613 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
614 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l / r; });
618 template <
typename PixelT>
622 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
628 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l /
static_cast<PixelT
>(c * r); });
635 template <
typename LhsPixelT,
typename RhsPixelT>
636 struct plusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
637 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
638 return static_cast<LhsPixelT
>(lhs + rhs);
642 template <
typename LhsPixelT,
typename RhsPixelT>
643 struct minusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
644 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
645 return static_cast<LhsPixelT
>(lhs - rhs);
649 template <
typename LhsPixelT,
typename RhsPixelT>
650 struct timesEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
651 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
652 return static_cast<LhsPixelT
>(lhs * rhs);
656 template <
typename LhsPixelT,
typename RhsPixelT>
657 struct divideEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
658 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
659 return static_cast<LhsPixelT
>(lhs / rhs);
664 template <
typename LhsPixelT,
typename RhsPixelT>
670 template <
typename LhsPixelT,
typename RhsPixelT>
676 template <
typename LhsPixelT,
typename RhsPixelT>
682 template <
typename LhsPixelT,
typename RhsPixelT>
690 if (metadata.
exists(
"ZNAXIS1") && metadata.
exists(
"ZNAXIS2")) {
699 template <
typename T1,
typename T2>
704 auto beg1Addr = arr1.front().begin();
705 auto end1Addr = arr1.back().end();
708 auto beg2Addr = arr2.front().begin();
709 auto end2Addr = arr2.back().end();
712 return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
719 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
720 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
721 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
722 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
723 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
724 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
726 #define INSTANTIATE(T) \
727 template class ImageBase<T>; \
728 template class Image<T>; \
729 INSTANTIATE_OPERATOR(+=, T); \
730 INSTANTIATE_OPERATOR(-=, T); \
731 INSTANTIATE_OPERATOR(*=, T); \
732 INSTANTIATE_OPERATOR(/=, T)
734 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
#define INSTANTIATE(FROMSYS, TOSYS)
#define LSST_EXCEPT(type,...)
afw::table::PointKey< int > dimensions
#define INSTANTIATE2(ImagePixelT1, ImagePixelT2)
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.
A class used to request that array accesses be checked.
std::shared_ptr< daf::base::PropertyList > readMetadata()
Read the image's FITS header.
The base class for all image classed (Image, Mask, MaskedImage, ...)
iterator end() const
Return an STL compliant iterator to the end of the image.
iterator begin() const
Return an STL compliant iterator to the start of the image.
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Reference< PixelT >::type PixelReference
A Reference to a PixelT.
PixelReference operator()(int x, int y)
Return a reference to the pixel (x, y) in LOCAL coordinates.
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
int getWidth() const
Return the number of columns in the image.
_view_t::reverse_iterator reverse_iterator
An STL compliant reverse iterator.
x_iterator fast_iterator
A fast STL compliant iterator for contiguous images N.b.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
ndarray::Array< PixelT, 2, 1 > Array
A mutable ndarray representation of the image.
lsst::geom::Extent2I getDimensions() const
Return the image's size; useful for passing to constructors.
void assign(ImageBase const &rhs, lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT)
Copy pixels from another image to a specified subregion of this image.
int getHeight() const
Return the number of rows in the image.
_view_t::iterator iterator
An STL compliant iterator.
ImageBase & operator=(const ImageBase &rhs)
Shallow assignment operator.
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
ConstReference< PixelT >::type PixelConstReference
A ConstReference to a PixelT.
reverse_iterator rbegin() const
Return an STL compliant reverse iterator to the start of the image.
_view_t _getRawView() const
PixelReference get(lsst::geom::Point2I const &index, ImageOrigin origin)
Return a reference to a single pixel (with no bounds check).
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
void swap(ImageBase &rhs)
reverse_iterator rend() const
Return an STL compliant reverse iterator to the end of the image.
A FITS reader class for regular Images.
Image< PixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the Image.
A class to represent a 2-dimensional array of pixels.
void scaledPlus(double const c, Image< PixelT > const &rhs)
Add Image c*rhs to lhs.
Image & operator*=(PixelT const rhs)
Multiply lhs by scalar rhs.
void scaledMinus(double const c, Image< PixelT > const &rhs)
Subtract Image c*rhs from lhs.
Image & operator-=(PixelT const rhs)
Subtract scalar rhs from lhs.
Image & operator=(const PixelT rhs)
Set the image's pixels to rhs.
void scaledMultiplies(double const c, Image< PixelT > const &rhs)
Multiply lhs by Image c*rhs (i.e. pixel-by-pixel multiplication)
Image & operator+=(PixelT const rhs)
Add scalar rhs to lhs.
Image & operator/=(PixelT const rhs)
Divide lhs by scalar rhs.
void writeFits(std::string const &fileName, std::shared_ptr< lsst::daf::base::PropertySet const > metadata=std::shared_ptr< lsst::daf::base::PropertySet const >(), std::string const &mode="w") const
Write an image to a regular FITS file.
void scaledDivides(double const c, Image< PixelT > const &rhs)
Divide lhs by Image c*rhs (i.e. pixel-by-pixel division)
A Function taking two arguments.
int getAsInt(std::string const &name) const
bool exists(std::string const &name) const
lsst::geom::Point2I getImageXY0FromMetadata(daf::base::PropertySet &metadata, std::string const &wcsName, bool strip=false)
std::string const wcsNameForXY0
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Image< LhsPixelT > & operator+=(Image< LhsPixelT > &lhs, Image< RhsPixelT > const &rhs)
Add lhs to Image rhs (i.e. pixel-by-pixel addition) where types are different.
Image< LhsPixelT > & operator-=(Image< LhsPixelT > &lhs, Image< RhsPixelT > const &rhs)
Subtract lhs from Image rhs (i.e. pixel-by-pixel subtraction) where types are different.
void for_each_pixel(Image< LhsT > &lhs, pixelOp0< LhsT > const &func)
Set each pixel in an Image<LhsT> to func()
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
Image< LhsPixelT > & operator/=(Image< LhsPixelT > &lhs, Image< RhsPixelT > const &rhs)
Divide lhs by Image rhs (i.e. pixel-by-pixel division) where types are different.
double indexToPosition(double ind)
Convert image index to image position.
Image< LhsPixelT > & operator*=(Image< LhsPixelT > &lhs, Image< RhsPixelT > const &rhs)
Multiply lhs by Image rhs (i.e. pixel-by-pixel multiplication) where types are different.
bool imagesOverlap(ImageBase< T1 > const &image1, ImageBase< T2 > const &image2)
Return true if the pixels for two images or masks overlap in memory.
void swap(Image< PixelT > &a, Image< PixelT > &b)
Extent< int, 2 > Extent2I
A base class for image defects.
A functor class equivalent to std::function<LhsT (LhsT, RhsT)>, but with a virtual operator()