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"
38 #include "boost/version.hpp"
39 #if BOOST_VERSION < 106900
40 #include "boost/gil/gil_all.hpp"
42 #include "boost/gil.hpp"
56 template <
typename PixelT>
58 Manager::Ptr& manager) {
61 str(boost::format(
"Both width and height must be non-negative: %d, %d") %
66 str(boost::format(
"Image dimensions (%d x %d) too large; int overflow detected.") %
73 (
typename _view_t::value_type*)r.second,
76 template <
typename PixelT>
79 const _view_t& view) {
80 if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() +
dimensions.getX() > view.width() ||
81 offset.getY() +
dimensions.getY() > view.height()) {
85 "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
91 && view.width() == 0 && view.height() == 0) {
95 return boost::gil::subimage_view(view, offset.getX(), offset.getY(),
dimensions.getX(),
100 template <
typename PixelT>
102 : _origin(0, 0), _manager(), _gilView(_allocateView(
dimensions, _manager)) {}
104 template <
typename PixelT>
106 : _origin(
bbox.getMin()), _manager(), _gilView(_allocateView(
bbox.getDimensions(), _manager)) {}
108 template <
typename PixelT>
112 : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
120 template <
typename PixelT>
123 template <
typename PixelT>
129 _manager(rhs._manager),
130 _gilView(_makeSubView(
bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
138 template <
typename PixelT>
141 _manager(array.getManager()),
142 _gilView(
boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
143 (typename _view_t::value_type*)array.getData(),
144 array.template getStride<0>() * sizeof(PixelT))) {
151 template <
typename PixelT>
159 template <
typename PixelT>
164 template <
typename PixelT>
166 auto lhsDim =
bbox.isEmpty() ? getDimensions() :
bbox.getDimensions();
169 (boost::format(
"Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
173 if (
bbox.isEmpty()) {
174 copy_pixels(rhs._gilView, _gilView);
177 auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
178 copy_pixels(rhs._gilView, lhsGilView);
182 template <
typename PixelT>
188 template <
typename PixelT>
191 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
193 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
194 (getWidth() - 1) % (getHeight() - 1))
202 template <
typename PixelT>
204 return _gilView(
x,
y)[0];
207 template <
typename PixelT>
210 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
212 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
213 (this->getWidth() - 1) % (this->getHeight() - 1))
217 return _gilView(
x,
y)[0];
220 template <
typename PixelT>
223 int x = index.getX();
224 int y = index.getY();
229 return _gilView(
x,
y)[0];
232 template <
typename PixelT>
235 int x = index.getX();
236 int y = index.getY();
241 return _gilView(
x,
y)[0];
244 template <
typename PixelT>
248 swap(_manager, rhs._manager);
249 swap(_gilView, rhs._gilView);
250 swap(_origin, rhs._origin);
253 template <
typename PixelT>
261 template <
typename PixelT>
263 return _gilView.begin();
266 template <
typename PixelT>
268 return _gilView.end();
271 template <
typename PixelT>
273 return _gilView.rbegin();
276 template <
typename PixelT>
278 return _gilView.rend();
281 template <
typename PixelT>
283 return _gilView.at(
x,
y);
286 template <
typename PixelT>
291 if (!this->isContiguous()) {
298 template <
typename PixelT>
303 if (!this->isContiguous()) {
307 return row_end(getHeight() - 1);
310 template <
typename PixelT>
312 fill_pixels(_gilView, rhs);
320 template <
typename PixelT>
323 *
this = initialValue;
326 template <
typename PixelT>
329 *
this = initialValue;
332 template <
typename PixelT>
334 *
this = initialValue;
337 template <
typename PixelT>
340 template <
typename PixelT>
343 template <
typename PixelT>
348 template <
typename PixelT>
355 template <
typename PixelT>
362 template <
typename PixelT>
369 template <
typename PixelT>
373 *
this = reader.read<PixelT>(
bbox, origin, allowUnsafe);
375 metadata->combine(reader.readMetadata());
379 template <
typename PixelT>
384 *
this = reader.
read<PixelT>(
bbox, origin, allowUnsafe);
390 template <
typename PixelT>
393 ImageFitsReader reader(&fitsFile);
394 *
this = reader.read<PixelT>(
bbox, origin, allowUnsafe);
396 metadata->combine(reader.readMetadata());
400 template <
typename PixelT>
401 void Image<PixelT>::writeFits(
std::string const& fileName,
404 fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
405 writeFits(fitsfile, metadata_i);
408 template <
typename PixelT>
409 void Image<PixelT>::writeFits(fits::MemFileManager& manager,
412 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
413 writeFits(fitsfile, metadata_i);
416 template <
typename PixelT>
417 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
419 fitsfile.writeImage(*
this, fits::ImageWriteOptions(*
this), metadata);
422 template <
typename PixelT>
423 void Image<PixelT>::writeFits(
std::string const& filename, fits::ImageWriteOptions
const& options,
426 fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
427 writeFits(fitsfile, options, header,
mask);
430 template <
typename PixelT>
431 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions
const& options,
434 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
435 writeFits(fitsfile, options, header,
mask);
438 template <
typename PixelT>
439 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions
const& options,
442 fitsfile.writeImage(*
this, options, header,
mask);
447 template <
typename PixelT>
454 template <
typename PixelT>
460 template <
typename PixelT>
462 transform_pixels(_getRawView(), _getRawView(),
463 [](PixelT
const& l) -> PixelT {
return static_cast<PixelT
>(
std::sqrt(l)); });
466 template <
typename PixelT>
468 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l + rhs; });
472 template <
typename PixelT>
476 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
480 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
481 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l + r; });
485 template <
typename PixelT>
487 for (
int y = 0;
y != this->getHeight(); ++
y) {
492 *ptr +=
function(xPos, yPos);
498 template <
typename PixelT>
502 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
508 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l +
static_cast<PixelT
>(c * r); });
511 template <
typename PixelT>
513 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l - rhs; });
517 template <
typename PixelT>
521 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
525 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
526 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l - r; });
530 template <
typename PixelT>
534 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
540 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l -
static_cast<PixelT
>(c * r); });
543 template <
typename PixelT>
545 for (
int y = 0;
y != this->getHeight(); ++
y) {
550 *ptr -=
function(xPos, yPos);
556 template <
typename PixelT>
558 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l * rhs; });
562 template <
typename PixelT>
566 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
570 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
571 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l * r; });
575 template <
typename PixelT>
579 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
585 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l *
static_cast<PixelT
>(c * r); });
588 template <
typename PixelT>
590 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l / rhs; });
598 double const irhs = 1 / rhs;
605 float const irhs = 1 / rhs;
610 template <
typename PixelT>
614 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
618 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
619 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l / r; });
623 template <
typename PixelT>
627 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
633 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l /
static_cast<PixelT
>(c * r); });
640 template <
typename LhsPixelT,
typename RhsPixelT>
641 struct plusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
642 LhsPixelT
operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
643 return static_cast<LhsPixelT
>(lhs + rhs);
647 template <
typename LhsPixelT,
typename RhsPixelT>
648 struct minusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
649 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
650 return static_cast<LhsPixelT
>(lhs - rhs);
654 template <
typename LhsPixelT,
typename RhsPixelT>
655 struct timesEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
656 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
657 return static_cast<LhsPixelT
>(lhs * rhs);
661 template <
typename LhsPixelT,
typename RhsPixelT>
662 struct divideEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
663 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
664 return static_cast<LhsPixelT
>(lhs / rhs);
669 template <
typename LhsPixelT,
typename RhsPixelT>
675 template <
typename LhsPixelT,
typename RhsPixelT>
681 template <
typename LhsPixelT,
typename RhsPixelT>
687 template <
typename LhsPixelT,
typename RhsPixelT>
695 if (metadata.
exists(
"ZNAXIS1") && metadata.
exists(
"ZNAXIS2")) {
704 template <
typename T1,
typename T2>
715 auto beg1Addr = arr1.front().begin();
716 auto end1Addr = arr1.back().end();
719 auto beg2Addr = arr2.front().begin();
720 auto end2Addr = arr2.back().end();
723 return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
730 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
731 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
732 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
733 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
734 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
735 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
737 #define INSTANTIATE(T) \
738 template class ImageBase<T>; \
739 template class Image<T>; \
740 INSTANTIATE_OPERATOR(+=, T); \
741 INSTANTIATE_OPERATOR(-=, T); \
742 INSTANTIATE_OPERATOR(*=, T); \
743 INSTANTIATE_OPERATOR(/=, T)
745 #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.
int getArea() const
Return the area 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.
A Function taking two arguments.
void swap(PolymorphicValue &lhs, PolymorphicValue &rhs) noexcept
Swap specialization for PolymorphicValue.
int getAsInt(std::string const &name) const
bool exists(std::string const &name) const
void swap(CameraSys &a, CameraSys &b)
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)
double indexToPosition(double ind)
Convert image index to image position.
bool imagesOverlap(ImageBase< T1 > const &image1, ImageBase< T2 > const &image2)
Return true if the pixels for two images or masks overlap in memory.
FilterProperty & operator=(FilterProperty const &)=default
void swap(Image< PixelT > &a, Image< PixelT > &b)
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
void operator/=(ExtentBase< int, N > &lhs, double rhs) noexcept
void operator*=(ExtentBase< int, N > &lhs, double rhs) noexcept
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()
virtual LhsT operator()(LhsT lhs, RhsT rhs) const =0