LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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 <functional>
30 #include "boost/format.hpp"
31 #include "boost/gil.hpp"
32 
33 #include "lsst/pex/exceptions.h"
34 #include "lsst/afw/geom/wcsUtils.h"
35 #include "lsst/afw/image/Image.h"
37 #include "lsst/afw/fits.h"
39 
40 namespace lsst {
41 namespace afw {
42 namespace image {
43 
44 template <typename PixelT>
45 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
46  Manager::Ptr& manager) {
47  if (dimensions.getX() < 0 || dimensions.getY() < 0) {
49  str(boost::format("Both width and height must be non-negative: %d, %d") %
50  dimensions.getX() % dimensions.getY()));
51  }
52  if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
54  str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
55  dimensions.getX() % dimensions.getY()));
56  }
58  ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
59  manager = r.first;
60  return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
61  (typename _view_t::value_type*)r.second,
62  dimensions.getX() * sizeof(PixelT));
63 }
64 template <typename PixelT>
65 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
66  lsst::geom::Extent2I const& offset,
67  const _view_t& view) {
68  if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() + dimensions.getX() > view.width() ||
69  offset.getY() + dimensions.getY() > view.height()) {
70  throw LSST_EXCEPT(
73  "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
74  offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
75  view.height())
76  .str());
77  }
78  if (dimensions.getX() == 0 && dimensions.getY() == 0
79  && view.width() == 0 && view.height() == 0) {
80  // Getting a zero-extent subview of a zero-extent view returns itself
81  return view;
82  } else {
83  return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
84  dimensions.getY());
85  }
86 }
87 
88 template <typename PixelT>
90  : _origin(0, 0), _manager(), _gilView(_allocateView(dimensions, _manager)) {}
91 
92 template <typename PixelT>
94  : _origin(bbox.getMin()), _manager(), _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
95 
96 template <typename PixelT>
97 ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
98 
99  )
100  : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
101  if (deep) {
102  ImageBase tmp(getBBox());
103  tmp.assign(*this); // now copy the pixels
104  swap(tmp);
105  }
106 }
107 // Delegate to copy-constructor for backwards compatibility
108 template <typename PixelT>
110 
111 template <typename PixelT>
113  bool const deep
114 
115  )
116  : _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
117  _manager(rhs._manager), // reference counted pointer, don't copy pixels
118  _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
119  if (deep) {
121  tmp.assign(*this); // now copy the pixels
122  swap(tmp);
123  }
124 }
125 
126 template <typename PixelT>
127 ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
128  : _origin(xy0),
129  _manager(array.getManager()),
130  _gilView(boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
131  (typename _view_t::value_type*)array.getData(),
132  array.template getStride<0>() * sizeof(PixelT))) {
133  if (deep) {
134  ImageBase tmp(*this, true);
135  swap(tmp);
136  }
137 }
138 
139 template <typename PixelT>
141  ImageBase tmp(rhs);
142  swap(tmp); // See Meyers, Effective C++, Item 11
143 
144  return *this;
145 }
146 // Delegate to copy-assignment for backwards compatibility
147 template <typename PixelT>
149  return *this = rhs;
150 }
151 
152 template <typename PixelT>
154  auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
155  if (lhsDim != rhs.getDimensions()) {
157  (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
158  lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
159  .str());
160  }
161  if (bbox.isEmpty()) {
162  copy_pixels(rhs._gilView, _gilView);
163  } else {
164  auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
165  auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
166  copy_pixels(rhs._gilView, lhsGilView);
167  }
168 }
169 
170 template <typename PixelT>
172  return const_cast<typename ImageBase<PixelT>::PixelReference>(
173  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
174 }
175 
176 template <typename PixelT>
178  CheckIndices const& check) {
179  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
181  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
182  (getWidth() - 1) % (getHeight() - 1))
183  .str());
184  }
185 
186  return const_cast<typename ImageBase<PixelT>::PixelReference>(
187  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
188 }
189 
190 template <typename PixelT>
192  return _gilView(x, y)[0];
193 }
194 
195 template <typename PixelT>
197  int x, int y, CheckIndices const& check) const {
198  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
200  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
201  (this->getWidth() - 1) % (this->getHeight() - 1))
202  .str());
203  }
204 
205  return _gilView(x, y)[0];
206 }
207 
208 template <typename PixelT>
210  ImageOrigin origin) {
211  int x = index.getX();
212  int y = index.getY();
213  if (origin == PARENT) {
214  x -= getX0();
215  y -= getY0();
216  }
217  return _gilView(x, y)[0];
218 }
219 
220 template <typename PixelT>
222  ImageOrigin origin) const {
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  using std::swap; // See Meyers, Effective C++, Item 25
235 
236  swap(_manager, rhs._manager); // just swapping the pointers
237  swap(_gilView, rhs._gilView);
238  swap(_origin, rhs._origin);
239 }
240 
241 template <typename PixelT>
243  a.swap(b);
244 }
245 
246 //
247 // Iterators
248 //
249 template <typename PixelT>
251  return _gilView.begin();
252 }
253 
254 template <typename PixelT>
256  return _gilView.end();
257 }
258 
259 template <typename PixelT>
261  return _gilView.rbegin();
262 }
263 
264 template <typename PixelT>
266  return _gilView.rend();
267 }
268 
269 template <typename PixelT>
271  return _gilView.at(x, y);
272 }
273 
274 template <typename PixelT>
276  if (!contiguous) {
277  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
278  }
279  if (!this->isContiguous()) {
280  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
281  }
282 
283  return row_begin(0);
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_end(getHeight() - 1);
296 }
297 
298 template <typename PixelT>
300  fill_pixels(_gilView, rhs);
301 
302  return *this;
303 }
304 
305 //
306 // On to Image itself. ctors, cctors, and operator=
307 //
308 template <typename PixelT>
309 Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
310  : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
311  *this = initialValue;
312 }
313 
314 template <typename PixelT>
317  *this = initialValue;
318 }
319 
320 template <typename PixelT>
322  *this = initialValue;
323 }
324 
325 template <typename PixelT>
326 Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
327 // Delegate to copy-constructor for backwards compatibility
328 template <typename PixelT>
329 Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
330 
331 template <typename PixelT>
333  bool const deep)
334  : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
335 
336 template <typename PixelT>
339 
340  return *this;
341 }
342 
343 template <typename PixelT>
345  this->ImageBase<PixelT>::operator=(rhs);
346 
347  return *this;
348 }
349 // Delegate to copy-assignment for backwards compatibility
350 template <typename PixelT>
352  return *this = rhs;
353 }
354 
355 #ifndef DOXYGEN // doc for this section has been moved to header
356 
357 template <typename PixelT>
359  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe) {
360  ImageFitsReader reader(fileName, hdu);
361  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
362  if (metadata) {
363  metadata->combine(reader.readMetadata());
364  }
365 }
366 
367 template <typename PixelT>
370  ImageOrigin const origin, bool allowUnsafe) {
371  ImageFitsReader reader(manager, hdu);
372  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
373  if (metadata) {
374  metadata->combine(reader.readMetadata());
375  }
376 }
377 
378 template <typename PixelT>
380  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe) {
381  ImageFitsReader reader(&fitsFile);
382  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
383  if (metadata) {
384  metadata->combine(reader.readMetadata());
385  }
386 }
387 
388 template <typename PixelT>
389 void Image<PixelT>::writeFits(std::string const& fileName,
391  std::string const& mode) const {
392  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
393  writeFits(fitsfile, metadata_i);
394 }
395 
396 template <typename PixelT>
399  std::string const& mode) const {
400  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
401  writeFits(fitsfile, metadata_i);
402 }
403 
404 template <typename PixelT>
405 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
407  fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
408 }
409 
410 template <typename PixelT>
411 void Image<PixelT>::writeFits(std::string const& filename, fits::ImageWriteOptions const& options,
413  std::shared_ptr<Mask<MaskPixel> const> mask) const {
414  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
415  writeFits(fitsfile, options, header, mask);
416 }
417 
418 template <typename PixelT>
419 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions const& options,
421  std::shared_ptr<Mask<MaskPixel> const> mask) const {
422  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
423  writeFits(fitsfile, options, header, mask);
424 }
425 
426 template <typename PixelT>
427 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
429  std::shared_ptr<Mask<MaskPixel> const> mask) const {
430  fitsfile.writeImage(*this, options, header, mask);
431 }
432 
433 #endif // !DOXYGEN
434 
435 template <typename PixelT>
437  using std::swap; // See Meyers, Effective C++, Item 25
439 }
440 
441 template <typename PixelT>
443  a.swap(b);
444 }
445 
446 // In-place, per-pixel, sqrt().
447 template <typename PixelT>
449  transform_pixels(_getRawView(), _getRawView(),
450  [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
451 }
452 
453 template <typename PixelT>
455  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
456  return *this;
457 }
458 
459 template <typename PixelT>
461  if (this->getDimensions() != rhs.getDimensions()) {
463  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
464  this->getHeight() % rhs.getWidth() % rhs.getHeight())
465  .str());
466  }
467  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
468  [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
469  return *this;
470 }
471 
472 template <typename PixelT>
474  for (int y = 0; y != this->getHeight(); ++y) {
475  double const yPos = this->indexToPosition(y, Y);
476  double xPos = this->indexToPosition(0, X);
477  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
478  ++ptr, ++xPos) {
479  *ptr += function(xPos, yPos);
480  }
481  }
482  return *this;
483 }
484 
485 template <typename PixelT>
486 void Image<PixelT>::scaledPlus(PixelT const c, Image<PixelT> const& rhs) {
487  if (this->getDimensions() != rhs.getDimensions()) {
489  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
490  this->getHeight() % rhs.getWidth() % rhs.getHeight())
491  .str());
492  }
493  transform_pixels(
494  _getRawView(), rhs._getRawView(), _getRawView(),
495  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + (c * r); });
496 }
497 
498 template <typename PixelT>
500  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
501  return *this;
502 }
503 
504 template <typename PixelT>
506  if (this->getDimensions() != rhs.getDimensions()) {
508  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
509  this->getHeight() % rhs.getWidth() % rhs.getHeight())
510  .str());
511  }
512  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
513  [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
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(
526  _getRawView(), rhs._getRawView(), _getRawView(),
527  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - (c * r); });
528 }
529 
530 template <typename PixelT>
532  for (int y = 0; y != this->getHeight(); ++y) {
533  double const yPos = this->indexToPosition(y, Y);
534  double xPos = this->indexToPosition(0, X);
535  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
536  ++ptr, ++xPos) {
537  *ptr -= function(xPos, yPos);
538  }
539  }
540  return *this;
541 }
542 
543 template <typename PixelT>
545  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
546  return *this;
547 }
548 
549 template <typename PixelT>
551  if (this->getDimensions() != rhs.getDimensions()) {
553  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
554  this->getHeight() % rhs.getWidth() % rhs.getHeight())
555  .str());
556  }
557  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
558  [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
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(
571  _getRawView(), rhs._getRawView(), _getRawView(),
572  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * (c * r); });
573 }
574 
575 template <typename PixelT>
577  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
578  return *this;
579 }
580 //
581 // Specialize float and double for efficiency
582 //
583 template <>
585  double const irhs = 1 / rhs;
586  *this *= irhs;
587  return *this;
588 }
589 
590 template <>
592  float const irhs = 1 / rhs;
593  *this *= irhs;
594  return *this;
595 }
596 
597 template <typename PixelT>
599  if (this->getDimensions() != rhs.getDimensions()) {
601  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
602  this->getHeight() % rhs.getWidth() % rhs.getHeight())
603  .str());
604  }
605  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
606  [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
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(
619  _getRawView(), rhs._getRawView(), _getRawView(),
620  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / (c * r); });
621 }
622 
623 namespace {
624 /*
625  * Worker routine for manipulating images;
626  */
627 template <typename LhsPixelT, typename RhsPixelT>
628 struct plusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
629  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
630  return static_cast<LhsPixelT>(lhs + rhs);
631  }
632 };
633 
634 template <typename LhsPixelT, typename RhsPixelT>
635 struct minusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
636  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
637  return static_cast<LhsPixelT>(lhs - rhs);
638  }
639 };
640 
641 template <typename LhsPixelT, typename RhsPixelT>
642 struct timesEq : public pixelOp2<LhsPixelT, RhsPixelT> {
643  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
644  return static_cast<LhsPixelT>(lhs * rhs);
645  }
646 };
647 
648 template <typename LhsPixelT, typename RhsPixelT>
649 struct divideEq : public pixelOp2<LhsPixelT, RhsPixelT> {
650  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
651  return static_cast<LhsPixelT>(lhs / rhs);
652  }
653 };
654 } // namespace
655 
656 template <typename LhsPixelT, typename RhsPixelT>
658  for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
659  return lhs;
660 }
661 
662 template <typename LhsPixelT, typename RhsPixelT>
664  for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
665  return lhs;
666 }
667 
668 template <typename LhsPixelT, typename RhsPixelT>
670  for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
671  return lhs;
672 }
673 
674 template <typename LhsPixelT, typename RhsPixelT>
676  for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
677  return lhs;
678 }
679 
682  if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
683  dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
684  } else {
685  dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
686  }
688  return lsst::geom::Box2I(xy0, dims);
689 }
690 
691 template <typename T1, typename T2>
692 bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
693 
694  if (image1.getArea() == 0 || image2.getArea() == 0) {
695  // zero-area images cannot overlap.
696  return false;
697  }
698 
699  auto arr1 = image1.getArray();
700  // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
701  // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
702  auto beg1Addr = arr1.front().begin();
703  auto end1Addr = arr1.back().end();
704 
705  auto arr2 = image2.getArray();
706  auto beg2Addr = arr2.front().begin();
707  auto end2Addr = arr2.back().end();
708 
709  auto ptrLess = std::less<void const* const>();
710  return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
711 }
712 
713 //
714 // Explicit instantiations
715 //
717 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
718  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
719  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
720  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
721  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
722  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
723 
724 #define INSTANTIATE(T) \
725  template class ImageBase<T>; \
726  template class Image<T>; \
727  INSTANTIATE_OPERATOR(+=, T); \
728  INSTANTIATE_OPERATOR(-=, T); \
729  INSTANTIATE_OPERATOR(*=, T); \
730  INSTANTIATE_OPERATOR(/=, T)
731 
732 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
733 
735 INSTANTIATE(int);
736 INSTANTIATE(float);
737 INSTANTIATE(double);
739 
743 INSTANTIATE2(std::uint16_t, double);
745 
747 INSTANTIATE2(int, int);
748 INSTANTIATE2(int, float);
749 INSTANTIATE2(int, double);
751 
753 INSTANTIATE2(float, int);
754 INSTANTIATE2(float, float);
755 INSTANTIATE2(float, double);
757 
758 INSTANTIATE2(double, std::uint16_t);
759 INSTANTIATE2(double, int);
760 INSTANTIATE2(double, float);
761 INSTANTIATE2(double, double);
762 INSTANTIATE2(double, std::uint64_t);
763 
767 INSTANTIATE2(std::uint64_t, double);
769 
771 } // namespace image
772 } // namespace afw
773 } // namespace lsst
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
int end
double x
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:484
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:48
afw::table::Key< afw::table::Array< MaskPixelT > > mask
#define INSTANTIATE2(ImagePixelT1, ImagePixelT2)
Definition: MaskedImage.cc:690
uint64_t * ptr
Definition: RangeSet.cc:88
int y
Definition: SpanSet.cc:48
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
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
Definition: fits.h:477
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:255
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:250
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:45
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:171
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
Definition: Image.cc:65
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:153
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:140
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:270
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:260
_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:209
void swap(ImageBase &rhs)
Definition: Image.cc:233
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:265
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:51
Image & operator*=(PixelT const rhs)
Multiply lhs by scalar rhs.
Definition: Image.cc:544
Image & operator-=(PixelT const rhs)
Subtract scalar rhs from lhs.
Definition: Image.cc:499
void scaledPlus(PixelT const c, Image< PixelT > const &rhs)
Add Image c*rhs to lhs.
Definition: Image.cc:486
Image & operator=(const PixelT rhs)
Set the image's pixels to rhs.
Definition: Image.cc:337
Image & operator+=(PixelT const rhs)
Add scalar rhs to lhs.
Definition: Image.cc:454
void scaledMinus(PixelT const c, Image< PixelT > const &rhs)
Subtract Image c*rhs from lhs.
Definition: Image.cc:518
void swap(Image &rhs)
Definition: Image.cc:436
Image & operator/=(PixelT const rhs)
Divide lhs by scalar rhs.
Definition: Image.cc:576
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(PixelT const c, Image< PixelT > const &rhs)
Divide lhs by Image c*rhs (i.e. pixel-by-pixel division)
Definition: Image.cc:611
void scaledMultiplies(PixelT const c, Image< PixelT > const &rhs)
Multiply lhs by Image c*rhs (i.e. pixel-by-pixel multiplication)
Definition: Image.cc:563
friend class Image
Definition: Image.h:65
A Function taking two arguments.
Definition: Function.h:259
Class for storing generic metadata.
Definition: PropertySet.h:66
int getAsInt(std::string const &name) const
Get the last value for a bool/char/short/int property name (possibly hierarchical).
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
An integer coordinate rectangle.
Definition: Box.h:55
Reports attempts to exceed implementation-defined length limits for some classes.
Definition: Runtime.h:76
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
Definition: Polygon.cc:24
lsst::geom::Point2I getImageXY0FromMetadata(daf::base::PropertySet &metadata, std::string const &wcsName, bool strip=false)
Definition: wcsUtils.cc:95
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:657
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:663
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:680
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.
Definition: Image.cc:675
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:55
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.
Definition: Image.cc:669
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:692
void swap(Image< PixelT > &a, Image< PixelT > &b)
Definition: Image.cc:442
Extent< int, 2 > ExtentI
Definition: Extent.h:396
Extent< int, 2 > Extent2I
Definition: Extent.h:397
def writeFits(filename, stamps, metadata, type_name, write_mask, write_variance, write_archive=False)
Definition: stamps.py:42
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
T sqrt(T... args)
Options for writing an image to FITS.
Definition: fits.h:219
A functor class equivalent to std::function<LhsT (LhsT, RhsT)>, but with a virtual operator()
T swap(T... args)