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>
362 #ifndef DOXYGEN // doc for this section has been moved to header
364 template <
typename PixelT>
374 template <
typename PixelT>
385 template <
typename PixelT>
395 template <
typename PixelT>
399 fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
400 writeFits(fitsfile, metadata_i);
403 template <
typename PixelT>
407 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
408 writeFits(fitsfile, metadata_i);
411 template <
typename PixelT>
412 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
414 fitsfile.writeImage(*
this, fits::ImageWriteOptions(*
this), metadata);
417 template <
typename PixelT>
418 void Image<PixelT>::writeFits(
std::string const& filename, fits::ImageWriteOptions
const& options,
421 fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
422 writeFits(fitsfile, options, header,
mask);
425 template <
typename PixelT>
426 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions
const& options,
429 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
430 writeFits(fitsfile, options, header,
mask);
433 template <
typename PixelT>
434 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions
const& options,
437 fitsfile.writeImage(*
this, options, header,
mask);
442 template <
typename PixelT>
449 template <
typename PixelT>
455 template <
typename PixelT>
457 transform_pixels(_getRawView(), _getRawView(),
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(),
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() %
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(),
525 template <
typename PixelT>
529 (
boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
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(),
570 template <
typename PixelT>
574 (
boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
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(),
618 template <
typename PixelT>
622 (
boost::format(
"Images are of different size, %dx%d v %dx%d") % this->getWidth() %
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&);