LSSTApplications  17.0+124,17.0+14,17.0+73,18.0.0+37,18.0.0+80,18.0.0-4-g68ffd23+4,18.1.0-1-g0001055+12,18.1.0-1-g03d53ef+5,18.1.0-1-g1349e88+55,18.1.0-1-g2505f39+44,18.1.0-1-g5315e5e+4,18.1.0-1-g5e4b7ea+14,18.1.0-1-g7e8fceb+4,18.1.0-1-g85f8cd4+48,18.1.0-1-g8ff0b9f+4,18.1.0-1-ga2c679d+1,18.1.0-1-gd55f500+35,18.1.0-10-gb58edde+2,18.1.0-11-g0997b02+4,18.1.0-13-gfe4edf0b+12,18.1.0-14-g259bd21+21,18.1.0-19-gdb69f3f+2,18.1.0-2-g5f9922c+24,18.1.0-2-gd3b74e5+11,18.1.0-2-gfbf3545+32,18.1.0-26-g728bddb4+5,18.1.0-27-g6ff7ca9+2,18.1.0-3-g52aa583+25,18.1.0-3-g8ea57af+9,18.1.0-3-gb69f684+42,18.1.0-3-gfcaddf3+6,18.1.0-32-gd8786685a,18.1.0-4-gf3f9b77+6,18.1.0-5-g1dd662b+2,18.1.0-5-g6dbcb01+41,18.1.0-6-gae77429+3,18.1.0-7-g9d75d83+9,18.1.0-7-gae09a6d+30,18.1.0-9-gc381ef5+4,w.2019.45
LSSTDataManagementBasePackage
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/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) { arrayInput = _value; }
23 
24 private:
25  float _value;
26 };
27 }
28 
29 template <typename ImageT>
30 void replaceSaturatedPixels(ImageT& rim, // R image (e.g. i)
31  ImageT& gim, // G image (e.g. r)
32  ImageT& bim, // B image (e.g. g)
33  int borderWidth, // width of border used to estimate colour of saturated regions
34  float saturatedPixelValue // the brightness of a saturated pixel, once fixed
35  ) {
36  int const width = rim.getWidth(), height = rim.getHeight();
37  int const x0 = rim.getX0(), y0 = rim.getY0();
38 
39  if (width != gim.getWidth() || height != gim.getHeight() || x0 != gim.getX0() || y0 != gim.getY0()) {
40  throw LSST_EXCEPT(
42  str(boost::format("R image has different size/origin from G image "
43  "(%dx%d+%d+%d v. %dx%d+%d+%d") %
44  width % height % x0 % y0 % gim.getWidth() % gim.getHeight() % gim.getX0() % gim.getY0()));
45  }
46  if (width != bim.getWidth() || height != bim.getHeight() || x0 != bim.getX0() || y0 != bim.getY0()) {
47  throw LSST_EXCEPT(
49  str(boost::format("R image has different size/origin from B image "
50  "(%dx%d+%d+%d v. %dx%d+%d+%d") %
51  width % height % x0 % y0 % bim.getWidth() % bim.getHeight() % bim.getX0() % bim.getY0()));
52  }
53 
54  bool const useMaxPixel = !std::isfinite(saturatedPixelValue);
55 
56  SetPixels<typename ImageT::Image> setR, setG, setB; // functors used to set pixel values
57 
58  // Find all the saturated pixels in any of the three image
59  int const npixMin = 1; // minimum number of pixels in an object
60  afw::image::MaskPixel const SAT = rim.getMask()->getPlaneBitMask("SAT");
62 
63  detection::FootprintSet sat(*rim.getMask(), satThresh, npixMin);
64  sat.merge(detection::FootprintSet(*gim.getMask(), satThresh, npixMin));
65  sat.merge(detection::FootprintSet(*bim.getMask(), satThresh, npixMin));
66  // go through the list of saturated regions, determining the mean colour of the surrounding pixels
67  typedef detection::FootprintSet::FootprintList FootprintList;
68  std::shared_ptr<FootprintList> feet = sat.getFootprints();
69  for (FootprintList::const_iterator ptr = feet->begin(), end = feet->end(); ptr != end; ++ptr) {
71  auto const bigFoot = std::make_shared<detection::Footprint>(foot->getSpans()->dilated(borderWidth),
72  foot->getRegion());
73 
74  double sumR = 0, sumG = 0, sumB = 0; // sum of all non-saturated adjoining pixels
75  double maxR = 0, maxG = 0, maxB = 0; // maximum of non-saturated adjoining pixels
76 
77  for (auto span = bigFoot->getSpans()->begin(), send = bigFoot->getSpans()->end(); span != send;
78  ++span) {
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 }
157 }
158 }
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
uint64_t * ptr
Definition: RangeSet.cc:88
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
int y
Definition: SpanSet.cc:49
Use (pixels & (given mask))
Definition: Threshold.h:48
ImageT val
Definition: CR.cc:146
A Threshold is used to pass a threshold value to detection algorithms.
Definition: Threshold.h:43
void replaceSaturatedPixels(ImageT &rim, ImageT &gim, ImageT &bim, int borderWidth=2, float saturatedPixelValue=65535)
Definition: saturated.cc:30
A base class for image defects.
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:73
T isfinite(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53
STL class.
Reports invalid arguments.
Definition: Runtime.h:66
int end
void merge(FootprintSet const &rhs, int tGrow=0, int rGrow=0, bool isotropic=true)
Merge a FootprintSet into *this.