lsst.afw  22.0.1-29-g184b6e44e+8b185d4e2d
Image.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008-2016 AURA/LSST.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 /*
26  * Implementation for ImageBase and Image
27  */
28 #include <cstdint>
29 #include <iostream>
30 #include <functional>
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 
38 #include "boost/version.hpp"
39 #if BOOST_VERSION < 106900
40 #include "boost/gil/gil_all.hpp"
41 #else
42 #include "boost/gil.hpp"
43 #endif
44 
45 #include "lsst/pex/exceptions.h"
46 #include "lsst/afw/geom/wcsUtils.h"
47 #include "lsst/afw/image/Image.h"
49 #include "lsst/afw/fits.h"
51 
52 namespace lsst {
53 namespace afw {
54 namespace image {
55 
56 template <typename PixelT>
57 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
58  Manager::Ptr& manager) {
59  if (dimensions.getX() < 0 || dimensions.getY() < 0) {
61  str(boost::format("Both width and height must be non-negative: %d, %d") %
62  dimensions.getX() % dimensions.getY()));
63  }
64  if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
66  str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
67  dimensions.getX() % dimensions.getY()));
68  }
70  ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
71  manager = r.first;
72  return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
73  (typename _view_t::value_type*)r.second,
74  dimensions.getX() * sizeof(PixelT));
75 }
76 template <typename PixelT>
77 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
78  lsst::geom::Extent2I const& offset,
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()) {
82  throw LSST_EXCEPT(
84  (boost::format(
85  "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
86  offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
87  view.height())
88  .str());
89  }
90  if (dimensions.getX() == 0 && dimensions.getY() == 0
91  && view.width() == 0 && view.height() == 0) {
92  // Getting a zero-extent subview of a zero-extent view returns itself
93  return view;
94  } else {
95  return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
96  dimensions.getY());
97  }
98 }
99 
100 template <typename PixelT>
102  : _origin(0, 0), _manager(), _gilView(_allocateView(dimensions, _manager)) {}
103 
104 template <typename PixelT>
106  : _origin(bbox.getMin()), _manager(), _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
107 
108 template <typename PixelT>
109 ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
110 
111  )
112  : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
113  if (deep) {
114  ImageBase tmp(getBBox());
115  tmp.assign(*this); // now copy the pixels
116  swap(tmp);
117  }
118 }
119 // Delegate to copy-constructor for backwards compatibility
120 template <typename PixelT>
122 
123 template <typename PixelT>
125  bool const deep
126 
127  )
128  : _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
129  _manager(rhs._manager), // reference counted pointer, don't copy pixels
130  _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
131  if (deep) {
132  ImageBase tmp(getBBox());
133  tmp.assign(*this); // now copy the pixels
134  swap(tmp);
135  }
136 }
137 
138 template <typename PixelT>
139 ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
140  : _origin(xy0),
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))) {
145  if (deep) {
146  ImageBase tmp(*this, true);
147  swap(tmp);
148  }
149 }
150 
151 template <typename PixelT>
153  ImageBase tmp(rhs);
154  swap(tmp); // See Meyers, Effective C++, Item 11
155 
156  return *this;
157 }
158 // Delegate to copy-assignment for backwards compatibility
159 template <typename PixelT>
161  return *this = rhs;
162 }
163 
164 template <typename PixelT>
166  auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
167  if (lhsDim != rhs.getDimensions()) {
169  (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
170  lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
171  .str());
172  }
173  if (bbox.isEmpty()) {
174  copy_pixels(rhs._gilView, _gilView);
175  } else {
176  auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
177  auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
178  copy_pixels(rhs._gilView, lhsGilView);
179  }
180 }
181 
182 template <typename PixelT>
184  return const_cast<typename ImageBase<PixelT>::PixelReference>(
185  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
186 }
187 
188 template <typename PixelT>
190  CheckIndices const& check) {
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))
195  .str());
196  }
197 
198  return const_cast<typename ImageBase<PixelT>::PixelReference>(
199  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
200 }
201 
202 template <typename PixelT>
204  return _gilView(x, y)[0];
205 }
206 
207 template <typename PixelT>
209  int x, int y, CheckIndices const& check) const {
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))
214  .str());
215  }
216 
217  return _gilView(x, y)[0];
218 }
219 
220 template <typename PixelT>
222  ImageOrigin origin) {
223  int x = index.getX();
224  int y = index.getY();
225  if (origin == PARENT) {
226  x -= getX0();
227  y -= getY0();
228  }
229  return _gilView(x, y)[0];
230 }
231 
232 template <typename PixelT>
234  ImageOrigin origin) const {
235  int x = index.getX();
236  int y = index.getY();
237  if (origin == PARENT) {
238  x -= getX0();
239  y -= getY0();
240  }
241  return _gilView(x, y)[0];
242 }
243 
244 template <typename PixelT>
246  using std::swap; // See Meyers, Effective C++, Item 25
247 
248  swap(_manager, rhs._manager); // just swapping the pointers
249  swap(_gilView, rhs._gilView);
250  swap(_origin, rhs._origin);
251 }
252 
253 template <typename PixelT>
255  a.swap(b);
256 }
257 
258 //
259 // Iterators
260 //
261 template <typename PixelT>
263  return _gilView.begin();
264 }
265 
266 template <typename PixelT>
268  return _gilView.end();
269 }
270 
271 template <typename PixelT>
273  return _gilView.rbegin();
274 }
275 
276 template <typename PixelT>
278  return _gilView.rend();
279 }
280 
281 template <typename PixelT>
283  return _gilView.at(x, y);
284 }
285 
286 template <typename PixelT>
288  if (!contiguous) {
289  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
290  }
291  if (!this->isContiguous()) {
292  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
293  }
294 
295  return row_begin(0);
296 }
297 
298 template <typename PixelT>
300  if (!contiguous) {
301  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
302  }
303  if (!this->isContiguous()) {
304  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
305  }
306 
307  return row_end(getHeight() - 1);
308 }
309 
310 template <typename PixelT>
312  fill_pixels(_gilView, rhs);
313 
314  return *this;
315 }
316 
317 //
318 // On to Image itself. ctors, cctors, and operator=
319 //
320 template <typename PixelT>
321 Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
322  : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
323  *this = initialValue;
324 }
325 
326 template <typename PixelT>
328  : ImageBase<PixelT>(dimensions) {
329  *this = initialValue;
330 }
331 
332 template <typename PixelT>
333 Image<PixelT>::Image(lsst::geom::Box2I const& bbox, PixelT initialValue) : ImageBase<PixelT>(bbox) {
334  *this = initialValue;
335 }
336 
337 template <typename PixelT>
338 Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
339 // Delegate to copy-constructor for backwards compatibility
340 template <typename PixelT>
341 Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
342 
343 template <typename PixelT>
345  bool const deep)
346  : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
347 
348 template <typename PixelT>
350  this->ImageBase<PixelT>::operator=(rhs);
351 
352  return *this;
353 }
354 
355 template <typename PixelT>
358 
359  return *this;
360 }
361 // Delegate to copy-assignment for backwards compatibility
362 template <typename PixelT>
364  return *this = rhs;
365 }
366 
367 #ifndef DOXYGEN // doc for this section has been moved to header
368 
369 template <typename PixelT>
371  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe) {
372  ImageFitsReader reader(fileName, hdu);
373  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
374  if (metadata) {
375  metadata->combine(reader.readMetadata());
376  }
377 }
378 
379 template <typename PixelT>
380 Image<PixelT>::Image(fits::MemFileManager& manager, int const hdu,
382  ImageOrigin const origin, bool allowUnsafe) {
383  ImageFitsReader reader(manager, hdu);
384  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
385  if (metadata) {
386  metadata->combine(reader.readMetadata());
387  }
388 }
389 
390 template <typename PixelT>
391 Image<PixelT>::Image(fits::Fits& fitsFile, std::shared_ptr<daf::base::PropertySet> metadata,
392  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe) {
393  ImageFitsReader reader(&fitsFile);
394  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
395  if (metadata) {
396  metadata->combine(reader.readMetadata());
397  }
398 }
399 
400 template <typename PixelT>
401 void Image<PixelT>::writeFits(std::string const& fileName,
403  std::string const& mode) const {
404  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
405  writeFits(fitsfile, metadata_i);
406 }
407 
408 template <typename PixelT>
409 void Image<PixelT>::writeFits(fits::MemFileManager& manager,
411  std::string const& mode) const {
412  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
413  writeFits(fitsfile, metadata_i);
414 }
415 
416 template <typename PixelT>
417 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
419  fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
420 }
421 
422 template <typename PixelT>
423 void Image<PixelT>::writeFits(std::string const& filename, fits::ImageWriteOptions const& options,
425  std::shared_ptr<Mask<MaskPixel> const> mask) const {
426  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
427  writeFits(fitsfile, options, header, mask);
428 }
429 
430 template <typename PixelT>
431 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions const& options,
433  std::shared_ptr<Mask<MaskPixel> const> mask) const {
434  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
435  writeFits(fitsfile, options, header, mask);
436 }
437 
438 template <typename PixelT>
439 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
441  std::shared_ptr<Mask<MaskPixel> const> mask) const {
442  fitsfile.writeImage(*this, options, header, mask);
443 }
444 
445 #endif // !DOXYGEN
446 
447 template <typename PixelT>
449  using std::swap; // See Meyers, Effective C++, Item 25
451  ; // no private variables to swap
452 }
453 
454 template <typename PixelT>
456  a.swap(b);
457 }
458 
459 // In-place, per-pixel, sqrt().
460 template <typename PixelT>
462  transform_pixels(_getRawView(), _getRawView(),
463  [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
464 }
465 
466 template <typename PixelT>
468  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
469  return *this;
470 }
471 
472 template <typename PixelT>
474  if (this->getDimensions() != rhs.getDimensions()) {
476  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
477  this->getHeight() % rhs.getWidth() % rhs.getHeight())
478  .str());
479  }
480  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
481  [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
482  return *this;
483 }
484 
485 template <typename PixelT>
487  for (int y = 0; y != this->getHeight(); ++y) {
488  double const yPos = this->indexToPosition(y, Y);
489  double xPos = this->indexToPosition(0, X);
490  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
491  ++ptr, ++xPos) {
492  *ptr += function(xPos, yPos);
493  }
494  }
495  return *this;
496 }
497 
498 template <typename PixelT>
499 void Image<PixelT>::scaledPlus(double const c, Image<PixelT> const& rhs) {
500  if (this->getDimensions() != rhs.getDimensions()) {
502  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
503  this->getHeight() % rhs.getWidth() % rhs.getHeight())
504  .str());
505  }
506  transform_pixels(
507  _getRawView(), rhs._getRawView(), _getRawView(),
508  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + static_cast<PixelT>(c * r); });
509 }
510 
511 template <typename PixelT>
513  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
514  return *this;
515 }
516 
517 template <typename PixelT>
519  if (this->getDimensions() != rhs.getDimensions()) {
521  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
522  this->getHeight() % rhs.getWidth() % rhs.getHeight())
523  .str());
524  }
525  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
526  [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
527  return *this;
528 }
529 
530 template <typename PixelT>
531 void Image<PixelT>::scaledMinus(double const c, Image<PixelT> const& rhs) {
532  if (this->getDimensions() != rhs.getDimensions()) {
534  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
535  this->getHeight() % rhs.getWidth() % rhs.getHeight())
536  .str());
537  }
538  transform_pixels(
539  _getRawView(), rhs._getRawView(), _getRawView(),
540  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - static_cast<PixelT>(c * r); });
541 }
542 
543 template <typename PixelT>
545  for (int y = 0; y != this->getHeight(); ++y) {
546  double const yPos = this->indexToPosition(y, Y);
547  double xPos = this->indexToPosition(0, X);
548  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
549  ++ptr, ++xPos) {
550  *ptr -= function(xPos, yPos);
551  }
552  }
553  return *this;
554 }
555 
556 template <typename PixelT>
558  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
559  return *this;
560 }
561 
562 template <typename PixelT>
564  if (this->getDimensions() != rhs.getDimensions()) {
566  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
567  this->getHeight() % rhs.getWidth() % rhs.getHeight())
568  .str());
569  }
570  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
571  [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
572  return *this;
573 }
574 
575 template <typename PixelT>
576 void Image<PixelT>::scaledMultiplies(double const c, Image<PixelT> const& rhs) {
577  if (this->getDimensions() != rhs.getDimensions()) {
579  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
580  this->getHeight() % rhs.getWidth() % rhs.getHeight())
581  .str());
582  }
583  transform_pixels(
584  _getRawView(), rhs._getRawView(), _getRawView(),
585  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * static_cast<PixelT>(c * r); });
586 }
587 
588 template <typename PixelT>
590  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
591  return *this;
592 }
593 //
594 // Specialize float and double for efficiency
595 //
596 template <>
598  double const irhs = 1 / rhs;
599  *this *= irhs;
600  return *this;
601 }
602 
603 template <>
605  float const irhs = 1 / rhs;
606  *this *= irhs;
607  return *this;
608 }
609 
610 template <typename PixelT>
612  if (this->getDimensions() != rhs.getDimensions()) {
614  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
615  this->getHeight() % rhs.getWidth() % rhs.getHeight())
616  .str());
617  }
618  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
619  [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
620  return *this;
621 }
622 
623 template <typename PixelT>
624 void Image<PixelT>::scaledDivides(double const c, Image<PixelT> const& rhs) {
625  if (this->getDimensions() != rhs.getDimensions()) {
627  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
628  this->getHeight() % rhs.getWidth() % rhs.getHeight())
629  .str());
630  }
631  transform_pixels(
632  _getRawView(), rhs._getRawView(), _getRawView(),
633  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / static_cast<PixelT>(c * r); });
634 }
635 
636 namespace {
637 /*
638  * Worker routine for manipulating images;
639  */
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);
644  }
645 };
646 
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);
651  }
652 };
653 
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);
658  }
659 };
660 
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);
665  }
666 };
667 } // namespace
668 
669 template <typename LhsPixelT, typename RhsPixelT>
671  for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
672  return lhs;
673 }
674 
675 template <typename LhsPixelT, typename RhsPixelT>
677  for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
678  return lhs;
679 }
680 
681 template <typename LhsPixelT, typename RhsPixelT>
683  for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
684  return lhs;
685 }
686 
687 template <typename LhsPixelT, typename RhsPixelT>
689  for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
690  return lhs;
691 }
692 
695  if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
696  dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
697  } else {
698  dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
699  }
701  return lsst::geom::Box2I(xy0, dims);
702 }
703 
704 template <typename T1, typename T2>
705 bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
706 
707  if (image1.getArea() == 0 || image2.getArea() == 0) {
708  // zero-area images cannot overlap.
709  return false;
710  }
711 
712  auto arr1 = image1.getArray();
713  // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
714  // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
715  auto beg1Addr = arr1.front().begin();
716  auto end1Addr = arr1.back().end();
717 
718  auto arr2 = image2.getArray();
719  auto beg2Addr = arr2.front().begin();
720  auto end2Addr = arr2.back().end();
721 
722  auto ptrLess = std::less<void const* const>();
723  return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
724 }
725 
726 //
727 // Explicit instantiations
728 //
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);
736 
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)
744 
745 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
746 
748 INSTANTIATE(int);
749 INSTANTIATE(float);
750 INSTANTIATE(double);
752 
756 INSTANTIATE2(std::uint16_t, double);
758 
760 INSTANTIATE2(int, int);
761 INSTANTIATE2(int, float);
762 INSTANTIATE2(int, double);
764 
766 INSTANTIATE2(float, int);
767 INSTANTIATE2(float, float);
768 INSTANTIATE2(float, double);
770 
771 INSTANTIATE2(double, std::uint16_t);
772 INSTANTIATE2(double, int);
773 INSTANTIATE2(double, float);
774 INSTANTIATE2(double, double);
775 INSTANTIATE2(double, std::uint64_t);
776 
780 INSTANTIATE2(std::uint64_t, double);
782 
784 } // namespace image
785 } // namespace afw
786 } // namespace lsst
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
int end
double x
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:484
#define LSST_EXCEPT(type,...)
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:49
afw::table::Key< afw::table::Array< MaskPixelT > > mask
#define INSTANTIATE2(ImagePixelT1, ImagePixelT2)
Definition: MaskedImage.cc:694
int y
Definition: SpanSet.cc:49
table::Key< int > b
table::Key< int > a
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
A class used to request that array accesses be checked.
Definition: ImageBase.h:74
std::shared_ptr< daf::base::PropertyList > readMetadata()
Read the image's FITS header.
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: ImageBase.h:102
iterator end() const
Return an STL compliant iterator to the end of the image.
Definition: Image.cc:267
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:262
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:57
typename Reference< PixelT >::type PixelReference
A Reference to a PixelT.
Definition: ImageBase.h:117
typename _view_t::iterator iterator
An STL compliant iterator.
Definition: ImageBase.h:125
PixelReference operator()(int x, int y)
Return a reference to the pixel (x, y) in LOCAL coordinates.
Definition: Image.cc:183
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
Definition: Image.cc:77
int getWidth() const
Return the number of columns in the image.
Definition: ImageBase.h:294
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition: ImageBase.h:445
int getArea() const
Return the area of the image.
Definition: ImageBase.h:298
lsst::geom::Extent2I getDimensions() const
Return the image's size; useful for passing to constructors.
Definition: ImageBase.h:356
typename ndarray::Array< PixelT, 2, 1 > Array
A mutable ndarray representation of the image.
Definition: ImageBase.h:149
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.
Definition: Image.cc:165
x_iterator fast_iterator
A fast STL compliant iterator for contiguous images N.b.
Definition: ImageBase.h:137
typename _view_t::reverse_iterator reverse_iterator
An STL compliant reverse iterator.
Definition: ImageBase.h:129
int getHeight() const
Return the number of rows in the image.
Definition: ImageBase.h:296
ImageBase & operator=(const ImageBase &rhs)
Shallow assignment operator.
Definition: Image.cc:152
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:282
typename _view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
reverse_iterator rbegin() const
Return an STL compliant reverse iterator to the start of the image.
Definition: Image.cc:272
_view_t _getRawView() const
Definition: ImageBase.h:465
PixelReference get(lsst::geom::Point2I const &index, ImageOrigin origin)
Return a reference to a single pixel (with no bounds check).
Definition: Image.cc:221
void swap(ImageBase &rhs)
Definition: Image.cc:245
typename ConstReference< PixelT >::type PixelConstReference
A ConstReference to a PixelT.
Definition: ImageBase.h:119
reverse_iterator rend() const
Return an STL compliant reverse iterator to the end of the image.
Definition: Image.cc:277
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.
Definition: Image.h:58
friend class Image
Definition: Image.h:72
A Function taking two arguments.
Definition: Function.h:259
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)
Definition: CameraSys.h:157
lsst::geom::Point2I getImageXY0FromMetadata(daf::base::PropertySet &metadata, std::string const &wcsName, bool strip=false)
Definition: wcsUtils.cc:98
std::string const wcsNameForXY0
Definition: ImageBase.h:70
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.
Definition: Image.cc:670
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.
Definition: Image.cc:676
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)
Definition: Image.cc:693
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:55
bool imagesOverlap(ImageBase< T1 > const &image1, ImageBase< T2 > const &image2)
Return true if the pixels for two images or masks overlap in memory.
Definition: Image.cc:705
FilterProperty & operator=(FilterProperty const &)=default
void swap(Image< PixelT > &a, Image< PixelT > &b)
Definition: Image.cc:455
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.
T sqrt(T... args)
A functor class equivalent to std::function<LhsT (LhsT, RhsT)>, but with a virtual operator()
virtual LhsT operator()(LhsT lhs, RhsT rhs) const =0
T swap(T... args)