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>
165 template <
typename PixelT>
167 auto lhsDim =
bbox.isEmpty() ? getDimensions() :
bbox.getDimensions();
170 (boost::format(
"Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
174 if (
bbox.isEmpty()) {
175 copy_pixels(rhs._gilView, _gilView);
178 auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
179 copy_pixels(rhs._gilView, lhsGilView);
183 template <
typename PixelT>
189 template <
typename PixelT>
192 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
194 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
195 (getWidth() - 1) % (getHeight() - 1))
203 template <
typename PixelT>
205 return _gilView(
x,
y)[0];
208 template <
typename PixelT>
211 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
213 (boost::format(
"Index (%d, %d) is out of range [0--%d], [0--%d]") %
x %
y %
214 (this->getWidth() - 1) % (this->getHeight() - 1))
218 return _gilView(
x,
y)[0];
221 template <
typename PixelT>
224 int x = index.getX();
225 int y = index.getY();
230 return _gilView(
x,
y)[0];
233 template <
typename PixelT>
236 int x = index.getX();
237 int y = index.getY();
242 return _gilView(
x,
y)[0];
245 template <
typename PixelT>
249 swap(_manager, rhs._manager);
250 swap(_gilView, rhs._gilView);
251 swap(_origin, rhs._origin);
254 template <
typename PixelT>
262 template <
typename PixelT>
264 return _gilView.
begin();
267 template <
typename PixelT>
269 return _gilView.end();
272 template <
typename PixelT>
277 template <
typename PixelT>
279 return _gilView.
rend();
282 template <
typename PixelT>
284 return _gilView.
at(
x,
y);
287 template <
typename PixelT>
292 if (!this->isContiguous()) {
299 template <
typename PixelT>
304 if (!this->isContiguous()) {
308 return row_end(getHeight() - 1);
311 template <
typename PixelT>
313 fill_pixels(_gilView, rhs);
321 template <
typename PixelT>
324 *
this = initialValue;
327 template <
typename PixelT>
330 *
this = initialValue;
333 template <
typename PixelT>
335 *
this = initialValue;
338 template <
typename PixelT>
341 template <
typename PixelT>
344 template <
typename PixelT>
349 template <
typename PixelT>
356 template <
typename PixelT>
363 template <
typename PixelT>
368 #ifndef DOXYGEN // doc for this section has been moved to header
370 template <
typename PixelT>
374 *
this = reader.read<PixelT>(
bbox, origin, allowUnsafe);
376 metadata->combine(reader.readMetadata());
380 template <
typename PixelT>
381 Image<PixelT>::Image(fits::MemFileManager& manager,
int const hdu,
384 ImageFitsReader reader(manager, hdu);
385 *
this = reader.read<PixelT>(
bbox, origin, allowUnsafe);
387 metadata->combine(reader.readMetadata());
391 template <
typename PixelT>
394 ImageFitsReader reader(&fitsFile);
395 *
this = reader.read<PixelT>(
bbox, origin, allowUnsafe);
397 metadata->combine(reader.readMetadata());
401 template <
typename PixelT>
402 void Image<PixelT>::writeFits(
std::string const& fileName,
405 fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
406 writeFits(fitsfile, metadata_i);
409 template <
typename PixelT>
410 void Image<PixelT>::writeFits(fits::MemFileManager& manager,
413 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
414 writeFits(fitsfile, metadata_i);
417 template <
typename PixelT>
418 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
420 fitsfile.writeImage(*
this, fits::ImageWriteOptions(*
this), metadata);
423 template <
typename PixelT>
424 void Image<PixelT>::writeFits(
std::string const& filename, fits::ImageWriteOptions
const& options,
427 fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
428 writeFits(fitsfile, options, header,
mask);
431 template <
typename PixelT>
432 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions
const& options,
435 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
436 writeFits(fitsfile, options, header,
mask);
439 template <
typename PixelT>
440 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions
const& options,
443 fitsfile.writeImage(*
this, options, header,
mask);
448 template <
typename PixelT>
455 template <
typename PixelT>
461 template <
typename PixelT>
463 transform_pixels(_getRawView(), _getRawView(),
464 [](PixelT
const& l) -> PixelT {
return static_cast<PixelT>(
std::sqrt(l)); });
467 template <
typename PixelT>
469 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l + rhs; });
473 template <
typename PixelT>
477 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
481 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
482 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l + r; });
486 template <
typename PixelT>
488 for (
int y = 0;
y != this->getHeight(); ++
y) {
493 *ptr +=
function(xPos, yPos);
499 template <
typename PixelT>
503 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
509 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l + static_cast<PixelT>(c * r); });
512 template <
typename PixelT>
514 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l - rhs; });
518 template <
typename PixelT>
522 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
526 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
527 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l - r; });
531 template <
typename PixelT>
535 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
541 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l - static_cast<PixelT>(c * r); });
544 template <
typename PixelT>
546 for (
int y = 0;
y != this->getHeight(); ++
y) {
551 *ptr -=
function(xPos, yPos);
557 template <
typename PixelT>
559 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l * rhs; });
563 template <
typename PixelT>
567 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
571 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
572 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l * r; });
576 template <
typename PixelT>
580 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
586 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l * static_cast<PixelT>(c * r); });
589 template <
typename PixelT>
591 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT
const& l) -> PixelT {
return l / rhs; });
599 double const irhs = 1 / rhs;
606 float const irhs = 1 / rhs;
611 template <
typename PixelT>
615 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
619 transform_pixels(_getRawView(), rhs.
_getRawView(), _getRawView(),
620 [](PixelT
const& l, PixelT
const& r) -> PixelT {
return l / r; });
624 template <
typename PixelT>
628 (boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
634 [&c](PixelT
const& l, PixelT
const& r) -> PixelT {
return l / static_cast<PixelT>(c * r); });
641 template <
typename LhsPixelT,
typename RhsPixelT>
642 struct plusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
643 LhsPixelT
operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
644 return static_cast<LhsPixelT>(lhs + rhs);
648 template <
typename LhsPixelT,
typename RhsPixelT>
649 struct minusEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
650 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
651 return static_cast<LhsPixelT>(lhs - rhs);
655 template <
typename LhsPixelT,
typename RhsPixelT>
656 struct timesEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
657 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
658 return static_cast<LhsPixelT>(lhs * rhs);
662 template <
typename LhsPixelT,
typename RhsPixelT>
663 struct divideEq :
public pixelOp2<LhsPixelT, RhsPixelT> {
664 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs)
const override {
665 return static_cast<LhsPixelT>(lhs / rhs);
670 template <
typename LhsPixelT,
typename RhsPixelT>
676 template <
typename LhsPixelT,
typename RhsPixelT>
682 template <
typename LhsPixelT,
typename RhsPixelT>
688 template <
typename LhsPixelT,
typename RhsPixelT>
696 if (metadata.
exists(
"ZNAXIS1") && metadata.
exists(
"ZNAXIS2")) {
705 template <
typename T1,
typename T2>
710 auto beg1Addr = arr1.front().begin();
711 auto end1Addr = arr1.back().end();
714 auto beg2Addr = arr2.front().begin();
715 auto end2Addr = arr2.back().end();
718 return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
725 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
726 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
727 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
728 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
729 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
730 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
732 #define INSTANTIATE(T) \
733 template class ImageBase<T>; \
734 template class Image<T>; \
735 INSTANTIATE_OPERATOR(+=, T); \
736 INSTANTIATE_OPERATOR(-=, T); \
737 INSTANTIATE_OPERATOR(*=, T); \
738 INSTANTIATE_OPERATOR(/=, T)
740 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);