LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
CentroidUtilities.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008-2014 LSST Corporation.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 #include <cmath>
24 
25 #include "lsst/geom/Angle.h"
26 #include "lsst/geom/Point.h"
29 
30 namespace lsst {
31 namespace meas {
32 namespace base {
33 
35  : x(std::numeric_limits<CentroidElement>::quiet_NaN()),
36  y(std::numeric_limits<CentroidElement>::quiet_NaN()),
37  xErr(std::numeric_limits<ErrElement>::quiet_NaN()),
38  yErr(std::numeric_limits<ErrElement>::quiet_NaN()),
39  x_y_Cov(std::numeric_limits<ErrElement>::quiet_NaN()) {}
40 
41 Centroid const CentroidResult::getCentroid() const { return Centroid(x, y); }
42 
44  x = centroid.getX();
45  y = centroid.getY();
46 }
47 
49  CentroidCov m;
50  m << xErr * xErr, x_y_Cov, x_y_Cov, yErr * yErr;
51  return m;
52 }
53 
55  xErr = std::sqrt(matrix(0, 0));
56  yErr = std::sqrt(matrix(1, 1));
57  x_y_Cov = matrix(0, 1);
58 }
59 
61  xErr = _xErr;
62  yErr = _yErr;
63  x_y_Cov = 0.0;
64 }
65 
67  std::string const &doc, UncertaintyEnum uncertainty) {
69  r._centroid = afw::table::PointKey<CentroidElement>::addFields(schema, name, doc, "pixel");
70  if (uncertainty != NO_UNCERTAINTY) {
73  sigma[0] = schema.addField<ErrElement>(schema.join(name, "xErr"), "1-sigma uncertainty on x position",
74  "pixel");
75  sigma[1] = schema.addField<ErrElement>(schema.join(name, "yErr"), "1-sigma uncertainty on y position",
76  "pixel");
77  if (uncertainty == FULL_COVARIANCE) {
78  cov.push_back(schema.addField<ErrElement>(schema.join(name, "x_y_Cov"),
79  "uncertainty covariance in x and y", "pixel^2"));
80  }
82  }
83  return r;
84 }
85 
86 namespace {
87 
88 std::vector<std::string> getNameVector() {
90  v.push_back("x");
91  v.push_back("y");
92  return v;
93 }
94 
95 } // namespace
96 
98  static std::vector<std::string> names = getNameVector(); // C++11 TODO: just use initializer list
99  try {
100  _centroidErr = afw::table::CovarianceMatrixKey<ErrElement, 2>(s, names);
101  } catch (pex::exceptions::NotFoundError &) {
102  }
103 }
104 
106  CentroidResult r;
107  r.setCentroid(record.get(_centroid));
108  if (_centroidErr.isValid()) {
109  r.setCentroidErr(record.get(_centroidErr));
110  }
111  return r;
112 }
113 
115  record.set(_centroid, value.getCentroid());
116  if (_centroidErr.isValid()) {
117  record.set(_centroidErr, value.getCentroidErr());
118  }
119 }
120 
122  : BaseTransform{name} {
123  // Map the flag through to the output
124  mapper.addMapping(mapper.getInputSchema().find<afw::table::Flag>(name + "_flag").key);
125 
126  // Add keys for the coordinates
127  auto &s = mapper.editOutputSchema();
128  _coordKey = afw::table::CoordKey::addFields(s, name, "ICRS coordinates");
129 
130  // If the centroid has an error key we also include one on the celestial
131  // coordinates; otherwise, it isn't necessary. Note that if we provide for
132  // errors in celestial coordinates, we always need the full covariance.
133  if (CentroidResultKey(mapper.getInputSchema()[name]).getCentroidErr().isValid()) {
136  sigma[0] = s.addField<ErrElement>(s.join(name, "raErr"), "1-sigma uncertainty on RA", "rad");
137  sigma[1] = s.addField<ErrElement>(s.join(name, "decErr"), "1-sigma uncertainty on dec", "rad");
138  cov[0] = s.addField<ErrElement>(s.join(name, "ra_dec_Cov"), "Uncertainty covariance in RA and dec",
139  "rad^2");
141  }
142 }
143 
145  afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs,
146  afw::image::PhotoCalib const &photoCalib) const {
147  checkCatalogSize(inputCatalog, outputCatalog);
148  CentroidResultKey centroidResultKey(inputCatalog.getSchema()[_name]);
149 
150  afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
151  afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
152 
153  for (; inSrc != inputCatalog.end() && outSrc != outputCatalog.end(); ++inSrc, ++outSrc) {
154  CentroidResult centroidResult = centroidResultKey.get(*inSrc);
155 
156  _coordKey.set(*outSrc, wcs.pixelToSky(centroidResult.getCentroid()));
157 
158  if (centroidResultKey.getCentroidErr().isValid()) {
159  CentroidCov centroidCov = centroidResult.getCentroidErr();
160  if (!(std::isnan(centroidCov(0, 0)) || std::isnan(centroidCov(1, 1)))) {
161  auto transform = wcs.linearizePixelToSky(centroidResult.getCentroid(), geom::radians)
162  .getLinear()
163  .getMatrix();
164  _coordErrKey.set(*outSrc, (transform * centroidResult.getCentroidErr().cast<double>() *
165  transform.transpose())
166  .cast<ErrElement>());
167  }
168  }
169  }
170 }
171 
172 // Add a key "flag_resetToPeak" if something is wrong with the centroid
173 // Save a key to this algorithm's Centroid, as well as the general failure flag
175  double maxDistFromPeak)
176  : _doFootprintCheck(doFootprintCheck), _maxDistFromPeak(maxDistFromPeak) {
177  _resetKey = schema.addField<afw::table::Flag>(schema.join(name, "flag_resetToPeak"),
178  "set if CentroidChecker reset the centroid");
179  _failureKey = schema.find<afw::table::Flag>(schema.join(name, "flag")).key;
180  _xKey = schema.find<CentroidElement>(schema.join(name, "x")).key;
181  _yKey = schema.find<CentroidElement>(schema.join(name, "y")).key;
182 
183  // We only check errors on the centroid if they exist: not all measurement
184  // algorithms provide them.
185  try {
186  _xErrKey = schema.find<ErrElement>(schema.join(name, "xErr")).key;
187  } catch (pex::exceptions::NotFoundError &err) {}
188  try {
189  _yErrKey = schema.find<ErrElement>(schema.join(name, "yErr")).key;
190  } catch (pex::exceptions::NotFoundError &err) {}
191  if (_xErrKey.isValid() || _yErrKey.isValid()) {
192  _badErrorKey = schema.addField<afw::table::Flag>(schema.join(name, "flag_badError"),
193  "Error on x and/or y position is NaN");
194  }
195 }
196 
198  CentroidElement x = record.get(_xKey);
199  CentroidElement y = record.get(_yKey);
200 
201  // Check any errors specified on the centroid position are valid.
202  if ((_xErrKey.isValid() && std::isnan(record.get(_xErrKey))) ||
203  (_yErrKey.isValid() && std::isnan(record.get(_yErrKey)))) {
204  record.set(_badErrorKey, true);
205  record.set(_failureKey, true);
206  }
207 
208  // Only proceed with checking if appropriately configured.
209  if (!_doFootprintCheck && _maxDistFromPeak < 0.0) {
210  return false;
211  }
212 
213  // Check that the centroid has a footprint that we can validate; otherwise, give up.
214  PTR(afw::detection::Footprint) footprint = record.getFootprint();
215  if (!footprint) {
216  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "No Footprint attached to record");
217  }
218  if (footprint->getPeaks().empty()) {
219  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "Footprint has no peaks; cannot verify centroid.");
220  }
221 
222  // Set the centroid to the first footprint if the centroid is either more than
223  // _maxDistFromPeak pixels from the centroid, or if it is outside the footprint.
224  CentroidElement footX = footprint->getPeaks().front().getFx();
225  CentroidElement footY = footprint->getPeaks().front().getFy();
226  double distsq = (x - footX) * (x - footX) + (y - footY) * (y - footY);
227  if ((_doFootprintCheck && !footprint->contains(geom::Point2I(geom::Point2D(x, y)))) ||
228  ((_maxDistFromPeak > 0) && (distsq > _maxDistFromPeak * _maxDistFromPeak))) {
229  record.set(_xKey, footX);
230  record.set(_yKey, footY);
231  record.set(_failureKey, true);
232  record.set(_resetKey, true);
233  return true;
234  }
235  return false;
236 }
237 } // namespace base
238 } // namespace meas
239 } // namespace lsst
void set(BaseRecord &record, Eigen::Matrix< T, N, N > const &value) const override
Set a covariance matrix in the given record (uses only the lower triangle of the given matrix) ...
Definition: aggregates.cc:278
Defines the fields and offsets for a table.
Definition: Schema.h:50
ErrElement yErr
standard deviation of y
Centroid const getCentroid() const
Return a Point object containing the measured x and y.
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Definition: SkyWcs.h:117
A proxy type for name lookups in a Schema.
Definition: Schema.h:357
virtual void set(afw::table::BaseRecord &record, CentroidResult const &value) const
Set a CentroidResult in the given record.
The photometric calibration of an exposure.
Definition: PhotoCalib.h:114
UncertaintyEnum
An enum used to specify how much uncertainty information measurement algorithms provide.
Definition: constants.h:43
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
Definition: SkyWcs.h:334
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
Definition: Schema.cc:641
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
A coordinate class intended to represent absolute positions.
A reusable struct for centroid measurements.
bool isValid() const
Return True if the centroid key is valid.
The full covariance matrix is provided.
Definition: constants.h:46
int y
Definition: SpanSet.cc:49
std::shared_ptr< Footprint > getFootprint() const
Definition: Source.h:100
static PointKey addFields(Schema &schema, std::string const &name, std::string const &doc, std::string const &unit)
Add a pair of _x, _y fields to a Schema, and return a PointKey that points to them.
Definition: aggregates.cc:36
ErrElement xErr
standard deviation of x
STL namespace.
CentroidElement x
x (column) coordinate of the measured position
SchemaMapper * mapper
Definition: SchemaMapper.cc:78
void setCentroid(Centroid const &centroid)
Set the struct fields from the given Point object.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
CentroidChecker(afw::table::Schema &schema, std::string const &name, bool inside=true, double maxDistFromPeak=-1.0)
Check source record produced by a centroid algorithm called "name".
AngleUnit constexpr radians
constant with units of radians
Definition: Angle.h:108
bool isValid() const noexcept
Return true if the key was initialized to valid offset.
Definition: Key.h:97
table::Key< table::Array< std::uint8_t > > wcs
Definition: SkyWcs.cc:71
float ErrElement
Definition: constants.h:55
afw::table::Key< double > sigma
Definition: GaussianPsf.cc:50
Matrix const getMatrix() const noexcept
Return the transform as a full 3x3 matrix.
STL class.
CentroidResult()
Constructor; initializes everything to NaN.
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
Eigen::Matrix< ErrElement, 2, 2, Eigen::DontAlign > CentroidCov
Definition: constants.h:59
T push_back(T... args)
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Definition: Schema.cc:656
A base class for image defects.
UnitVector3d centroid(VertexIterator const begin, VertexIterator const end)
iterator end()
Iterator access.
Definition: Catalog.h:397
ErrElement x_y_Cov
x,y term in the uncertainty convariance matrix
table::Schema schema
Definition: Amplifier.cc:115
Iterator class for CatalogT.
Definition: Catalog.h:38
Key< U > key
Definition: Schema.cc:281
lsst::geom::AffineTransform linearizePixelToSky(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Return the local linear approximation to pixelToSky at a point given in sky coordinates.
Definition: SkyWcs.cc:260
static CentroidResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty)
Add the appropriate fields to a Schema, and return a CentroidResultKey that manages them...
geom::Point< CentroidElement, 2 > Centroid
Definition: constants.h:58
virtual void operator()(afw::table::SourceCatalog const &inputCatalog, afw::table::BaseCatalog &outputCatalog, afw::geom::SkyWcs const &wcs, afw::image::PhotoCalib const &photoCalib) const
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:62
double x
bool operator()(afw::table::SourceRecord &record) const
Set the centroid to the first footprint if the centroid is either more than _dist pixels from the foo...
CentroidTransform(std::string const &name, afw::table::SchemaMapper &mapper)
Definition: __init__.py:1
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
Base class for all records.
Definition: BaseRecord.h:31
Algorithm provides no uncertainy information at all.
Definition: constants.h:44
Abstract base class for all C++ measurement transformations.
Definition: Transform.h:86
static CoordKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _ra, _dec fields to a Schema, and return a CoordKey that points to them.
Definition: aggregates.cc:83
A FunctorKey for CentroidResult.
T isnan(T... args)
void set(Key< T > const &key, U const &value)
Set value of a field for the given key.
Definition: BaseRecord.h:164
CentroidElement y
y (row) coordinate of the measured position
int m
Definition: SpanSet.cc:49
CentroidResultKey()
Default constructor; instance will not be usuable unless subsequently assigned to.
void checkCatalogSize(afw::table::BaseCatalog const &cat1, afw::table::BaseCatalog const &cat2) const
Ensure that catalogs have the same size.
Definition: Transform.h:102
Record class that contains measurements made on a single exposure.
Definition: Source.h:80
double CentroidElement
Definition: constants.h:56
virtual CentroidResult get(afw::table::BaseRecord const &record) const
Get a CentroidResult from the given record.
T sqrt(T... args)
void set(BaseRecord &record, lsst::geom::SpherePoint const &value) const override
Set an lsst::geom::SpherePoint in the given record.
Definition: aggregates.cc:93
CentroidCov const getCentroidErr() const
Return the 2x2 symmetric covariance matrix, with rows and columns ordered (x, y)
iterator begin()
Iterator access.
Definition: Catalog.h:396
bool isValid() const noexcept
Return True if all the constituent error Keys are valid.
Definition: aggregates.cc:294
#define PTR(...)
Definition: base.h:41
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Definition: Schema.cc:668
void setCentroidErr(CentroidCov const &matrix)
Set the struct uncertainty fields from the given matrix, with rows and columns ordered (x...
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104