LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
Image.cc
Go to the documentation of this file.
1// -*- lsst-c++ -*-
2
3/*
4 * LSST Data Management System
5 * Copyright 2008-2016 AURA/LSST.
6 *
7 * This product includes software developed by the
8 * LSST Project (http://www.lsst.org/).
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the LSST License Statement and
21 * the GNU General Public License along with this program. If not,
22 * see <http://www.lsstcorp.org/LegalNotices/>.
23 */
24
25/*
26 * Implementation for ImageBase and Image
27 */
28#include <cstdint>
29#include <functional>
30#include "boost/format.hpp"
31#include "boost/gil.hpp"
32
33#include "lsst/pex/exceptions.h"
37#include "lsst/afw/fits.h"
39
40namespace lsst {
41namespace afw {
42namespace image {
43
44template <typename PixelT>
45typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_allocateView(lsst::geom::Extent2I const& dimensions,
46 Manager::Ptr& manager) {
47 if (dimensions.getX() < 0 || dimensions.getY() < 0) {
49 str(boost::format("Both width and height must be non-negative: %d, %d") %
50 dimensions.getX() % dimensions.getY()));
51 }
52 if (dimensions.getX() != 0 && dimensions.getY() > std::numeric_limits<int>::max() / dimensions.getX()) {
54 str(boost::format("Image dimensions (%d x %d) too large; int overflow detected.") %
55 dimensions.getX() % dimensions.getY()));
56 }
58 ndarray::SimpleManager<PixelT>::allocate(dimensions.getX() * dimensions.getY());
59 manager = r.first;
60 return boost::gil::interleaved_view(dimensions.getX(), dimensions.getY(),
61 (typename _view_t::value_type*)r.second,
62 dimensions.getX() * sizeof(PixelT));
63}
64template <typename PixelT>
65typename ImageBase<PixelT>::_view_t ImageBase<PixelT>::_makeSubView(lsst::geom::Extent2I const& dimensions,
66 lsst::geom::Extent2I const& offset,
67 const _view_t& view) {
68 if (offset.getX() < 0 || offset.getY() < 0 || offset.getX() + dimensions.getX() > view.width() ||
69 offset.getY() + dimensions.getY() > view.height()) {
70 throw LSST_EXCEPT(
72 (boost::format(
73 "Box2I(Point2I(%d,%d),lsst::geom::Extent2I(%d,%d)) doesn't fit in image %dx%d") %
74 offset.getX() % offset.getY() % dimensions.getX() % dimensions.getY() % view.width() %
75 view.height())
76 .str());
77 }
78 if (dimensions.getX() == 0 && dimensions.getY() == 0
79 && view.width() == 0 && view.height() == 0) {
80 // Getting a zero-extent subview of a zero-extent view returns itself
81 return view;
82 } else {
83 return boost::gil::subimage_view(view, offset.getX(), offset.getY(), dimensions.getX(),
84 dimensions.getY());
85 }
86}
88template <typename PixelT>
90 : _origin(0, 0), _manager(), _gilView(_allocateView(dimensions, _manager)) {}
91
92template <typename PixelT>
94 : _origin(bbox.getMin()), _manager(), _gilView(_allocateView(bbox.getDimensions(), _manager)) {}
95
96template <typename PixelT>
97ImageBase<PixelT>::ImageBase(ImageBase const& rhs, bool const deep
98
99 )
100 : _origin(rhs._origin), _manager(rhs._manager), _gilView(rhs._gilView) {
101 if (deep) {
102 ImageBase tmp(getBBox());
103 tmp.assign(*this); // now copy the pixels
104 swap(tmp);
105 }
106}
107// Delegate to copy-constructor for backwards compatibility
108template <typename PixelT>
110
111template <typename PixelT>
113 bool const deep
114
115 )
116 : _origin((origin == PARENT) ? bbox.getMin() : rhs._origin + lsst::geom::Extent2I(bbox.getMin())),
117 _manager(rhs._manager), // reference counted pointer, don't copy pixels
118 _gilView(_makeSubView(bbox.getDimensions(), _origin - rhs._origin, rhs._gilView)) {
119 if (deep) {
121 tmp.assign(*this); // now copy the pixels
122 swap(tmp);
123 }
124}
125
126template <typename PixelT>
127ImageBase<PixelT>::ImageBase(Array const& array, bool deep, lsst::geom::Point2I const& xy0)
128 : _origin(xy0),
129 _manager(array.getManager()),
130 _gilView(boost::gil::interleaved_view(array.template getSize<1>(), array.template getSize<0>(),
131 (typename _view_t::value_type*)array.getData(),
132 array.template getStride<0>() * sizeof(PixelT))) {
133 if (deep) {
134 ImageBase tmp(*this, true);
135 swap(tmp);
136 }
137}
138
139template <typename PixelT>
141 ImageBase tmp(rhs);
142 swap(tmp); // See Meyers, Effective C++, Item 11
143
144 return *this;
145}
146// Delegate to copy-assignment for backwards compatibility
147template <typename PixelT>
149 return *this = rhs;
150}
151
152template <typename PixelT>
154 auto lhsDim = bbox.isEmpty() ? getDimensions() : bbox.getDimensions();
155 if (lhsDim != rhs.getDimensions()) {
157 (boost::format("Dimension mismatch: %dx%d v. %dx%d") % lhsDim.getX() %
158 lhsDim.getY() % rhs.getWidth() % rhs.getHeight())
159 .str());
160 }
161 if (bbox.isEmpty()) {
162 copy_pixels(rhs._gilView, _gilView);
163 } else {
164 auto lhsOff = (origin == PARENT) ? bbox.getMin() - _origin : lsst::geom::Extent2I(bbox.getMin());
165 auto lhsGilView = _makeSubView(lhsDim, lhsOff, _gilView);
166 copy_pixels(rhs._gilView, lhsGilView);
167 }
168}
169
170template <typename PixelT>
172 return const_cast<typename ImageBase<PixelT>::PixelReference>(
173 static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
174}
176template <typename PixelT>
178 CheckIndices const& check) {
179 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
181 (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
182 (getWidth() - 1) % (getHeight() - 1))
183 .str());
184 }
185
186 return const_cast<typename ImageBase<PixelT>::PixelReference>(
187 static_cast<typename ImageBase<PixelT>::PixelConstReference>(_gilView(x, y)[0]));
188}
189
190template <typename PixelT>
192 return _gilView(x, y)[0];
194
195template <typename PixelT>
197 int x, int y, CheckIndices const& check) const {
198 if (check && (x < 0 || x >= getWidth() || y < 0 || y >= getHeight())) {
200 (boost::format("Index (%d, %d) is out of range [0--%d], [0--%d]") % x % y %
201 (this->getWidth() - 1) % (this->getHeight() - 1))
202 .str());
205 return _gilView(x, y)[0];
206}
207
208template <typename PixelT>
210 ImageOrigin origin) {
211 int x = index.getX();
212 int y = index.getY();
213 if (origin == PARENT) {
214 x -= getX0();
215 y -= getY0();
216 }
217 return _gilView(x, y)[0];
218}
219
220template <typename PixelT>
222 ImageOrigin origin) const {
223 int x = index.getX();
224 int y = index.getY();
225 if (origin == PARENT) {
226 x -= getX0();
227 y -= getY0();
228 }
229 return _gilView(x, y)[0];
230}
231
232template <typename PixelT>
234 using std::swap; // See Meyers, Effective C++, Item 25
235
236 swap(_manager, rhs._manager); // just swapping the pointers
237 swap(_gilView, rhs._gilView);
238 swap(_origin, rhs._origin);
240
241template <typename PixelT>
243 a.swap(b);
244}
245
246//
247// Iterators
248//
249template <typename PixelT>
251 return _gilView.begin();
253
254template <typename PixelT>
256 return _gilView.end();
257}
258
259template <typename PixelT>
261 return _gilView.rbegin();
262}
263
264template <typename PixelT>
266 return _gilView.rend();
268
269template <typename PixelT>
271 return _gilView.at(x, y);
272}
274template <typename PixelT>
276 if (!contiguous) {
277 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
278 }
279 if (!this->isContiguous()) {
280 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
281 }
283 return row_begin(0);
284}
286template <typename PixelT>
288 if (!contiguous) {
289 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Only contiguous == true makes sense");
290 }
291 if (!this->isContiguous()) {
292 throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Image's pixels are not contiguous");
293 }
294
295 return row_end(getHeight() - 1);
296}
297
298template <typename PixelT>
300 fill_pixels(_gilView, rhs);
301
302 return *this;
303}
304
305//
306// On to Image itself. ctors, cctors, and operator=
307//
308template <typename PixelT>
309Image<PixelT>::Image(unsigned int width, unsigned int height, PixelT initialValue)
310 : ImageBase<PixelT>(lsst::geom::ExtentI(width, height)) {
311 *this = initialValue;
312}
313
314template <typename PixelT>
316 : ImageBase<PixelT>(dimensions) {
317 *this = initialValue;
318}
319
320template <typename PixelT>
321Image<PixelT>::Image(lsst::geom::Box2I const& bbox, PixelT initialValue) : ImageBase<PixelT>(bbox) {
322 *this = initialValue;
323}
324
325template <typename PixelT>
326Image<PixelT>::Image(Image const& rhs, bool const deep) : ImageBase<PixelT>(rhs, deep) {}
327// Delegate to copy-constructor for backwards compatibility
328template <typename PixelT>
329Image<PixelT>::Image(Image&& rhs) : Image(rhs, false) {}
330
331template <typename PixelT>
333 bool const deep)
334 : ImageBase<PixelT>(rhs, bbox, origin, deep) {}
335
336template <typename PixelT>
339
340 return *this;
341}
342
343template <typename PixelT>
346
347 return *this;
348}
349// Delegate to copy-assignment for backwards compatibility
350template <typename PixelT>
352 return *this = rhs;
353}
354
355#ifndef DOXYGEN // doc for this section has been moved to header
356
357template <typename PixelT>
359 lsst::geom::Box2I const& bbox, ImageOrigin origin, bool allowUnsafe) {
360 ImageFitsReader reader(fileName, hdu);
361 *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
362 if (metadata) {
363 metadata->combine(*reader.readMetadata());
364 }
366
367template <typename PixelT>
368Image<PixelT>::Image(fits::MemFileManager& manager, int const hdu,
370 ImageOrigin const origin, bool allowUnsafe) {
371 ImageFitsReader reader(manager, hdu);
372 *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
373 if (metadata) {
374 metadata->combine(*reader.readMetadata());
378template <typename PixelT>
380 lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool allowUnsafe) {
381 ImageFitsReader reader(&fitsFile);
382 *this = reader.read<PixelT>(bbox, origin, allowUnsafe);
383 if (metadata) {
384 metadata->combine(*reader.readMetadata());
386}
388template <typename PixelT>
390 daf::base::PropertySet const * metadata_i,
391 std::string const& mode) const {
392 fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
393 writeFits(fitsfile, metadata_i);
394}
396template <typename PixelT>
399 std::string const& mode) const {
400 writeFits(fileName, metadata_i.get(), mode);
402
403template <typename PixelT>
405 daf::base::PropertySet const * metadata_i,
406 std::string const& mode) const {
408 writeFits(fitsfile, metadata_i);
409}
410
411template <typename PixelT>
414 std::string const& mode) const {
415 writeFits(manager, metadata_i.get(), mode);
416}
417
418template <typename PixelT>
420 daf::base::PropertySet const * metadata) const {
421 fitsfile.writeImage(*this, fits::ImageWriteOptions(*this), metadata);
422}
423
424template <typename PixelT>
425void Image<PixelT>::writeFits(fits::Fits& fitsfile,
427 writeFits(fitsfile, metadata.get());
428}
429
430template <typename PixelT>
431void Image<PixelT>::writeFits(std::string const& filename, fits::ImageWriteOptions const& options,
432 std::string const& mode, daf::base::PropertySet const * header,
433 Mask<MaskPixel> const * mask) const {
434 fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
435 writeFits(fitsfile, options, header, mask);
436}
437
438template <typename PixelT>
439void Image<PixelT>::writeFits(std::string const& filename, fits::ImageWriteOptions const& options,
441 std::shared_ptr<Mask<MaskPixel> const> mask) const {
442 writeFits(filename, options, mode, header.get(), mask.get());
443}
444
445template <typename PixelT>
446void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions const& options,
447 std::string const& mode, daf::base::PropertySet const * header,
448 Mask<MaskPixel> const * mask) const {
449 fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
450 writeFits(fitsfile, options, header, mask);
451}
452
453template <typename PixelT>
454void Image<PixelT>::writeFits(fits::MemFileManager& manager, fits::ImageWriteOptions const& options,
456 std::shared_ptr<Mask<MaskPixel> const> mask) const {
457 writeFits(manager, options, mode, header.get(), mask.get());
458}
459
460template <typename PixelT>
463 Mask<MaskPixel> const * mask) const {
464 fitsfile.writeImage(*this, options, header, mask);
465}
466
467template <typename PixelT>
468void Image<PixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
470 std::shared_ptr<Mask<MaskPixel> const> mask) const {
471 writeFits(fitsfile, options, header.get(), mask.get());
472}
473
474#endif // !DOXYGEN
475
476template <typename PixelT>
478 using std::swap; // See Meyers, Effective C++, Item 25
480}
481
482template <typename PixelT>
484 a.swap(b);
485}
486
487// In-place, per-pixel, sqrt().
488template <typename PixelT>
490 transform_pixels(_getRawView(), _getRawView(),
491 [](PixelT const& l) -> PixelT { return static_cast<PixelT>(std::sqrt(l)); });
492}
493
494template <typename PixelT>
496 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l + rhs; });
497 return *this;
498}
499
500template <typename PixelT>
502 if (this->getDimensions() != rhs.getDimensions()) {
504 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
505 this->getHeight() % rhs.getWidth() % rhs.getHeight())
506 .str());
507 }
508 transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
509 [](PixelT const& l, PixelT const& r) -> PixelT { return l + r; });
510 return *this;
511}
512
513template <typename PixelT>
515 for (int y = 0; y != this->getHeight(); ++y) {
516 double const yPos = this->indexToPosition(y, Y);
517 double xPos = this->indexToPosition(0, X);
518 for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
519 ++ptr, ++xPos) {
520 *ptr += function(xPos, yPos);
521 }
522 }
523 return *this;
524}
525
526template <typename PixelT>
527void Image<PixelT>::scaledPlus(PixelT const c, Image<PixelT> const& rhs) {
528 if (this->getDimensions() != rhs.getDimensions()) {
530 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
531 this->getHeight() % rhs.getWidth() % rhs.getHeight())
532 .str());
533 }
534 transform_pixels(
535 _getRawView(), rhs._getRawView(), _getRawView(),
536 [&c](PixelT const& l, PixelT const& r) -> PixelT { return l + (c * r); });
537}
538
539template <typename PixelT>
541 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l - rhs; });
542 return *this;
543}
544
545template <typename PixelT>
547 if (this->getDimensions() != rhs.getDimensions()) {
549 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
550 this->getHeight() % rhs.getWidth() % rhs.getHeight())
551 .str());
552 }
553 transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
554 [](PixelT const& l, PixelT const& r) -> PixelT { return l - r; });
555 return *this;
556}
557
558template <typename PixelT>
559void Image<PixelT>::scaledMinus(PixelT const c, Image<PixelT> const& rhs) {
560 if (this->getDimensions() != rhs.getDimensions()) {
562 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
563 this->getHeight() % rhs.getWidth() % rhs.getHeight())
564 .str());
565 }
566 transform_pixels(
567 _getRawView(), rhs._getRawView(), _getRawView(),
568 [&c](PixelT const& l, PixelT const& r) -> PixelT { return l - (c * r); });
569}
570
571template <typename PixelT>
573 for (int y = 0; y != this->getHeight(); ++y) {
574 double const yPos = this->indexToPosition(y, Y);
575 double xPos = this->indexToPosition(0, X);
576 for (typename Image<PixelT>::x_iterator ptr = this->row_begin(y), end = this->row_end(y); ptr != end;
577 ++ptr, ++xPos) {
578 *ptr -= function(xPos, yPos);
579 }
580 }
581 return *this;
582}
583
584template <typename PixelT>
586 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l * rhs; });
587 return *this;
588}
589
590template <typename PixelT>
592 if (this->getDimensions() != rhs.getDimensions()) {
594 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
595 this->getHeight() % rhs.getWidth() % rhs.getHeight())
596 .str());
597 }
598 transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
599 [](PixelT const& l, PixelT const& r) -> PixelT { return l * r; });
600 return *this;
601}
602
603template <typename PixelT>
605 if (this->getDimensions() != rhs.getDimensions()) {
607 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
608 this->getHeight() % rhs.getWidth() % rhs.getHeight())
609 .str());
610 }
611 transform_pixels(
612 _getRawView(), rhs._getRawView(), _getRawView(),
613 [&c](PixelT const& l, PixelT const& r) -> PixelT { return l * (c * r); });
614}
615
616template <typename PixelT>
618 transform_pixels(_getRawView(), _getRawView(), [&rhs](PixelT const& l) -> PixelT { return l / rhs; });
619 return *this;
620}
621//
622// Specialize float and double for efficiency
623//
624template <>
626 double const irhs = 1 / rhs;
627 *this *= irhs;
628 return *this;
629}
630
631template <>
633 float const irhs = 1 / rhs;
634 *this *= irhs;
635 return *this;
636}
637
638template <typename PixelT>
640 if (this->getDimensions() != rhs.getDimensions()) {
642 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
643 this->getHeight() % rhs.getWidth() % rhs.getHeight())
644 .str());
645 }
646 transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
647 [](PixelT const& l, PixelT const& r) -> PixelT { return l / r; });
648 return *this;
649}
650
651template <typename PixelT>
652void Image<PixelT>::scaledDivides(PixelT c, Image<PixelT> const& rhs) {
653 if (this->getDimensions() != rhs.getDimensions()) {
655 (boost::format("Images are of different size, %dx%d v %dx%d") % this->getWidth() %
656 this->getHeight() % rhs.getWidth() % rhs.getHeight())
657 .str());
658 }
659 transform_pixels(
660 _getRawView(), rhs._getRawView(), _getRawView(),
661 [&c](PixelT const& l, PixelT const& r) -> PixelT { return l / (c * r); });
662}
663
664namespace {
665/*
666 * Worker routine for manipulating images;
667 */
668template <typename LhsPixelT, typename RhsPixelT>
669struct plusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
670 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
671 return static_cast<LhsPixelT>(lhs + rhs);
672 }
673};
674
675template <typename LhsPixelT, typename RhsPixelT>
676struct minusEq : public pixelOp2<LhsPixelT, RhsPixelT> {
677 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
678 return static_cast<LhsPixelT>(lhs - rhs);
679 }
680};
681
682template <typename LhsPixelT, typename RhsPixelT>
683struct timesEq : public pixelOp2<LhsPixelT, RhsPixelT> {
684 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
685 return static_cast<LhsPixelT>(lhs * rhs);
686 }
687};
688
689template <typename LhsPixelT, typename RhsPixelT>
690struct divideEq : public pixelOp2<LhsPixelT, RhsPixelT> {
691 LhsPixelT operator()(LhsPixelT lhs, RhsPixelT rhs) const override {
692 return static_cast<LhsPixelT>(lhs / rhs);
693 }
694};
695} // namespace
696
697template <typename LhsPixelT, typename RhsPixelT>
699 for_each_pixel(lhs, rhs, plusEq<LhsPixelT, RhsPixelT>());
700 return lhs;
701}
702
703template <typename LhsPixelT, typename RhsPixelT>
705 for_each_pixel(lhs, rhs, minusEq<LhsPixelT, RhsPixelT>());
706 return lhs;
707}
708
709template <typename LhsPixelT, typename RhsPixelT>
711 for_each_pixel(lhs, rhs, timesEq<LhsPixelT, RhsPixelT>());
712 return lhs;
713}
714
715template <typename LhsPixelT, typename RhsPixelT>
717 for_each_pixel(lhs, rhs, divideEq<LhsPixelT, RhsPixelT>());
718 return lhs;
719}
720
723 if (metadata.exists("ZNAXIS1") && metadata.exists("ZNAXIS2")) {
724 dims = lsst::geom::Extent2I(metadata.getAsInt("ZNAXIS1"), metadata.getAsInt("ZNAXIS2"));
725 } else {
726 dims = lsst::geom::Extent2I(metadata.getAsInt("NAXIS1"), metadata.getAsInt("NAXIS2"));
727 }
728 lsst::geom::Point2I xy0 = geom::getImageXY0FromMetadata(metadata, detail::wcsNameForXY0);
729 return lsst::geom::Box2I(xy0, dims);
730}
731
732template <typename T1, typename T2>
733bool imagesOverlap(ImageBase<T1> const& image1, ImageBase<T2> const& image2) {
734
735 if (image1.getArea() == 0 || image2.getArea() == 0) {
736 // zero-area images cannot overlap.
737 return false;
738 }
739
740 auto arr1 = image1.getArray();
741 // get the address of the first and one-past-the-last element of arr1 using ndarray iterators;
742 // this works because the iterators for contiguous 1-d ndarray Arrays are just pointers
743 auto beg1Addr = arr1.front().begin();
744 auto end1Addr = arr1.back().end();
745
746 auto arr2 = image2.getArray();
747 auto beg2Addr = arr2.front().begin();
748 auto end2Addr = arr2.back().end();
749
750 auto ptrLess = std::less<void const* const>();
751 return ptrLess(beg1Addr, end2Addr) && ptrLess(beg2Addr, end1Addr);
752}
753
754//
755// Explicit instantiations
756//
758#define INSTANTIATE_OPERATOR(OP_EQ, T) \
759 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint16_t> const& rhs); \
760 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<int> const& rhs); \
761 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<float> const& rhs); \
762 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<double> const& rhs); \
763 template Image<T>& operator OP_EQ(Image<T>& lhs, Image<std::uint64_t> const& rhs);
764
765#define INSTANTIATE(T) \
766 template class ImageBase<T>; \
767 template class Image<T>; \
768 INSTANTIATE_OPERATOR(+=, T); \
769 INSTANTIATE_OPERATOR(-=, T); \
770 INSTANTIATE_OPERATOR(*=, T); \
771 INSTANTIATE_OPERATOR(/=, T)
772
773#define INSTANTIATE2(T1, T2) template bool imagesOverlap<T1, T2>(ImageBase<T1> const&, ImageBase<T2> const&);
774
776INSTANTIATE(int);
777INSTANTIATE(float);
778INSTANTIATE(double);
780
786
788INSTANTIATE2(int, int);
789INSTANTIATE2(int, float);
790INSTANTIATE2(int, double);
792
794INSTANTIATE2(float, int);
795INSTANTIATE2(float, float);
796INSTANTIATE2(float, double);
798
800INSTANTIATE2(double, int);
801INSTANTIATE2(double, float);
802INSTANTIATE2(double, double);
804
810
812} // namespace image
813} // namespace afw
814} // namespace lsst
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
int end
double x
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:509
#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:308
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
Definition: fits.h:498
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:125
A class used to request that array accesses be checked.
Definition: ImageBase.h:74
std::shared_ptr< daf::base::PropertyList > readMetadata()
Read the image's FITS header.
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: ImageBase.h:102
iterator end() const
Return an STL compliant iterator to the end of the image.
Definition: Image.cc:255
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:250
static _view_t _allocateView(lsst::geom::Extent2I const &dimensions, Manager::Ptr &manager)
Definition: Image.cc:45
typename Reference< PixelT >::type PixelReference
A Reference to a PixelT.
Definition: ImageBase.h:117
typename _view_t::iterator iterator
An STL compliant iterator.
Definition: ImageBase.h:125
PixelReference operator()(int x, int y)
Return a reference to the pixel (x, y) in LOCAL coordinates.
Definition: Image.cc:171
static _view_t _makeSubView(lsst::geom::Extent2I const &dimensions, lsst::geom::Extent2I const &offset, const _view_t &view)
Definition: Image.cc:65
int getWidth() const
Return the number of columns in the image.
Definition: ImageBase.h:294
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition: ImageBase.h:445
int getArea() const
Return the area of the image.
Definition: ImageBase.h:298
lsst::geom::Extent2I getDimensions() const
Return the image's size; useful for passing to constructors.
Definition: ImageBase.h:356
typename ndarray::Array< PixelT, 2, 1 > Array
A mutable ndarray representation of the image.
Definition: ImageBase.h:149
void assign(ImageBase const &rhs, lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT)
Copy pixels from another image to a specified subregion of this image.
Definition: Image.cc:153
x_iterator fast_iterator
A fast STL compliant iterator for contiguous images N.b.
Definition: ImageBase.h:137
typename _view_t::reverse_iterator reverse_iterator
An STL compliant reverse iterator.
Definition: ImageBase.h:129
int getHeight() const
Return the number of rows in the image.
Definition: ImageBase.h:296
ImageBase & operator=(const ImageBase &rhs)
Shallow assignment operator.
Definition: Image.cc:140
iterator at(int x, int y) const
Return an STL compliant iterator at the point (x, y)
Definition: Image.cc:270
typename _view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
reverse_iterator rbegin() const
Return an STL compliant reverse iterator to the start of the image.
Definition: Image.cc:260
_view_t _getRawView() const
Definition: ImageBase.h:465
PixelReference get(lsst::geom::Point2I const &index, ImageOrigin origin)
Return a reference to a single pixel (with no bounds check).
Definition: Image.cc:209
void swap(ImageBase &rhs)
Definition: Image.cc:233
typename ConstReference< PixelT >::type PixelConstReference
A ConstReference to a PixelT.
Definition: ImageBase.h:119
reverse_iterator rend() const
Return an STL compliant reverse iterator to the end of the image.
Definition: Image.cc:265
A FITS reader class for regular Images.
Image< PixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the Image.
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:51
Image & operator*=(PixelT const rhs)
Multiply lhs by scalar rhs.
Definition: Image.cc:585
Image & operator-=(PixelT const rhs)
Subtract scalar rhs from lhs.
Definition: Image.cc:540
void scaledPlus(PixelT const c, Image< PixelT > const &rhs)
Add Image c*rhs to lhs.
Definition: Image.cc:527
Image & operator=(const PixelT rhs)
Set the image's pixels to rhs.
Definition: Image.cc:337
Image & operator+=(PixelT const rhs)
Add scalar rhs to lhs.
Definition: Image.cc:495
void scaledMinus(PixelT const c, Image< PixelT > const &rhs)
Subtract Image c*rhs from lhs.
Definition: Image.cc:559
void swap(Image &rhs)
Definition: Image.cc:477
Image & operator/=(PixelT const rhs)
Divide lhs by scalar rhs.
Definition: Image.cc:617
void writeFits(std::string const &fileName, daf::base::PropertySet const *metadata=nullptr, std::string const &mode="w") const
Write an image to a regular FITS file.
void scaledDivides(PixelT const c, Image< PixelT > const &rhs)
Divide lhs by Image c*rhs (i.e. pixel-by-pixel division)
Definition: Image.cc:652
void scaledMultiplies(PixelT const c, Image< PixelT > const &rhs)
Multiply lhs by Image c*rhs (i.e. pixel-by-pixel multiplication)
Definition: Image.cc:604
friend class Image
Definition: Image.h:65
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
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
T get(T... args)
Definition: Polygon.cc:24
std::string const wcsNameForXY0
Definition: ImageBase.h:70
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:698
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:704
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:721
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:716
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:710
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:733
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
T sqrt(T... args)
Options for writing an image to FITS.
Definition: fits.h:223
A functor class equivalent to std::function<LhsT (LhsT, RhsT)>, but with a virtual operator()
T swap(T... args)