LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
_saturated.cc
Go to the documentation of this file.
1/*
2 * Handle saturated pixels when making colour images
3 */
4#include <cmath>
5#include "boost/format.hpp"
8#include "Rgb.h"
9
10namespace lsst {
11namespace afw {
12namespace display {
13
14namespace {
15template <typename ImageT>
16class SetPixels {
17public:
18 explicit SetPixels() {}
19
20 void setValue(float value) { _value = value; }
21
22 void operator()(lsst::geom::Point2I const& point, typename ImageT::Pixel& arrayInput) {
23 arrayInput = _value;
24 }
25
26private:
27 float _value{0};
28};
29} // namespace
30
31template <typename ImageT>
32void replaceSaturatedPixels(ImageT& rim, // R image (e.g. i)
33 ImageT& gim, // G image (e.g. r)
34 ImageT& bim, // B image (e.g. g)
35 int borderWidth, // width of border used to estimate colour of saturated regions
36 float saturatedPixelValue // the brightness of a saturated pixel, once fixed
37) {
38 int const width = rim.getWidth(), height = rim.getHeight();
39 int const x0 = rim.getX0(), y0 = rim.getY0();
40
41 if (width != gim.getWidth() || height != gim.getHeight() || x0 != gim.getX0() || y0 != gim.getY0()) {
42 throw LSST_EXCEPT(
44 str(boost::format("R image has different size/origin from G image "
45 "(%dx%d+%d+%d v. %dx%d+%d+%d") %
46 width % height % x0 % y0 % gim.getWidth() % gim.getHeight() % gim.getX0() % gim.getY0()));
47 }
48 if (width != bim.getWidth() || height != bim.getHeight() || x0 != bim.getX0() || y0 != bim.getY0()) {
49 throw LSST_EXCEPT(
51 str(boost::format("R image has different size/origin from B image "
52 "(%dx%d+%d+%d v. %dx%d+%d+%d") %
53 width % height % x0 % y0 % bim.getWidth() % bim.getHeight() % bim.getX0() % bim.getY0()));
54 }
55
56 bool const useMaxPixel = !std::isfinite(saturatedPixelValue);
57
58 SetPixels<typename ImageT::Image> setR, setG, setB; // functors used to set pixel values
59
60 // Find all the saturated pixels in any of the three image
61 int const npixMin = 1; // minimum number of pixels in an object
62 afw::image::MaskPixel const SAT = rim.getMask()->getPlaneBitMask("SAT");
64
65 detection::FootprintSet sat(*rim.getMask(), satThresh, npixMin);
66 sat.merge(detection::FootprintSet(*gim.getMask(), satThresh, npixMin));
67 sat.merge(detection::FootprintSet(*bim.getMask(), satThresh, npixMin));
68 // go through the list of saturated regions, determining the mean colour of the surrounding pixels
69 using FootprintList = detection::FootprintSet::FootprintList;
71 for (const auto& foot : *feet) {
72 auto const bigFoot = std::make_shared<detection::Footprint>(foot->getSpans()->dilated(borderWidth),
73 foot->getRegion());
74
75 double sumR = 0, sumG = 0, sumB = 0; // sum of all non-saturated adjoining pixels
76 double maxR = 0, maxG = 0, maxB = 0; // maximum of non-saturated adjoining pixels
77
78 for (auto span : *bigFoot->getSpans()) {
79 int const y = span.getY() - y0;
80 if (y < 0 || y >= height) {
81 continue;
82 }
83 int sx0 = span.getX0() - x0;
84 if (sx0 < 0) {
85 sx0 = 0;
86 }
87 int sx1 = span.getX1() - x0;
88 if (sx1 >= width) {
89 sx1 = width - 1;
90 }
91
92 for (typename ImageT::iterator rptr = rim.at(sx0, y), rend = rim.at(sx1 + 1, y),
93 gptr = gim.at(sx0, y), bptr = bim.at(sx0, y);
94 rptr != rend; ++rptr, ++gptr, ++bptr) {
95 if (!((rptr.mask() | gptr.mask() | bptr.mask()) & SAT)) {
96 float val = rptr.image();
97 sumR += val;
98 if (val > maxR) {
99 maxR = val;
100 }
101
102 val = gptr.image();
103 sumG += val;
104 if (val > maxG) {
105 maxG = val;
106 }
107
108 val = bptr.image();
109 sumB += val;
110 if (val > maxB) {
111 maxB = val;
112 }
113 }
114 }
115 }
116 // OK, we have the mean fluxes for the pixels surrounding this set of saturated pixels
117 // so we can figure out the proper values to use for the saturated ones
118 float R = 0, G = 0, B = 0; // mean intensities
119 if (sumR + sumB + sumG > 0) {
120 if (sumR > sumG) {
121 if (sumR > sumB) {
122 R = useMaxPixel ? maxR : saturatedPixelValue;
123
124 G = (R * sumG) / sumR;
125 B = (R * sumB) / sumR;
126 } else {
127 B = useMaxPixel ? maxB : saturatedPixelValue;
128 R = (B * sumR) / sumB;
129 G = (B * sumG) / sumB;
130 }
131 } else {
132 if (sumG > sumB) {
133 G = useMaxPixel ? maxG : saturatedPixelValue;
134 R = (G * sumR) / sumG;
135 B = (G * sumB) / sumG;
136 } else {
137 B = useMaxPixel ? maxB : saturatedPixelValue;
138 R = (B * sumR) / sumB;
139 G = (B * sumG) / sumB;
140 }
141 }
142 }
143 // Now that we know R, G, and B we can fix the values
144 setR.setValue(R);
145 foot->getSpans()->applyFunctor(setR, *rim.getImage());
146 setG.setValue(G);
147 foot->getSpans()->applyFunctor(setG, *gim.getImage());
148 setB.setValue(B);
149 foot->getSpans()->applyFunctor(setB, *bim.getImage());
150 }
151}
152
154 image::MaskedImage<float>& bim, int borderWidth,
155 float saturatedPixelValue);
156} // namespace display
157} // namespace afw
158} // namespace lsst
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
int y
Definition: SpanSet.cc:48
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:55
std::shared_ptr< FootprintList > getFootprints()
: Return the Footprints of detected objects
Definition: FootprintSet.h:162
void merge(FootprintSet const &rhs, int tGrow=0, int rGrow=0, bool isotropic=true)
Merge a FootprintSet into *this.
std::vector< std::shared_ptr< Footprint > > FootprintList
The FootprintSet's set of Footprints.
Definition: FootprintSet.h:58
A Threshold is used to pass a threshold value to detection algorithms.
Definition: Threshold.h:43
@ BITMASK
Use (pixels & (given mask))
Definition: Threshold.h:48
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:73
Reports invalid arguments.
Definition: Runtime.h:66
T isfinite(T... args)
void replaceSaturatedPixels(ImageT &rim, ImageT &gim, ImageT &bim, int borderWidth, float saturatedPixelValue)
Definition: _saturated.cc:32
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
ImageT val
Definition: CR.cc:146