LSSTApplications  17.0+11,17.0+34,17.0+56,17.0+57,17.0+59,17.0+7,17.0-1-g377950a+33,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+28,17.0.1-1-g55520dc+49,17.0.1-1-g5f4ed7e+52,17.0.1-1-g6dd7d69+17,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+55,17.0.1-1-gfc65f5f+50,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+1,17.0.1-11-ge9de802+16,17.0.1-16-ga14f7d5c+4,17.0.1-17-gc79d625+1,17.0.1-17-gdae4c4a+8,17.0.1-2-g26618f5+29,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-20-g2ca2f74+6,17.0.1-23-gf3eadeb7+1,17.0.1-3-g7e86b59+39,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+40,17.0.1-30-g596af8797,17.0.1-4-g59d126d+4,17.0.1-4-gc69c472+5,17.0.1-6-g5afd9b9+4,17.0.1-7-g35889ee+1,17.0.1-7-gc7c8782+18,17.0.1-9-gc4bbfb2+3,w.2019.22
LSSTDataManagementBasePackage
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 #include "boost/filesystem/path.hpp"
38 
39 #include "boost/version.hpp"
40 #if BOOST_VERSION < 106900
41 #include "boost/gil/gil_all.hpp"
42 #else
43 #include "boost/gil.hpp"
44 #endif
45 
46 #include "lsst/pex/exceptions.h"
47 #include "lsst/afw/geom/wcsUtils.h"
48 #include "lsst/afw/image/Image.h"
50 #include "lsst/afw/fits.h"
52 
53 namespace lsst {
54 namespace afw {
55 namespace image {
56 
57 template <typename PixelT>
58 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
59  Manager::Ptr& manager) {
60  if (dimensions.getX() < 0 || dimensions.getY() < 0) {
62  str(boost::format("Both width and height must be non-negative: %d, %d") %
63  dimensions.getX() % dimensions.getY()));
64  }
65  if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
67  str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
68  dimensions.getX() % dimensions.getY()));
69  }
71  ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
72  manager = r.first;
73  return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
74  (typename _view_t::value_type*)r.second,
75  dimensions.getX() * sizeof(PixelT));
76 }
77 template <typename PixelT>
78 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
79  lsst::geom::Extent2I const& offset,
80  const _view_t& view) {
81  if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() + dimensions.getX() > view.width() ||
82  offset.getY() + dimensions.getY() > view.height()) {
83  throw LSST_EXCEPT(
86  "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
87  offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
88  view.height())
89  .str());
90  }
91  return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
92  dimensions.getY());
93 }
94 
95 template <typename PixelT>
97  : daf::base::Citizen(typeid(this)),
98  _origin(0, 0),
99  _manager(),
100  _gilView(_allocateView(dimensions, _manager)) {}
101 
102 template <typename PixelT>
104  : daf::base::Citizen(typeid(this)),
105  _origin(bbox.getMin()),
106  _manager(),
107  _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
108 
109 template <typename PixelT>
110 ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
111 
112  )
113  : daf::base::Citizen(typeid(this)),
114  _origin(rhs._origin),
115  _manager(rhs._manager),
116  _gilView(rhs._gilView) {
117  if (deep) {
118  ImageBase tmp(getBBox());
119  tmp.assign(*this); // now copy the pixels
120  swap(tmp);
121  }
122 }
123 // Delegate to copy-constructor for backwards compatibility
124 template <typename PixelT>
126 
127 template <typename PixelT>
129  bool const deep
130 
131  )
132  : daf::base::Citizen(typeid(this)),
133  _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
134  _manager(rhs._manager), // reference counted pointer, don't copy pixels
135  _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
136  if (deep) {
137  ImageBase tmp(getBBox());
138  tmp.assign(*this); // now copy the pixels
139  swap(tmp);
140  }
141 }
142 
143 template <typename PixelT>
144 ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
145  : daf::base::Citizen(typeid(this)),
146  _origin(xy0),
147  _manager(array.getManager()),
148  _gilView(boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
149  (typename _view_t::value_type*)array.getData(),
150  array.template getStride<0>() * sizeof(PixelT))) {
151  if (deep) {
152  ImageBase tmp(*this, true);
153  swap(tmp);
154  }
155 }
156 
157 template <typename PixelT>
159  ImageBase tmp(rhs);
160  swap(tmp); // See Meyers, Effective C++, Item 11
161 
162  return *this;
163 }
164 // Delegate to copy-assignment for backwards compatibility
165 template <typename PixelT>
167  return *this = rhs;
168 }
169 
170 template <typename PixelT>
172  assign(rhs);
173  return *this;
174 }
175 
176 template <typename PixelT>
178  auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
179  if (lhsDim != rhs.getDimensions()) {
181  (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
182  lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
183  .str());
184  }
185  if (bbox.isEmpty()) {
186  copy_pixels(rhs._gilView, _gilView);
187  } else {
188  auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
189  auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
190  copy_pixels(rhs._gilView, lhsGilView);
191  }
192 }
193 
194 template <typename PixelT>
196  return const_cast<typename ImageBase<PixelT>::PixelReference>(
197  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
198 }
199 
200 template <typename PixelT>
202  CheckIndices const& check) {
203  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
205  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
206  (getWidth() - 1) % (getHeight() - 1))
207  .str());
208  }
209 
210  return const_cast<typename ImageBase<PixelT>::PixelReference>(
211  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
212 }
213 
214 template <typename PixelT>
216  return _gilView(x, y)[0];
217 }
218 
219 template <typename PixelT>
221  int x, int y, CheckIndices const& check) const {
222  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
224  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
225  (this->getWidth() - 1) % (this->getHeight() - 1))
226  .str());
227  }
228 
229  return _gilView(x, y)[0];
230 }
231 
232 template <typename PixelT>
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>
247  int x = index.getX();
248  int y = index.getY();
249  if (origin == PARENT) {
250  x -= getX0();
251  y -= getY0();
252  }
253  return _gilView(x, y)[0];
254 }
255 
256 
257 template <typename PixelT>
259  using std::swap; // See Meyers, Effective C++, Item 25
260 
261  swap(_manager, rhs._manager); // just swapping the pointers
262  swap(_gilView, rhs._gilView);
263  swap(_origin, rhs._origin);
264 }
265 
266 template <typename PixelT>
268  a.swap(b);
269 }
270 
271 //
272 // Iterators
273 //
274 template <typename PixelT>
276  return _gilView.begin();
277 }
278 
279 template <typename PixelT>
281  return _gilView.end();
282 }
283 
284 template <typename PixelT>
286  return _gilView.rbegin();
287 }
288 
289 template <typename PixelT>
291  return _gilView.rend();
292 }
293 
294 template <typename PixelT>
296  return _gilView.at(x, y);
297 }
298 
299 template <typename PixelT>
301  if (!contiguous) {
302  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
303  }
304  if (!this->isContiguous()) {
305  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
306  }
307 
308  return row_begin(0);
309 }
310 
311 template <typename PixelT>
313  if (!contiguous) {
314  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
315  }
316  if (!this->isContiguous()) {
317  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
318  }
319 
320  return row_end(getHeight() - 1);
321 }
322 
323 template <typename PixelT>
325  fill_pixels(_gilView, rhs);
326 
327  return *this;
328 }
329 
330 //
331 // On to Image itself. ctors, cctors, and operator=
332 //
333 template <typename PixelT>
334 Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
335  : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
336  *this = initialValue;
337 }
338 
339 template <typename PixelT>
341  : ImageBase<PixelT>(dimensions) {
342  *this = initialValue;
343 }
344 
345 template <typename PixelT>
347  *this = initialValue;
348 }
349 
350 template <typename PixelT>
351 Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
352 // Delegate to copy-constructor for backwards compatibility
353 template <typename PixelT>
354 Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
355 
356 template <typename PixelT>
358  bool const deep)
359  : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
360 
361 template <typename PixelT>
363  this->ImageBase<PixelT>::operator=(rhs);
364 
365  return *this;
366 }
367 
368 template <typename PixelT>
370  this->ImageBase<PixelT>::operator=(rhs);
371 
372  return *this;
373 }
374 // Delegate to copy-assignment for backwards compatibility
375 template <typename PixelT>
377  return *this = rhs;
378 }
379 
380 #ifndef DOXYGEN // doc for this section has been moved to header
381 
382 template <typename PixelT>
384  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe)
385 {
386  ImageFitsReader reader(fileName, hdu);
387  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
388  if (metadata) {
389  metadata->combine(reader.readMetadata());
390  }
391 }
392 
393 template <typename PixelT>
394 Image<PixelT>::Image(fits::MemFileManager& manager, int const hdu,
396  ImageOrigin const origin, bool allowUnsafe)
397 {
398  ImageFitsReader reader(manager, hdu);
399  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
400  if (metadata) {
401  metadata->combine(reader.readMetadata());
402  }
403 }
404 
405 template <typename PixelT>
407  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe)
408 {
409  ImageFitsReader reader(&fitsFile);
410  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
411  if (metadata) {
412  metadata->combine(reader.readMetadata());
413  }
414 }
415 
416 template <typename PixelT>
417 void Image<PixelT>::writeFits(std::string const& fileName,
419  std::string const& mode) const {
420  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
421  writeFits(fitsfile, metadata_i);
422 }
423 
424 template <typename PixelT>
427  std::string const& mode) const {
428  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
429  writeFits(fitsfile, metadata_i);
430 }
431 
432 template <typename PixelT>
433 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
435  fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
436 }
437 
438 template <typename PixelT>
441  std::shared_ptr<Mask<MaskPixel> const> mask) const {
442  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
443  writeFits(fitsfile, options, header, mask);
444 }
445 
446 template <typename PixelT>
449  std::shared_ptr<Mask<MaskPixel> const> mask) const {
450  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
451  writeFits(fitsfile, options, header, mask);
452 }
453 
454 template <typename PixelT>
455 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
457  std::shared_ptr<Mask<MaskPixel> const> mask) const {
458  fitsfile.writeImage(*this, options, header, mask);
459 }
460 
461 #endif // !DOXYGEN
462 
463 template <typename PixelT>
465  using std::swap; // See Meyers, Effective C++, Item 25
467  ; // no private variables to swap
468 }
469 
470 template <typename PixelT>
472  a.swap(b);
473 }
474 
475 // In-place, per-pixel, sqrt().
476 template <typename PixelT>
478  transform_pixels(_getRawView(), _getRawView(),
479  [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
480 }
481 
482 template <typename PixelT>
484  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
485  return *this;
486 }
487 
488 template <typename PixelT>
490  if (this->getDimensions() != rhs.getDimensions()) {
492  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
493  this->getHeight() % rhs.getWidth() % rhs.getHeight())
494  .str());
495  }
496  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
497  [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
498  return *this;
499 }
500 
501 template <typename PixelT>
503  for (int y = 0; y != this->getHeight(); ++y) {
504  double const yPos = this->indexToPosition(y, Y);
505  double xPos = this->indexToPosition(0, X);
506  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
507  ++ptr, ++xPos) {
508  *ptr += function(xPos, yPos);
509  }
510  }
511  return *this;
512 }
513 
514 template <typename PixelT>
515 void Image<PixelT>::scaledPlus(double const c, Image<PixelT> const& rhs) {
516  if (this->getDimensions() != rhs.getDimensions()) {
518  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
519  this->getHeight() % rhs.getWidth() % rhs.getHeight())
520  .str());
521  }
522  transform_pixels(
523  _getRawView(), rhs._getRawView(), _getRawView(),
524  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + static_cast<PixelT>(c * r); });
525 }
526 
527 template <typename PixelT>
529  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
530  return *this;
531 }
532 
533 template <typename PixelT>
535  if (this->getDimensions() != rhs.getDimensions()) {
537  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
538  this->getHeight() % rhs.getWidth() % rhs.getHeight())
539  .str());
540  }
541  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
542  [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
543  return *this;
544 }
545 
546 template <typename PixelT>
547 void Image<PixelT>::scaledMinus(double const c, Image<PixelT> const& rhs) {
548  if (this->getDimensions() != rhs.getDimensions()) {
550  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
551  this->getHeight() % rhs.getWidth() % rhs.getHeight())
552  .str());
553  }
554  transform_pixels(
555  _getRawView(), rhs._getRawView(), _getRawView(),
556  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - static_cast<PixelT>(c * r); });
557 }
558 
559 template <typename PixelT>
561  for (int y = 0; y != this->getHeight(); ++y) {
562  double const yPos = this->indexToPosition(y, Y);
563  double xPos = this->indexToPosition(0, X);
564  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
565  ++ptr, ++xPos) {
566  *ptr -= function(xPos, yPos);
567  }
568  }
569  return *this;
570 }
571 
572 template <typename PixelT>
574  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
575  return *this;
576 }
577 
578 template <typename PixelT>
580  if (this->getDimensions() != rhs.getDimensions()) {
582  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
583  this->getHeight() % rhs.getWidth() % rhs.getHeight())
584  .str());
585  }
586  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
587  [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
588  return *this;
589 }
590 
591 template <typename PixelT>
592 void Image<PixelT>::scaledMultiplies(double const c, Image<PixelT> const& rhs) {
593  if (this->getDimensions() != rhs.getDimensions()) {
595  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
596  this->getHeight() % rhs.getWidth() % rhs.getHeight())
597  .str());
598  }
599  transform_pixels(
600  _getRawView(), rhs._getRawView(), _getRawView(),
601  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * static_cast<PixelT>(c * r); });
602 }
603 
604 template <typename PixelT>
606  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
607  return *this;
608 }
609 //
610 // Specialize float and double for efficiency
611 //
612 template <>
614  double const irhs = 1 / rhs;
615  *this *= irhs;
616  return *this;
617 }
618 
619 template <>
621  float const irhs = 1 / rhs;
622  *this *= irhs;
623  return *this;
624 }
625 
626 template <typename PixelT>
628  if (this->getDimensions() != rhs.getDimensions()) {
630  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
631  this->getHeight() % rhs.getWidth() % rhs.getHeight())
632  .str());
633  }
634  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
635  [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
636  return *this;
637 }
638 
639 template <typename PixelT>
640 void Image<PixelT>::scaledDivides(double const c, Image<PixelT> const& rhs) {
641  if (this->getDimensions() != rhs.getDimensions()) {
643  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
644  this->getHeight() % rhs.getWidth() % rhs.getHeight())
645  .str());
646  }
647  transform_pixels(
648  _getRawView(), rhs._getRawView(), _getRawView(),
649  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / static_cast<PixelT>(c * r); });
650 }
651 
652 namespace {
653 /*
654  * Worker routine for manipulating images;
655  */
656 template <typename LhsPixelT, typename RhsPixelT>
657 struct plusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
658  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
659  return static_cast<LhsPixelT>(lhs + rhs);
660  }
661 };
662 
663 template <typename LhsPixelT, typename RhsPixelT>
664 struct minusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
665  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
666  return static_cast<LhsPixelT>(lhs - rhs);
667  }
668 };
669 
670 template <typename LhsPixelT, typename RhsPixelT>
671 struct timesEq : public pixelOp2<LhsPixelT, RhsPixelT> {
672  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
673  return static_cast<LhsPixelT>(lhs * rhs);
674  }
675 };
676 
677 template <typename LhsPixelT, typename RhsPixelT>
678 struct divideEq : public pixelOp2<LhsPixelT, RhsPixelT> {
679  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
680  return static_cast<LhsPixelT>(lhs / rhs);
681  }
682 };
683 } // namespace
684 
685 template <typename LhsPixelT, typename RhsPixelT>
687  for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
688  return lhs;
689 }
690 
691 template <typename LhsPixelT, typename RhsPixelT>
693  for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
694  return lhs;
695 }
696 
697 template <typename LhsPixelT, typename RhsPixelT>
699  for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
700  return lhs;
701 }
702 
703 template <typename LhsPixelT, typename RhsPixelT>
705  for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
706  return lhs;
707 }
708 
711  if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
712  dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
713  } else {
714  dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
715  }
717  return lsst::geom::Box2I(xy0, dims);
718 }
719 
720 template <typename T1, typename T2>
721 bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
722  auto arr1 = image1.getArray();
723  // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
724  // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
725  auto beg1Addr = arr1.front().begin();
726  auto end1Addr = arr1.back().end();
727 
728  auto arr2 = image2.getArray();
729  auto beg2Addr = arr2.front().begin();
730  auto end2Addr = arr2.back().end();
731 
732  auto ptrLess = std::less<void const* const>();
733  return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
734 }
735 
736 //
737 // Explicit instantiations
738 //
740 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
741  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
742  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
743  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
744  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
745  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
746 
747 #define INSTANTIATE(T) \
748  template class ImageBase<T>; \
749  template class Image<T>; \
750  INSTANTIATE_OPERATOR(+=, T); \
751  INSTANTIATE_OPERATOR(-=, T); \
752  INSTANTIATE_OPERATOR(*=, T); \
753  INSTANTIATE_OPERATOR(/=, T)
754 
755 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
756 
758 INSTANTIATE(int);
759 INSTANTIATE(float);
760 INSTANTIATE(double);
762 
766 INSTANTIATE2(std::uint16_t, double);
768 
770 INSTANTIATE2(int, int);
771 INSTANTIATE2(int, float);
772 INSTANTIATE2(int, double);
774 
776 INSTANTIATE2(float, int);
777 INSTANTIATE2(float, float);
778 INSTANTIATE2(float, double);
780 
781 INSTANTIATE2(double, std::uint16_t);
782 INSTANTIATE2(double, int);
783 INSTANTIATE2(double, float);
784 INSTANTIATE2(double, double);
785 INSTANTIATE2(double, std::uint64_t);
786 
790 INSTANTIATE2(std::uint64_t, double);
792 
794 } // namespace image
795 } // namespace afw
796 } // namespace lsst
Extent2I const getDimensions() const noexcept
Definition: Box.h:173
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:49
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
A functor class equivalent to std::function<LhsT (LhsT, RhsT)>, but with a virtual operator() ...
uint64_t * ptr
Definition: RangeSet.cc:88
x_iterator fast_iterator
A fast STL compliant iterator for contiguous images N.b.
Definition: ImageBase.h:138
std::shared_ptr< daf::base::PropertyList > readMetadata()
Read the image&#39;s FITS header.
ConstReference< PixelT >::type PixelConstReference
A ConstReference to a PixelT.
Definition: ImageBase.h:120
Definition: Polygon.cc:25
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:55
_view_t::reverse_iterator reverse_iterator
An STL compliant reverse iterator.
Definition: ImageBase.h:130
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:686
T swap(T... args)
int getHeight() const
Return the number of rows in the image.
Definition: ImageBase.h:316
table::Key< int > b
bool isEmpty() const noexcept
Return true if the box contains no points.
Definition: Box.h:194
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
Options for writing an image to FITS.
Definition: fits.h:219
int getAsInt(std::string const &name) const
Get the last value for a bool/char/short/int property name (possibly hierarchical).
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:134
int y
Definition: SpanSet.cc:49
table::Key< int > a
A FITS reader class for regular Images.
tuple options
Definition: lsstimport.py:47
void for_each_pixel(Image< LhsT > &lhs, pixelOp0< LhsT > const &func)
Set each pixel in an Image<LhsT> to func()
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: ImageBase.h:103
A Function taking two arguments.
Definition: Function.h:261
STL class.
Point2I const getMin() const noexcept
Definition: Box.h:143
_view_t::iterator iterator
An STL compliant iterator.
Definition: ImageBase.h:126
A base class for image defects.
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:78
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
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:177
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
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:721
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
A class used to request that array accesses be checked.
Definition: ImageBase.h:75
void swap(ImageBase &rhs)
Definition: Image.cc:258
table::Box2IKey bbox
Definition: Detector.cc:169
T max(T... args)
double x
Image< PixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the Image.
void swap(Image< PixelT > &a, Image< PixelT > &b)
Definition: Image.cc:471
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
afw::table::Key< afw::table::Array< MaskPixelT > > mask
Extent< int, 2 > Extent2I
Definition: Extent.h:397
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:698
reverse_iterator rend() const
Return an STL compliant reverse iterator to the end of the image.
Definition: Image.cc:290
lsst::geom::Point2I getImageXY0FromMetadata(daf::base::PropertySet &metadata, std::string const &wcsName, bool strip=false)
Definition: wcsUtils.cc:98
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:692
Class for storing generic metadata.
Definition: PropertySet.h:68
int getWidth() const
Return the number of columns in the image.
Definition: ImageBase.h:314
Extent< int, 2 > ExtentI
Definition: Extent.h:396
Reference< PixelT >::type PixelReference
A Reference to a PixelT.
Definition: ImageBase.h:118
reverse_iterator rbegin() const
Return an STL compliant reverse iterator to the start of the image.
Definition: Image.cc:285
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:275
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:704
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:295
T sqrt(T... args)
lsst::geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: ImageBase.h:374
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
Definition: fits.h:477
_view_t _getRawView() const
Definition: ImageBase.h:483
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:58
ndarray::Array< MaskPixelT, 2, 1 > Array
A mutable ndarray representation of the image.
Definition: ImageBase.h:150
An integer coordinate rectangle.
Definition: Box.h:54
void swap(Image &rhs)
Definition: Image.cc:464
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
Definition: Image.cc:709
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:59
#define INSTANTIATE2(ImagePixelT1, ImagePixelT2)
Definition: MaskedImage.cc:689
std::string const wcsNameForXY0
Definition: ImageBase.h:71
int end
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:349
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
Definition: Image.cc:78