LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
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"
6 #include "lsst/afw/detection.h"
8 #include "Rgb.h"
9 
10 namespace lsst {
11 namespace afw {
12 namespace display {
13 
14 namespace {
15 template <typename ImageT>
16 class SetPixels {
17 public:
18  explicit SetPixels() : _value(0) {}
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 
26 private:
27  float _value;
28 };
29 } // namespace
30 
31 template <typename ImageT>
32 void 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  typedef detection::FootprintSet::FootprintList FootprintList;
71  for (FootprintList::const_iterator ptr = feet->begin(), end = feet->end(); ptr != end; ++ptr) {
73  auto const bigFoot = std::make_shared<detection::Footprint>(foot->getSpans()->dilated(borderWidth),
74  foot->getRegion());
75 
76  double sumR = 0, sumG = 0, sumB = 0; // sum of all non-saturated adjoining pixels
77  double maxR = 0, maxG = 0, maxB = 0; // maximum of non-saturated adjoining pixels
78 
79  for (auto span = bigFoot->getSpans()->begin(), send = bigFoot->getSpans()->end(); span != send;
80  ++span) {
81  int const y = span->getY() - y0;
82  if (y < 0 || y >= height) {
83  continue;
84  }
85  int sx0 = span->getX0() - x0;
86  if (sx0 < 0) {
87  sx0 = 0;
88  }
89  int sx1 = span->getX1() - x0;
90  if (sx1 >= width) {
91  sx1 = width - 1;
92  }
93 
94  for (typename ImageT::iterator rptr = rim.at(sx0, y), rend = rim.at(sx1 + 1, y),
95  gptr = gim.at(sx0, y), bptr = bim.at(sx0, y);
96  rptr != rend; ++rptr, ++gptr, ++bptr) {
97  if (!((rptr.mask() | gptr.mask() | bptr.mask()) & SAT)) {
98  float val = rptr.image();
99  sumR += val;
100  if (val > maxR) {
101  maxR = val;
102  }
103 
104  val = gptr.image();
105  sumG += val;
106  if (val > maxG) {
107  maxG = val;
108  }
109 
110  val = bptr.image();
111  sumB += val;
112  if (val > maxB) {
113  maxB = val;
114  }
115  }
116  }
117  }
118  // OK, we have the mean fluxes for the pixels surrounding this set of saturated pixels
119  // so we can figure out the proper values to use for the saturated ones
120  float R = 0, G = 0, B = 0; // mean intensities
121  if (sumR + sumB + sumG > 0) {
122  if (sumR > sumG) {
123  if (sumR > sumB) {
124  R = useMaxPixel ? maxR : saturatedPixelValue;
125 
126  G = (R * sumG) / sumR;
127  B = (R * sumB) / sumR;
128  } else {
129  B = useMaxPixel ? maxB : saturatedPixelValue;
130  R = (B * sumR) / sumB;
131  G = (B * sumG) / sumB;
132  }
133  } else {
134  if (sumG > sumB) {
135  G = useMaxPixel ? maxG : saturatedPixelValue;
136  R = (G * sumR) / sumG;
137  B = (G * sumB) / sumG;
138  } else {
139  B = useMaxPixel ? maxB : saturatedPixelValue;
140  R = (B * sumR) / sumB;
141  G = (B * sumG) / sumB;
142  }
143  }
144  }
145  // Now that we know R, G, and B we can fix the values
146  setR.setValue(R);
147  foot->getSpans()->applyFunctor(setR, *rim.getImage());
148  setG.setValue(G);
149  foot->getSpans()->applyFunctor(setG, *gim.getImage());
150  setB.setValue(B);
151  foot->getSpans()->applyFunctor(setB, *bim.getImage());
152  }
153 }
154 
156  image::MaskedImage<float>& bim, int borderWidth,
157  float saturatedPixelValue);
158 } // namespace display
159 } // namespace afw
160 } // namespace lsst
int end
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
uint64_t * ptr
Definition: RangeSet.cc:88
int y
Definition: SpanSet.cc:49
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53
std::shared_ptr< FootprintList > getFootprints()
: Return the Footprints of detected objects
Definition: FootprintSet.h:156
void merge(FootprintSet const &rhs, int tGrow=0, int rGrow=0, bool isotropic=true)
Merge a FootprintSet into *this.
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