LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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 <iostream>
30 #include <functional>
31 #include "boost/format.hpp"
32 #include "boost/gil.hpp"
33 
34 #include "lsst/pex/exceptions.h"
35 #include "lsst/afw/geom/wcsUtils.h"
36 #include "lsst/afw/image/Image.h"
38 #include "lsst/afw/fits.h"
40 
41 namespace lsst {
42 namespace afw {
43 namespace image {
44 
45 template <typename PixelT>
46 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
47  Manager::Ptr& manager) {
48  if (dimensions.getX() < 0 || dimensions.getY() < 0) {
50  str(boost::format("Both width and height must be non-negative: %d, %d") %
51  dimensions.getX() % dimensions.getY()));
52  }
53  if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
55  str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
56  dimensions.getX() % dimensions.getY()));
57  }
59  ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
60  manager = r.first;
61  return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
62  (typename _view_t::value_type*)r.second,
63  dimensions.getX() * sizeof(PixelT));
64 }
65 template <typename PixelT>
66 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
67  lsst::geom::Extent2I const& offset,
68  const _view_t& view) {
69  if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() + dimensions.getX() > view.width() ||
70  offset.getY() + dimensions.getY() > view.height()) {
71  throw LSST_EXCEPT(
74  "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
75  offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
76  view.height())
77  .str());
78  }
79  if (dimensions.getX() == 0 && dimensions.getY() == 0
80  && view.width() == 0 && view.height() == 0) {
81  // Getting a zero-extent subview of a zero-extent view returns itself
82  return view;
83  } else {
84  return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
85  dimensions.getY());
86  }
87 }
88 
89 template <typename PixelT>
91  : _origin(0, 0), _manager(), _gilView(_allocateView(dimensions, _manager)) {}
92 
93 template <typename PixelT>
95  : _origin(bbox.getMin()), _manager(), _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
96 
97 template <typename PixelT>
98 ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
99 
100  )
101  : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
102  if (deep) {
103  ImageBase tmp(getBBox());
104  tmp.assign(*this); // now copy the pixels
105  swap(tmp);
106  }
107 }
108 // Delegate to copy-constructor for backwards compatibility
109 template <typename PixelT>
111 
112 template <typename PixelT>
114  bool const deep
115 
116  )
117  : _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
118  _manager(rhs._manager), // reference counted pointer, don't copy pixels
119  _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
120  if (deep) {
122  tmp.assign(*this); // now copy the pixels
123  swap(tmp);
124  }
125 }
126 
127 template <typename PixelT>
128 ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
129  : _origin(xy0),
130  _manager(array.getManager()),
131  _gilView(boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
132  (typename _view_t::value_type*)array.getData(),
133  array.template getStride<0>() * sizeof(PixelT))) {
134  if (deep) {
135  ImageBase tmp(*this, true);
136  swap(tmp);
137  }
138 }
139 
140 template <typename PixelT>
142  ImageBase tmp(rhs);
143  swap(tmp); // See Meyers, Effective C++, Item 11
144 
145  return *this;
146 }
147 // Delegate to copy-assignment for backwards compatibility
148 template <typename PixelT>
150  return *this = rhs;
151 }
152 
153 template <typename PixelT>
155  auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
156  if (lhsDim != rhs.getDimensions()) {
158  (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
159  lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
160  .str());
161  }
162  if (bbox.isEmpty()) {
163  copy_pixels(rhs._gilView, _gilView);
164  } else {
165  auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
166  auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
167  copy_pixels(rhs._gilView, lhsGilView);
168  }
169 }
170 
171 template <typename PixelT>
173  return const_cast<typename ImageBase<PixelT>::PixelReference>(
174  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
175 }
176 
177 template <typename PixelT>
179  CheckIndices const& check) {
180  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
182  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
183  (getWidth() - 1) % (getHeight() - 1))
184  .str());
185  }
186 
187  return const_cast<typename ImageBase<PixelT>::PixelReference>(
188  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
189 }
190 
191 template <typename PixelT>
193  return _gilView(x, y)[0];
194 }
195 
196 template <typename PixelT>
198  int x, int y, CheckIndices const& check) const {
199  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
201  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
202  (this->getWidth() - 1) % (this->getHeight() - 1))
203  .str());
204  }
205 
206  return _gilView(x, y)[0];
207 }
208 
209 template <typename PixelT>
211  ImageOrigin origin) {
212  int x = index.getX();
213  int y = index.getY();
214  if (origin == PARENT) {
215  x -= getX0();
216  y -= getY0();
217  }
218  return _gilView(x, y)[0];
219 }
220 
221 template <typename PixelT>
223  ImageOrigin origin) const {
224  int x = index.getX();
225  int y = index.getY();
226  if (origin == PARENT) {
227  x -= getX0();
228  y -= getY0();
229  }
230  return _gilView(x, y)[0];
231 }
232 
233 template <typename PixelT>
235  using std::swap; // See Meyers, Effective C++, Item 25
236 
237  swap(_manager, rhs._manager); // just swapping the pointers
238  swap(_gilView, rhs._gilView);
239  swap(_origin, rhs._origin);
240 }
241 
242 template <typename PixelT>
244  a.swap(b);
245 }
246 
247 //
248 // Iterators
249 //
250 template <typename PixelT>
252  return _gilView.begin();
253 }
254 
255 template <typename PixelT>
257  return _gilView.end();
258 }
259 
260 template <typename PixelT>
262  return _gilView.rbegin();
263 }
264 
265 template <typename PixelT>
267  return _gilView.rend();
268 }
269 
270 template <typename PixelT>
272  return _gilView.at(x, y);
273 }
274 
275 template <typename PixelT>
277  if (!contiguous) {
278  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
279  }
280  if (!this->isContiguous()) {
281  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
282  }
283 
284  return row_begin(0);
285 }
286 
287 template <typename PixelT>
289  if (!contiguous) {
290  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
291  }
292  if (!this->isContiguous()) {
293  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
294  }
295 
296  return row_end(getHeight() - 1);
297 }
298 
299 template <typename PixelT>
301  fill_pixels(_gilView, rhs);
302 
303  return *this;
304 }
305 
306 //
307 // On to Image itself. ctors, cctors, and operator=
308 //
309 template <typename PixelT>
310 Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
311  : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
312  *this = initialValue;
313 }
314 
315 template <typename PixelT>
318  *this = initialValue;
319 }
320 
321 template <typename PixelT>
323  *this = initialValue;
324 }
325 
326 template <typename PixelT>
327 Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
328 // Delegate to copy-constructor for backwards compatibility
329 template <typename PixelT>
330 Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
331 
332 template <typename PixelT>
334  bool const deep)
335  : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
336 
337 template <typename PixelT>
339  this->ImageBase<PixelT>::operator=(rhs);
340 
341  return *this;
342 }
343 
344 template <typename PixelT>
346  this->ImageBase<PixelT>::operator=(rhs);
347 
348  return *this;
349 }
350 // Delegate to copy-assignment for backwards compatibility
351 template <typename PixelT>
353  return *this = rhs;
354 }
355 
356 #ifndef DOXYGEN // doc for this section has been moved to header
357 
358 template <typename PixelT>
360  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe) {
361  ImageFitsReader reader(fileName, hdu);
362  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
363  if (metadata) {
364  metadata->combine(reader.readMetadata());
365  }
366 }
367 
368 template <typename PixelT>
369 Image<PixelT>::Image(fits::MemFileManager& manager, int const hdu,
371  ImageOrigin const origin, bool allowUnsafe) {
372  ImageFitsReader reader(manager, hdu);
373  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
374  if (metadata) {
375  metadata->combine(reader.readMetadata());
376  }
377 }
378 
379 template <typename PixelT>
381  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe) {
382  ImageFitsReader reader(&fitsFile);
383  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
384  if (metadata) {
385  metadata->combine(reader.readMetadata());
386  }
387 }
388 
389 template <typename PixelT>
390 void Image<PixelT>::writeFits(std::string const& fileName,
392  std::string const& mode) const {
393  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
394  writeFits(fitsfile, metadata_i);
395 }
396 
397 template <typename PixelT>
400  std::string const& mode) const {
401  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
402  writeFits(fitsfile, metadata_i);
403 }
404 
405 template <typename PixelT>
406 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
408  fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
409 }
410 
411 template <typename PixelT>
412 void Image<PixelT>::writeFits(std::string const& filename, fits::ImageWriteOptions const& options,
414  std::shared_ptr<Mask<MaskPixel> const> mask) const {
415  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
416  writeFits(fitsfile, options, header, mask);
417 }
418 
419 template <typename PixelT>
420 void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions const& options,
422  std::shared_ptr<Mask<MaskPixel> const> mask) const {
423  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
424  writeFits(fitsfile, options, header, mask);
425 }
426 
427 template <typename PixelT>
428 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
430  std::shared_ptr<Mask<MaskPixel> const> mask) const {
431  fitsfile.writeImage(*this, options, header, mask);
432 }
433 
434 #endif // !DOXYGEN
435 
436 template <typename PixelT>
438  using std::swap; // See Meyers, Effective C++, Item 25
440  ; // no private variables to swap
441 }
442 
443 template <typename PixelT>
445  a.swap(b);
446 }
447 
448 // In-place, per-pixel, sqrt().
449 template <typename PixelT>
451  transform_pixels(_getRawView(), _getRawView(),
452  [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
453 }
454 
455 template <typename PixelT>
457  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
458  return *this;
459 }
460 
461 template <typename PixelT>
463  if (this->getDimensions() != rhs.getDimensions()) {
465  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
466  this->getHeight() % rhs.getWidth() % rhs.getHeight())
467  .str());
468  }
469  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
470  [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
471  return *this;
472 }
473 
474 template <typename PixelT>
476  for (int y = 0; y != this->getHeight(); ++y) {
477  double const yPos = this->indexToPosition(y, Y);
478  double xPos = this->indexToPosition(0, X);
479  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
480  ++ptr, ++xPos) {
481  *ptr += function(xPos, yPos);
482  }
483  }
484  return *this;
485 }
486 
487 template <typename PixelT>
488 void Image<PixelT>::scaledPlus(double const c, Image<PixelT> const& rhs) {
489  if (this->getDimensions() != rhs.getDimensions()) {
491  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
492  this->getHeight() % rhs.getWidth() % rhs.getHeight())
493  .str());
494  }
495  transform_pixels(
496  _getRawView(), rhs._getRawView(), _getRawView(),
497  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + static_cast<PixelT>(c * r); });
498 }
499 
500 template <typename PixelT>
502  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
503  return *this;
504 }
505 
506 template <typename PixelT>
508  if (this->getDimensions() != rhs.getDimensions()) {
510  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
511  this->getHeight() % rhs.getWidth() % rhs.getHeight())
512  .str());
513  }
514  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
515  [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
516  return *this;
517 }
518 
519 template <typename PixelT>
520 void Image<PixelT>::scaledMinus(double const c, Image<PixelT> const& rhs) {
521  if (this->getDimensions() != rhs.getDimensions()) {
523  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
524  this->getHeight() % rhs.getWidth() % rhs.getHeight())
525  .str());
526  }
527  transform_pixels(
528  _getRawView(), rhs._getRawView(), _getRawView(),
529  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - static_cast<PixelT>(c * r); });
530 }
531 
532 template <typename PixelT>
534  for (int y = 0; y != this->getHeight(); ++y) {
535  double const yPos = this->indexToPosition(y, Y);
536  double xPos = this->indexToPosition(0, X);
537  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
538  ++ptr, ++xPos) {
539  *ptr -= function(xPos, yPos);
540  }
541  }
542  return *this;
543 }
544 
545 template <typename PixelT>
547  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
548  return *this;
549 }
550 
551 template <typename PixelT>
553  if (this->getDimensions() != rhs.getDimensions()) {
555  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
556  this->getHeight() % rhs.getWidth() % rhs.getHeight())
557  .str());
558  }
559  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
560  [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
561  return *this;
562 }
563 
564 template <typename PixelT>
565 void Image<PixelT>::scaledMultiplies(double const c, Image<PixelT> const& rhs) {
566  if (this->getDimensions() != rhs.getDimensions()) {
568  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
569  this->getHeight() % rhs.getWidth() % rhs.getHeight())
570  .str());
571  }
572  transform_pixels(
573  _getRawView(), rhs._getRawView(), _getRawView(),
574  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * static_cast<PixelT>(c * r); });
575 }
576 
577 template <typename PixelT>
579  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
580  return *this;
581 }
582 //
583 // Specialize float and double for efficiency
584 //
585 template <>
587  double const irhs = 1 / rhs;
588  *this *= irhs;
589  return *this;
590 }
591 
592 template <>
594  float const irhs = 1 / rhs;
595  *this *= irhs;
596  return *this;
597 }
598 
599 template <typename PixelT>
601  if (this->getDimensions() != rhs.getDimensions()) {
603  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
604  this->getHeight() % rhs.getWidth() % rhs.getHeight())
605  .str());
606  }
607  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
608  [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
609  return *this;
610 }
611 
612 template <typename PixelT>
613 void Image<PixelT>::scaledDivides(double const c, Image<PixelT> const& rhs) {
614  if (this->getDimensions() != rhs.getDimensions()) {
616  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
617  this->getHeight() % rhs.getWidth() % rhs.getHeight())
618  .str());
619  }
620  transform_pixels(
621  _getRawView(), rhs._getRawView(), _getRawView(),
622  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / static_cast<PixelT>(c * r); });
623 }
624 
625 namespace {
626 /*
627  * Worker routine for manipulating images;
628  */
629 template <typename LhsPixelT, typename RhsPixelT>
630 struct plusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
631  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
632  return static_cast<LhsPixelT>(lhs + rhs);
633  }
634 };
635 
636 template <typename LhsPixelT, typename RhsPixelT>
637 struct minusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
638  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
639  return static_cast<LhsPixelT>(lhs - rhs);
640  }
641 };
642 
643 template <typename LhsPixelT, typename RhsPixelT>
644 struct timesEq : public pixelOp2<LhsPixelT, RhsPixelT> {
645  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
646  return static_cast<LhsPixelT>(lhs * rhs);
647  }
648 };
649 
650 template <typename LhsPixelT, typename RhsPixelT>
651 struct divideEq : public pixelOp2<LhsPixelT, RhsPixelT> {
652  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
653  return static_cast<LhsPixelT>(lhs / rhs);
654  }
655 };
656 } // namespace
657 
658 template <typename LhsPixelT, typename RhsPixelT>
660  for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
661  return lhs;
662 }
663 
664 template <typename LhsPixelT, typename RhsPixelT>
666  for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
667  return lhs;
668 }
669 
670 template <typename LhsPixelT, typename RhsPixelT>
672  for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
673  return lhs;
674 }
675 
676 template <typename LhsPixelT, typename RhsPixelT>
678  for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
679  return lhs;
680 }
681 
684  if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
685  dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
686  } else {
687  dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
688  }
690  return lsst::geom::Box2I(xy0, dims);
691 }
692 
693 template <typename T1, typename T2>
694 bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
695 
696  if (image1.getArea() == 0 || image2.getArea() == 0) {
697  // zero-area images cannot overlap.
698  return false;
699  }
700 
701  auto arr1 = image1.getArray();
702  // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
703  // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
704  auto beg1Addr = arr1.front().begin();
705  auto end1Addr = arr1.back().end();
706 
707  auto arr2 = image2.getArray();
708  auto beg2Addr = arr2.front().begin();
709  auto end2Addr = arr2.back().end();
710 
711  auto ptrLess = std::less<void const* const>();
712  return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
713 }
714 
715 //
716 // Explicit instantiations
717 //
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);
725 
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)
733 
734 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
735 
737 INSTANTIATE(int);
738 INSTANTIATE(float);
739 INSTANTIATE(double);
741 
745 INSTANTIATE2(std::uint16_t, double);
747 
749 INSTANTIATE2(int, int);
750 INSTANTIATE2(int, float);
751 INSTANTIATE2(int, double);
753 
755 INSTANTIATE2(float, int);
756 INSTANTIATE2(float, float);
757 INSTANTIATE2(float, double);
759 
760 INSTANTIATE2(double, std::uint16_t);
761 INSTANTIATE2(double, int);
762 INSTANTIATE2(double, float);
763 INSTANTIATE2(double, double);
764 INSTANTIATE2(double, std::uint64_t);
765 
769 INSTANTIATE2(std::uint64_t, double);
771 
773 } // namespace image
774 } // namespace afw
775 } // 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:256
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:251
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:46
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:172
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
Definition: Image.cc:66
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:154
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:141
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:271
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:261
_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:210
void swap(ImageBase &rhs)
Definition: Image.cc:234
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:266
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
void scaledPlus(double const c, Image< PixelT > const &rhs)
Add Image c*rhs to lhs.
Definition: Image.cc:488
Image & operator*=(PixelT const rhs)
Multiply lhs by scalar rhs.
Definition: Image.cc:546
void scaledMinus(double const c, Image< PixelT > const &rhs)
Subtract Image c*rhs from lhs.
Definition: Image.cc:520
Image & operator-=(PixelT const rhs)
Subtract scalar rhs from lhs.
Definition: Image.cc:501
Image & operator=(const PixelT rhs)
Set the image's pixels to rhs.
Definition: Image.cc:338
void scaledMultiplies(double const c, Image< PixelT > const &rhs)
Multiply lhs by Image c*rhs (i.e. pixel-by-pixel multiplication)
Definition: Image.cc:565
Image & operator+=(PixelT const rhs)
Add scalar rhs to lhs.
Definition: Image.cc:456
void swap(Image &rhs)
Definition: Image.cc:437
Image & operator/=(PixelT const rhs)
Divide lhs by scalar rhs.
Definition: Image.cc:578
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(double const c, Image< PixelT > const &rhs)
Divide lhs by Image c*rhs (i.e. pixel-by-pixel division)
Definition: Image.cc:613
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:659
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:665
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:682
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:677
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:671
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:694
void swap(Image< PixelT > &a, Image< PixelT > &b)
Definition: Image.cc:444
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)