lsst.meas.base  14.0-17-g4f4ea82+3
PixelFlags.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2008-2013 LSST Corporation.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #include <cctype> // ::tolower
25 #include <algorithm> // std::transform
26 #include <cmath>
27 
28 #include "ndarray/eigen.h"
29 
30 #include "lsst/afw/detection/Psf.h"
31 #include "lsst/afw/table/Source.h"
32 #include "lsst/afw/geom/Point.h"
33 #include "lsst/afw/geom/SpanSet.h"
35 
36 namespace lsst { namespace meas { namespace base {
37 namespace {
38 template <typename MaskedImageT>
39 class FootprintBits {
40 public:
41  explicit FootprintBits() : _bits(0) {}
42 
44  void reset() {
45  _bits = 0x0;
46  }
47 
48  void operator()(lsst::afw::geom::Point2I const & point,
49  typename MaskedImageT::Mask::Pixel const & value) {
50  _bits |= value;
51  }
52 
54  typename MaskedImageT::Mask::Pixel getBits() const { return _bits; }
55 private:
56  typename MaskedImageT::Mask::Pixel _bits;
57 };
58 
59 typedef afw::image::MaskedImage<float> MaskedImageF;
60 
61 void updateFlags(PixelFlagsAlgorithm::KeyMap const & maskFlagToPixelFlag, const FootprintBits<MaskedImageF> & func,
62  afw::table::SourceRecord & measRecord) {
63  for (auto const & i: maskFlagToPixelFlag) {
64  try {
65  if (func.getBits() & MaskedImageF::Mask::getPlaneBitMask(i.first)) {
66  measRecord.set(i.second, true);
67  }
68  }
69  catch (pex::exceptions::InvalidParameterError & err) {
70  throw LSST_EXCEPT(FatalAlgorithmError, err.what());
71  }
72  }
73  }
74 } // end anonymous namespace
75 
77  Control const & ctrl,
78  std::string const & name,
79  afw::table::Schema & schema
80 ) : _ctrl(ctrl) {
81  // Add generic keys first, which don't correspond to specific mask planes
82  _generalFailureKey = schema.addField<afw::table::Flag>(name + "_flag",
83  "general failure flag, set if anything went wring");
84  _offImageKey = schema.addField<afw::table::Flag>(name+"_flag" + "_offimage",
85  "Source center is off image");
86  // Set all the flags that correspond to mask planes anywhere in the footprint
87  _anyKeys["EDGE"] = schema.addField<afw::table::Flag>(name + "_flag_edge",
88  "Source is outside usable exposure region (masked EDGE or NO_DATA)");
89  _anyKeys["INTRP"] = schema.addField<afw::table::Flag>(name + "_flag_interpolated",
90  "Interpolated pixel in the Source footprint");
91  _anyKeys["SAT"] = schema.addField<afw::table::Flag>(name + "_flag_saturated",
92  "Saturated pixel in the Source footprint");
93  _anyKeys["CR"] = schema.addField<afw::table::Flag>(name + "_flag_cr",
94  "Cosmic ray in the Source footprint");
95  _anyKeys["BAD"] = schema.addField<afw::table::Flag>(name + "_flag_bad",
96  "Bad pixel in the Source footprint");
97  _anyKeys["SUSPECT"] = schema.addField<afw::table::Flag>(name + "_flag_suspect",
98  "Source's footprint includes suspect pixels");
99  // Flags that correspond to mask bits which occur in the center of the object
100  _centerKeys["INTRP"] = schema.addField<afw::table::Flag>(name + "_flag_interpolatedCenter",
101  "Interpolated pixel in the Source center");
102  _centerKeys["SAT"] = schema.addField<afw::table::Flag>(name + "_flag_saturatedCenter",
103  "Saturated pixel in the Source center");
104  _centerKeys["CR"] = schema.addField<afw::table::Flag>(name + "_flag_crCenter",
105  "Cosmic ray in the Source center");
106  _centerKeys["SUSPECT"] = schema.addField<afw::table::Flag>(name + "_flag_suspectCenter",
107  "Source's center is close to suspect pixels");
108 
109  // Read in the flags passed from the configuration, and add them to the schema
110  for (auto const & i: _ctrl.masksFpCenter) {
111  std::string maskName(i);
112  std::transform(maskName.begin(), maskName.end(), maskName.begin(), ::tolower);
113  _centerKeys[i] = schema.addField<afw::table::Flag>(name + "_flag_" + maskName + "Center",
114  "Source center is close to "+ i + " pixels");
115  }
116 
117  for (auto const & i: _ctrl.masksFpAnywhere) {
118  std::string maskName(i);
119  std::transform(maskName.begin(), maskName.end(), maskName.begin(), ::tolower);
120  _anyKeys[i] = schema.addField<afw::table::Flag>(name + "_flag_" + maskName,
121  "Source footprint includes " + i + " pixels");
122  }
123 }
124 
126  afw::table::SourceRecord & measRecord,
127  afw::image::Exposure<float> const & exposure
128 ) const {
129 
130  MaskedImageF mimage = exposure.getMaskedImage();
131  FootprintBits<MaskedImageF> func;
132 
133  // Check if the measRecord has a valid centroid key, i.e. it was centroided
134  afw::geom::Point2D center;
135  if (measRecord.getTable()->getCentroidKey().isValid()) {
136  center = measRecord.getCentroid();
137  // Catch NAN in centroid estimate
138  if (std::isnan(center.getX()) || std::isnan(center.getY())) {
140  "Center point passed to PixelFlagsAlgorithm is NaN");
141  }
142  }
143  else {
144  // Set the general failure flag because using the Peak might affect
145  // the current measurement
146  measRecord.set(_generalFailureKey, true);
147  // Attempting to set pixel flags with no centroider, the center will
148  // be determined though the peak pixel. The first peak in the
149  // footprint (supplied by the measurement framework) should be the
150  // highest peak so that one will be used as a proxy for the central
151  // tendency of the distribution of flux for the record.
152  PTR(afw::detection::Footprint) footprint = measRecord.getFootprint();
153  // If there is no footprint or the footprint contains no peaks, throw
154  // a runtime error.
155  if (!footprint || footprint->getPeaks().empty()) {
156  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "No footprint, or no footprint peaks detected");
157  }
158  else {
159  center.setX(footprint->getPeaks().front().getFx());
160  center.setY(footprint->getPeaks().front().getFy());
161  }
162  }
163 
164  // Catch centroids off the image
165  if (!mimage.getBBox().contains(afw::geom::Point2I(center))) {
166  measRecord.set(_offImageKey, true);
167  measRecord.set(_anyKeys.at("EDGE"), true);
168  }
169 
170  // Check for bits set in the source's Footprint
171  afw::detection::Footprint const & footprint(*measRecord.getFootprint());
172  footprint.getSpans()->clippedTo(mimage.getBBox())->applyFunctor(func, *(mimage.getMask()));
173 
174  // Set the EDGE flag if the bitmask has NO_DATA set
175  try {
176  if (func.getBits() & MaskedImageF::Mask::getPlaneBitMask("NO_DATA")) {
177  measRecord.set(_anyKeys.at("EDGE"), true);
178  }
180  throw LSST_EXCEPT(FatalAlgorithmError, err.what());
181  }
182 
183  // update the source record for the any keys
184  updateFlags(_anyKeys, func, measRecord);
185 
186  // Check for bits set in the 3x3 box around the center
187  afw::geom::Point2I llc(afw::image::positionToIndex(center.getX()) - 1,
188  afw::image::positionToIndex(center.getY()) - 1);
189 
190  func.reset();
191  auto spans = std::make_shared<afw::geom::SpanSet>(afw::geom::Box2I(llc, afw::geom::ExtentI(3)));
192  afw::detection::Footprint const middle(spans); // central 3x3
193  middle.getSpans()->clippedTo(mimage.getBBox())->applyFunctor(func, *(mimage.getMask()));
194 
195  // Update the flags which have to do with the center of the footprint
196  updateFlags(_centerKeys, func, measRecord);
197 
198 }
199 
201  measRecord.set(_generalFailureKey, true);
202 }
203 
204 }}} // namespace lsst::meas::base
int positionToIndex(double pos)
std::map< std::string, afw::table::Key< afw::table::Flag > > KeyMap
Definition: PixelFlags.h:81
std::shared_ptr< Footprint > getFootprint() const
#define PTR(...)
T end(T... args)
Key< T > addField(Field< T > const &field, bool doReplace=false)
Exception to be thrown when a measurement algorithm experiences a known failure mode.
Definition: exceptions.h:48
Exception to be thrown when a measurement algorithm experiences a fatal error.
Definition: exceptions.h:83
STL class.
T at(T... args)
MaskedImageT getMaskedImage()
std::shared_ptr< SourceTable const > getTable() const
PixelFlagsAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
Definition: PixelFlags.cc:76
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=nullptr) const
Handle an exception thrown by the current algorithm by setting flags in the given record...
Definition: PixelFlags.cc:200
#define LSST_EXCEPT(type,...)
virtual char const * what(void) const
A C++ control class to handle PixelFlagsAlgorithm&#39;s configuration.
Definition: PixelFlags.h:42
T begin(T... args)
std::vector< std::string > masksFpCenter
"List of mask planes to be searched for which occur in the center of a footprint. " "If any of the pl...
Definition: PixelFlags.h:46
T isnan(T... args)
void set(Key< T > const &key, U const &value)
std::shared_ptr< geom::SpanSet > getSpans() const
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Called to measure a single child source in an image.
Definition: PixelFlags.cc:125
T transform(T... args)
This is the algorithm for PixelFlags.
std::vector< std::string > masksFpAnywhere
"List of mask planes to be searched for which occur anywhere within a footprint. " "If any of the pla...
Definition: PixelFlags.h:49
CentroidSlotDefinition::MeasValue getCentroid() const