LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
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 #include "boost/gil/gil_all.hpp"
39 
40 #include "lsst/pex/exceptions.h"
41 #include "lsst/afw/geom/wcsUtils.h"
42 #include "lsst/afw/image/Image.h"
44 #include "lsst/afw/fits.h"
46 
47 namespace lsst {
48 namespace afw {
49 namespace image {
50 
51 template <typename PixelT>
52 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
53  Manager::Ptr& manager) {
54  if (dimensions.getX() < 0 || dimensions.getY() < 0) {
56  str(boost::format("Both width and height must be non-negative: %d, %d") %
57  dimensions.getX() % dimensions.getY()));
58  }
59  if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
61  str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
62  dimensions.getX() % dimensions.getY()));
63  }
65  ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
66  manager = r.first;
67  return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
68  (typename _view_t::value_type*)r.second,
69  dimensions.getX() * sizeof(PixelT));
70 }
71 template <typename PixelT>
72 typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
73  lsst::geom::Extent2I const& offset,
74  const _view_t& view) {
75  if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() + dimensions.getX() > view.width() ||
76  offset.getY() + dimensions.getY() > view.height()) {
77  throw LSST_EXCEPT(
80  "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
81  offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
82  view.height())
83  .str());
84  }
85  return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
86  dimensions.getY());
87 }
88 
89 template <typename PixelT>
91  : daf::base::Citizen(typeid(this)),
92  _origin(0, 0),
93  _manager(),
94  _gilView(_allocateView(dimensions, _manager)) {}
95 
96 template <typename PixelT>
98  : daf::base::Citizen(typeid(this)),
99  _origin(bbox.getMin()),
100  _manager(),
101  _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
102 
103 template <typename PixelT>
104 ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
105 
106  )
107  : daf::base::Citizen(typeid(this)),
108  _origin(rhs._origin),
109  _manager(rhs._manager),
110  _gilView(rhs._gilView) {
111  if (deep) {
112  ImageBase tmp(getBBox());
113  tmp.assign(*this); // now copy the pixels
114  swap(tmp);
115  }
116 }
117 // Delegate to copy-constructor for backwards compatibility
118 template <typename PixelT>
120 
121 template <typename PixelT>
123  bool const deep
124 
125  )
126  : daf::base::Citizen(typeid(this)),
127  _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
128  _manager(rhs._manager), // reference counted pointer, don't copy pixels
129  _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
130  if (deep) {
131  ImageBase tmp(getBBox());
132  tmp.assign(*this); // now copy the pixels
133  swap(tmp);
134  }
135 }
136 
137 template <typename PixelT>
138 ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
139  : daf::base::Citizen(typeid(this)),
140  _origin(xy0),
141  _manager(array.getManager()),
142  _gilView(boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
143  (typename _view_t::value_type*)array.getData(),
144  array.template getStride<0>() * sizeof(PixelT))) {
145  if (deep) {
146  ImageBase tmp(*this, true);
147  swap(tmp);
148  }
149 }
150 
151 template <typename PixelT>
153  ImageBase tmp(rhs);
154  swap(tmp); // See Meyers, Effective C++, Item 11
155 
156  return *this;
157 }
158 // Delegate to copy-assignment for backwards compatibility
159 template <typename PixelT>
161  return *this = rhs;
162 }
163 
164 template <typename PixelT>
166  assign(rhs);
167  return *this;
168 }
169 
170 template <typename PixelT>
172  auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
173  if (lhsDim != rhs.getDimensions()) {
175  (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
176  lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
177  .str());
178  }
179  if (bbox.isEmpty()) {
180  copy_pixels(rhs._gilView, _gilView);
181  } else {
182  auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
183  auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
184  copy_pixels(rhs._gilView, lhsGilView);
185  }
186 }
187 
188 template <typename PixelT>
190  return const_cast<typename ImageBase<PixelT>::PixelReference>(
191  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
192 }
193 
194 template <typename PixelT>
196  CheckIndices const& check) {
197  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
199  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
200  (getWidth() - 1) % (getHeight() - 1))
201  .str());
202  }
203 
204  return const_cast<typename ImageBase<PixelT>::PixelReference>(
205  static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
206 }
207 
208 template <typename PixelT>
210  return _gilView(x, y)[0];
211 }
212 
213 template <typename PixelT>
215  int x, int y, CheckIndices const& check) const {
216  if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
218  (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
219  (this->getWidth() - 1) % (this->getHeight() - 1))
220  .str());
221  }
222 
223  return _gilView(x, y)[0];
224 }
225 
226 template <typename PixelT>
229  int x = index.getX();
230  int y = index.getY();
231  if (origin == PARENT) {
232  x -= getX0();
233  y -= getY0();
234  }
235  return _gilView(x, y)[0];
236 }
237 
238 template <typename PixelT>
241  int x = index.getX();
242  int y = index.getY();
243  if (origin == PARENT) {
244  x -= getX0();
245  y -= getY0();
246  }
247  return _gilView(x, y)[0];
248 }
249 
250 
251 template <typename PixelT>
253  using std::swap; // See Meyers, Effective C++, Item 25
254 
255  swap(_manager, rhs._manager); // just swapping the pointers
256  swap(_gilView, rhs._gilView);
257  swap(_origin, rhs._origin);
258 }
259 
260 template <typename PixelT>
262  a.swap(b);
263 }
264 
265 //
266 // Iterators
267 //
268 template <typename PixelT>
270  return _gilView.begin();
271 }
272 
273 template <typename PixelT>
275  return _gilView.end();
276 }
277 
278 template <typename PixelT>
280  return _gilView.rbegin();
281 }
282 
283 template <typename PixelT>
285  return _gilView.rend();
286 }
287 
288 template <typename PixelT>
290  return _gilView.at(x, y);
291 }
292 
293 template <typename PixelT>
295  if (!contiguous) {
296  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
297  }
298  if (!this->isContiguous()) {
299  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
300  }
301 
302  return row_begin(0);
303 }
304 
305 template <typename PixelT>
307  if (!contiguous) {
308  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
309  }
310  if (!this->isContiguous()) {
311  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
312  }
313 
314  return row_end(getHeight() - 1);
315 }
316 
317 template <typename PixelT>
319  fill_pixels(_gilView, rhs);
320 
321  return *this;
322 }
323 
324 //
325 // On to Image itself. ctors, cctors, and operator=
326 //
327 template <typename PixelT>
328 Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
329  : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
330  *this = initialValue;
331 }
332 
333 template <typename PixelT>
335  : ImageBase<PixelT>(dimensions) {
336  *this = initialValue;
337 }
338 
339 template <typename PixelT>
341  *this = initialValue;
342 }
343 
344 template <typename PixelT>
345 Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
346 // Delegate to copy-constructor for backwards compatibility
347 template <typename PixelT>
348 Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
349 
350 template <typename PixelT>
352  bool const deep)
353  : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
354 
355 template <typename PixelT>
357  this->ImageBase<PixelT>::operator=(rhs);
358 
359  return *this;
360 }
361 
362 template <typename PixelT>
364  this->ImageBase<PixelT>::operator=(rhs);
365 
366  return *this;
367 }
368 // Delegate to copy-assignment for backwards compatibility
369 template <typename PixelT>
371  return *this = rhs;
372 }
373 
374 #ifndef DOXYGEN // doc for this section has been moved to header
375 
376 template <typename PixelT>
378  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe)
379 {
380  ImageFitsReader reader(fileName, hdu);
381  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
382  if (metadata) {
383  metadata->combine(reader.readMetadata());
384  }
385 }
386 
387 template <typename PixelT>
388 Image<PixelT>::Image(fits::MemFileManager& manager, int const hdu,
390  ImageOrigin const origin, bool allowUnsafe)
391 {
392  ImageFitsReader reader(manager, hdu);
393  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
394  if (metadata) {
395  metadata->combine(reader.readMetadata());
396  }
397 }
398 
399 template <typename PixelT>
401  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe)
402 {
403  ImageFitsReader reader(&fitsFile);
404  *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
405  if (metadata) {
406  metadata->combine(reader.readMetadata());
407  }
408 }
409 
410 template <typename PixelT>
411 void Image<PixelT>::writeFits(std::string const& fileName,
413  std::string const& mode) const {
414  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
415  writeFits(fitsfile, metadata_i);
416 }
417 
418 template <typename PixelT>
421  std::string const& mode) const {
422  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
423  writeFits(fitsfile, metadata_i);
424 }
425 
426 template <typename PixelT>
427 void Image<PixelT>::writeFits(fits::Fits& fitsfile,
429  fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
430 }
431 
432 template <typename PixelT>
435  std::shared_ptr<Mask<MaskPixel> const> mask) const {
436  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
437  writeFits(fitsfile, options, header, mask);
438 }
439 
440 template <typename PixelT>
443  std::shared_ptr<Mask<MaskPixel> const> mask) const {
444  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
445  writeFits(fitsfile, options, header, mask);
446 }
447 
448 template <typename PixelT>
449 void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
451  std::shared_ptr<Mask<MaskPixel> const> mask) const {
452  fitsfile.writeImage(*this, options, header, mask);
453 }
454 
455 #endif // !DOXYGEN
456 
457 template <typename PixelT>
459  using std::swap; // See Meyers, Effective C++, Item 25
461  ; // no private variables to swap
462 }
463 
464 template <typename PixelT>
466  a.swap(b);
467 }
468 
469 // In-place, per-pixel, sqrt().
470 template <typename PixelT>
472  transform_pixels(_getRawView(), _getRawView(),
473  [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
474 }
475 
476 template <typename PixelT>
478  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
479  return *this;
480 }
481 
482 template <typename PixelT>
484  if (this->getDimensions() != rhs.getDimensions()) {
486  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
487  this->getHeight() % rhs.getWidth() % rhs.getHeight())
488  .str());
489  }
490  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
491  [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
492  return *this;
493 }
494 
495 template <typename PixelT>
497  for (int y = 0; y != this->getHeight(); ++y) {
498  double const yPos = this->indexToPosition(y, Y);
499  double xPos = this->indexToPosition(0, X);
500  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
501  ++ptr, ++xPos) {
502  *ptr += function(xPos, yPos);
503  }
504  }
505  return *this;
506 }
507 
508 template <typename PixelT>
509 void Image<PixelT>::scaledPlus(double const c, Image<PixelT> const& rhs) {
510  if (this->getDimensions() != rhs.getDimensions()) {
512  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
513  this->getHeight() % rhs.getWidth() % rhs.getHeight())
514  .str());
515  }
516  transform_pixels(
517  _getRawView(), rhs._getRawView(), _getRawView(),
518  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + static_cast<PixelT>(c * r); });
519 }
520 
521 template <typename PixelT>
523  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
524  return *this;
525 }
526 
527 template <typename PixelT>
529  if (this->getDimensions() != rhs.getDimensions()) {
531  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
532  this->getHeight() % rhs.getWidth() % rhs.getHeight())
533  .str());
534  }
535  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
536  [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
537  return *this;
538 }
539 
540 template <typename PixelT>
541 void Image<PixelT>::scaledMinus(double const c, Image<PixelT> const& rhs) {
542  if (this->getDimensions() != rhs.getDimensions()) {
544  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
545  this->getHeight() % rhs.getWidth() % rhs.getHeight())
546  .str());
547  }
548  transform_pixels(
549  _getRawView(), rhs._getRawView(), _getRawView(),
550  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - static_cast<PixelT>(c * r); });
551 }
552 
553 template <typename PixelT>
555  for (int y = 0; y != this->getHeight(); ++y) {
556  double const yPos = this->indexToPosition(y, Y);
557  double xPos = this->indexToPosition(0, X);
558  for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
559  ++ptr, ++xPos) {
560  *ptr -= function(xPos, yPos);
561  }
562  }
563  return *this;
564 }
565 
566 template <typename PixelT>
568  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
569  return *this;
570 }
571 
572 template <typename PixelT>
574  if (this->getDimensions() != rhs.getDimensions()) {
576  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
577  this->getHeight() % rhs.getWidth() % rhs.getHeight())
578  .str());
579  }
580  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
581  [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
582  return *this;
583 }
584 
585 template <typename PixelT>
586 void Image<PixelT>::scaledMultiplies(double const c, Image<PixelT> const& rhs) {
587  if (this->getDimensions() != rhs.getDimensions()) {
589  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
590  this->getHeight() % rhs.getWidth() % rhs.getHeight())
591  .str());
592  }
593  transform_pixels(
594  _getRawView(), rhs._getRawView(), _getRawView(),
595  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * static_cast<PixelT>(c * r); });
596 }
597 
598 template <typename PixelT>
600  transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
601  return *this;
602 }
603 //
604 // Specialize float and double for efficiency
605 //
606 template <>
608  double const irhs = 1 / rhs;
609  *this *= irhs;
610  return *this;
611 }
612 
613 template <>
615  float const irhs = 1 / rhs;
616  *this *= irhs;
617  return *this;
618 }
619 
620 template <typename PixelT>
622  if (this->getDimensions() != rhs.getDimensions()) {
624  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
625  this->getHeight() % rhs.getWidth() % rhs.getHeight())
626  .str());
627  }
628  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
629  [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
630  return *this;
631 }
632 
633 template <typename PixelT>
634 void Image<PixelT>::scaledDivides(double const c, Image<PixelT> const& rhs) {
635  if (this->getDimensions() != rhs.getDimensions()) {
637  (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
638  this->getHeight() % rhs.getWidth() % rhs.getHeight())
639  .str());
640  }
641  transform_pixels(
642  _getRawView(), rhs._getRawView(), _getRawView(),
643  [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / static_cast<PixelT>(c * r); });
644 }
645 
646 namespace {
647 /*
648  * Worker routine for manipulating images;
649  */
650 template <typename LhsPixelT, typename RhsPixelT>
651 struct plusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
652  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
653  return static_cast<LhsPixelT>(lhs + rhs);
654  }
655 };
656 
657 template <typename LhsPixelT, typename RhsPixelT>
658 struct minusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
659  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
660  return static_cast<LhsPixelT>(lhs - rhs);
661  }
662 };
663 
664 template <typename LhsPixelT, typename RhsPixelT>
665 struct timesEq : public pixelOp2<LhsPixelT, RhsPixelT> {
666  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
667  return static_cast<LhsPixelT>(lhs * rhs);
668  }
669 };
670 
671 template <typename LhsPixelT, typename RhsPixelT>
672 struct divideEq : public pixelOp2<LhsPixelT, RhsPixelT> {
673  LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
674  return static_cast<LhsPixelT>(lhs / rhs);
675  }
676 };
677 } // namespace
678 
679 template <typename LhsPixelT, typename RhsPixelT>
681  for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
682  return lhs;
683 }
684 
685 template <typename LhsPixelT, typename RhsPixelT>
687  for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
688  return lhs;
689 }
690 
691 template <typename LhsPixelT, typename RhsPixelT>
693  for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
694  return lhs;
695 }
696 
697 template <typename LhsPixelT, typename RhsPixelT>
699  for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
700  return lhs;
701 }
702 
705  if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
706  dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
707  } else {
708  dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
709  }
711  return lsst::geom::Box2I(xy0, dims);
712 }
713 
714 template <typename T1, typename T2>
715 bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
716  auto arr1 = image1.getArray();
717  // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
718  // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
719  auto beg1Addr = arr1.front().begin();
720  auto end1Addr = arr1.back().end();
721 
722  auto arr2 = image2.getArray();
723  auto beg2Addr = arr2.front().begin();
724  auto end2Addr = arr2.back().end();
725 
726  auto ptrLess = std::less<void const* const>();
727  return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
728 }
729 
730 //
731 // Explicit instantiations
732 //
734 #define INSTANTIATE_OPERATOR(OP_EQ, T) \
735  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
736  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
737  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
738  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
739  template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
740 
741 #define INSTANTIATE(T) \
742  template class ImageBase<T>; \
743  template class Image<T>; \
744  INSTANTIATE_OPERATOR(+=, T); \
745  INSTANTIATE_OPERATOR(-=, T); \
746  INSTANTIATE_OPERATOR(*=, T); \
747  INSTANTIATE_OPERATOR(/=, T)
748 
749 #define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
750 
752 INSTANTIATE(int);
753 INSTANTIATE(float);
754 INSTANTIATE(double);
756 
760 INSTANTIATE2(std::uint16_t, double);
762 
764 INSTANTIATE2(int, int);
765 INSTANTIATE2(int, float);
766 INSTANTIATE2(int, double);
768 
770 INSTANTIATE2(float, int);
771 INSTANTIATE2(float, float);
772 INSTANTIATE2(float, double);
774 
775 INSTANTIATE2(double, std::uint16_t);
776 INSTANTIATE2(double, int);
777 INSTANTIATE2(double, float);
778 INSTANTIATE2(double, double);
779 INSTANTIATE2(double, std::uint64_t);
780 
784 INSTANTIATE2(std::uint64_t, double);
786 
788 } // namespace image
789 } // namespace afw
790 } // 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:680
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:183
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:218
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:296
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:120
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:171
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:715
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:252
table::Box2IKey bbox
Definition: Detector.cc:166
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:465
#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:692
reverse_iterator rend() const
Return an STL compliant reverse iterator to the end of the image.
Definition: Image.cc:284
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:686
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:279
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:269
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:698
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:289
T sqrt(T... args)
lsst::geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: ImageBase.h:374
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
Definition: fits.h:476
_view_t _getRawView() const
Definition: ImageBase.h:483
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:52
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:458
lsst::geom::Box2I bboxFromMetadata(daf::base::PropertySet &metadata)
Determine the image bounding box from its metadata (FITS header)
Definition: Image.cc:703
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:312
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:72