22 """Definition of measurement plugins. 24 This module defines and registers a series of pure-Python measurement plugins 25 which have trivial implementations. It also wraps measurement algorithms 26 defined in C++ to expose them to the measurement framework. 36 from .pluginRegistry
import register
37 from .pluginsBase
import BasePlugin
38 from .baseMeasurement
import BaseMeasurementPluginConfig
39 from .sfm
import SingleFramePluginConfig, SingleFramePlugin
40 from .forcedMeasurement
import ForcedPluginConfig, ForcedPlugin
41 from .wrappers
import wrapSimpleAlgorithm, wrapTransform, GenericPlugin
42 from .transforms
import SimpleCentroidTransform
44 from .apertureFlux
import ApertureFluxControl, ApertureFluxTransform
45 from .transform
import BaseTransform
46 from .blendedness
import BlendednessAlgorithm, BlendednessControl
47 from .circularApertureFlux
import CircularApertureFluxAlgorithm
48 from .gaussianFlux
import GaussianFluxAlgorithm, GaussianFluxControl, GaussianFluxTransform
49 from .exceptions
import MeasurementError
50 from .localBackground
import LocalBackgroundControl, LocalBackgroundAlgorithm, LocalBackgroundTransform
51 from .naiveCentroid
import NaiveCentroidAlgorithm, NaiveCentroidControl, NaiveCentroidTransform
52 from .peakLikelihoodFlux
import PeakLikelihoodFluxAlgorithm, PeakLikelihoodFluxControl, \
53 PeakLikelihoodFluxTransform
54 from .pixelFlags
import PixelFlagsAlgorithm, PixelFlagsControl
55 from .psfFlux
import PsfFluxAlgorithm, PsfFluxControl, PsfFluxTransform
56 from .scaledApertureFlux
import ScaledApertureFluxAlgorithm, ScaledApertureFluxControl, \
57 ScaledApertureFluxTransform
58 from .sdssCentroid
import SdssCentroidAlgorithm, SdssCentroidControl, SdssCentroidTransform
59 from .sdssShape
import SdssShapeAlgorithm, SdssShapeControl, SdssShapeTransform
62 "SingleFrameFPPositionConfig",
"SingleFrameFPPositionPlugin",
63 "SingleFrameJacobianConfig",
"SingleFrameJacobianPlugin",
64 "VarianceConfig",
"SingleFrameVariancePlugin",
"ForcedVariancePlugin",
65 "InputCountConfig",
"SingleFrameInputCountPlugin",
"ForcedInputCountPlugin",
66 "SingleFramePeakCentroidConfig",
"SingleFramePeakCentroidPlugin",
67 "SingleFrameSkyCoordConfig",
"SingleFrameSkyCoordPlugin",
68 "ForcedPeakCentroidConfig",
"ForcedPeakCentroidPlugin",
69 "ForcedTransformedCentroidConfig",
"ForcedTransformedCentroidPlugin",
70 "ForcedTransformedShapeConfig",
"ForcedTransformedShapePlugin",
75 TransformClass=PsfFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
76 shouldApCorr=
True, hasLogName=
True)
78 TransformClass=PeakLikelihoodFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
80 TransformClass=GaussianFluxTransform, executionOrder=BasePlugin.FLUX_ORDER,
83 TransformClass=NaiveCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
85 TransformClass=SdssCentroidTransform, executionOrder=BasePlugin.CENTROID_ORDER)
87 executionOrder=BasePlugin.FLUX_ORDER)
89 TransformClass=SdssShapeTransform, executionOrder=BasePlugin.SHAPE_ORDER)
91 TransformClass=ScaledApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
94 TransformClass=ApertureFluxTransform, executionOrder=BasePlugin.FLUX_ORDER)
96 TransformClass=BaseTransform, executionOrder=BasePlugin.SHAPE_ORDER)
99 TransformClass=LocalBackgroundTransform, executionOrder=BasePlugin.FLUX_ORDER)
113 """Configuration for the focal plane position measurment algorithm. 121 """Algorithm to calculate the position of a centroid on the focal plane. 125 config : `SingleFrameFPPositionConfig` 129 schema : `lsst.afw.table.Schema` 130 The schema for the measurement output catalog. New fields will be 131 added to hold measurements produced by this plugin. 132 metadata : `lsst.daf.base.PropertySet` 133 Plugin metadata that will be attached to the output catalog 136 ConfigClass = SingleFrameFPPositionConfig
142 def __init__(self, config, name, schema, metadata):
143 SingleFramePlugin.__init__(self, config, name, schema, metadata)
144 self.
focalValue = lsst.afw.table.Point2DKey.addFields(schema, name,
"Position on the focal plane",
146 self.
focalFlag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Set to True for any fatal failure")
147 self.
detectorFlag = schema.addField(name +
"_missingDetector_flag", type=
"Flag",
148 doc=
"Set to True if detector object is missing")
151 det = exposure.getDetector()
156 center = measRecord.getCentroid()
157 fp = det.transform(center, lsst.afw.cameraGeom.PIXELS, lsst.afw.cameraGeom.FOCAL_PLANE)
160 def fail(self, measRecord, error=None):
165 """Configuration for the Jacobian calculation plugin. 173 """Compute the Jacobian and its ratio with a nominal pixel area. 175 This enables one to compare relative, rather than absolute, pixel areas. 179 config : `SingleFrameJacobianConfig` 183 schema : `lsst.afw.table.Schema` 184 The schema for the measurement output catalog. New fields will be 185 added to hold measurements produced by this plugin. 186 metadata : `lsst.daf.base.PropertySet` 187 Plugin metadata that will be attached to the output catalog 190 ConfigClass = SingleFrameJacobianConfig
196 def __init__(self, config, name, schema, metadata):
197 SingleFramePlugin.__init__(self, config, name, schema, metadata)
198 self.
jacValue = schema.addField(name +
'_value', type=
"D", doc=
"Jacobian correction")
199 self.
jacFlag = schema.addField(name +
'_flag', type=
"Flag", doc=
"Set to 1 for any fatal failure")
204 center = measRecord.getCentroid()
207 result = np.abs(self.
scale*exposure.getWcs().linearizePixelToSky(
209 lsst.geom.arcseconds).getLinear().computeDeterminant())
210 measRecord.set(self.
jacValue, result)
212 def fail(self, measRecord, error=None):
213 measRecord.set(self.
jacFlag,
True)
217 """Configuration for the variance calculation plugin. 220 doc=
"Scale factor to apply to shape for aperture")
222 default=[
"DETECTED",
"DETECTED_NEGATIVE",
"BAD",
"SAT"])
226 """Compute the median variance corresponding to a footprint. 228 The aim here is to measure the background variance, rather than that of 229 the object itself. In order to achieve this, the variance is calculated 230 over an area scaled up from the shape of the input footprint. 234 config : `VarianceConfig` 238 schema : `lsst.afw.table.Schema` 239 The schema for the measurement output catalog. New fields will be 240 added to hold measurements produced by this plugin. 241 metadata : `lsst.daf.base.PropertySet` 242 Plugin metadata that will be attached to the output catalog 245 ConfigClass = VarianceConfig
247 FAILURE_BAD_CENTROID = 1
248 """Denotes failures due to bad centroiding (`int`). 251 FAILURE_EMPTY_FOOTPRINT = 2
252 """Denotes failures due to a lack of usable pixels (`int`). 257 return BasePlugin.FLUX_ORDER
259 def __init__(self, config, name, schema, metadata):
260 GenericPlugin.__init__(self, config, name, schema, metadata)
261 self.
varValue = schema.addField(name +
'_value', type=
"D", doc=
"Variance at object position")
263 doc=
"Set to True when the footprint has no usable pixels")
268 schema.getAliasMap().
set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
270 def measure(self, measRecord, exposure, center):
274 if not np.all(np.isfinite(measRecord.getCentroid())):
277 aperture.scale(self.
config.scale)
280 foot.clipTo(exposure.getBBox(lsst.afw.image.PARENT))
283 maskedImage = exposure.getMaskedImage()
285 maskBits = maskedImage.getMask().getPlaneBitMask(self.
config.mask)
286 logicalMask = np.logical_not(pixels.getMaskArray() & maskBits)
291 if np.any(logicalMask):
292 medVar = np.median(pixels.getVarianceArray()[logicalMask])
293 measRecord.set(self.
varValue, medVar)
295 raise MeasurementError(
"Footprint empty, or all pixels are masked, can't compute median",
298 def fail(self, measRecord, error=None):
301 if isinstance(error, MeasurementError):
306 measRecord.set(self.
varValue, np.nan)
307 GenericPlugin.fail(self, measRecord, error)
310 SingleFrameVariancePlugin = VariancePlugin.makeSingleFramePlugin(
"base_Variance")
311 """Single-frame version of `VariancePlugin`. 314 ForcedVariancePlugin = VariancePlugin.makeForcedPlugin(
"base_Variance")
315 """Forced version of `VariancePlugin`. 320 """Configuration for the input image counting plugin. 325 class InputCountPlugin(GenericPlugin):
326 """Count the number of input images which contributed to a a source. 330 config : `InputCountConfig` 334 schema : `lsst.afw.table.Schema` 335 The schema for the measurement output catalog. New fields will be 336 added to hold measurements produced by this plugin. 337 metadata : `lsst.daf.base.PropertySet` 338 Plugin metadata that will be attached to the output catalog 342 Information is derived from the image's `~lsst.afw.image.CoaddInputs`. 343 Note these limitation: 345 - This records the number of images which contributed to the pixel in the 346 center of the source footprint, rather than to any or all pixels in the 348 - Clipping in the coadd is not taken into account. 351 ConfigClass = InputCountConfig
353 FAILURE_BAD_CENTROID = 1
354 """Denotes failures due to bad centroiding (`int`). 357 FAILURE_NO_INPUTS = 2
358 """Denotes failures due to the image not having coadd inputs. (`int`) 363 return BasePlugin.SHAPE_ORDER
365 def __init__(self, config, name, schema, metadata):
366 GenericPlugin.__init__(self, config, name, schema, metadata)
367 self.
numberKey = schema.addField(name +
'_value', type=
"I",
368 doc=
"Number of images contributing at center, not including any" 370 self.
noInputsFlag = schema.addField(name +
'_flag_noInputs', type=
"Flag",
371 doc=
"No coadd inputs available")
374 schema.getAliasMap().
set(name +
'_flag_badCentroid', schema.getAliasMap().apply(
"slot_Centroid_flag"))
376 def measure(self, measRecord, exposure, center):
377 if not exposure.getInfo().getCoaddInputs():
379 if not np.all(np.isfinite(center)):
382 ccds = exposure.getInfo().getCoaddInputs().ccds
383 measRecord.set(self.
numberKey, len(ccds.subsetContaining(center, exposure.getWcs())))
385 def fail(self, measRecord, error=None):
386 if error
is not None:
391 GenericPlugin.fail(self, measRecord, error)
394 SingleFrameInputCountPlugin = InputCountPlugin.makeSingleFramePlugin(
"base_InputCount")
395 """Single-frame version of `InputCoutPlugin`. 398 ForcedInputCountPlugin = InputCountPlugin.makeForcedPlugin(
"base_InputCount")
399 """Forced version of `InputCoutPlugin`. 404 """Configuration for the single frame peak centroiding algorithm. 411 """Record the highest peak in a source footprint as its centroid. 413 This is of course a relatively poor measure of the true centroid of the 414 object; this algorithm is provided mostly for testing and debugging. 418 config : `SingleFramePeakCentroidConfig` 422 schema : `lsst.afw.table.Schema` 423 The schema for the measurement output catalog. New fields will be 424 added to hold measurements produced by this plugin. 425 metadata : `lsst.daf.base.PropertySet` 426 Plugin metadata that will be attached to the output catalog 429 ConfigClass = SingleFramePeakCentroidConfig
435 def __init__(self, config, name, schema, metadata):
436 SingleFramePlugin.__init__(self, config, name, schema, metadata)
437 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
438 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
439 self.
flag = schema.addField(name +
"_flag", type=
"Flag", doc=
"Centroiding failed")
442 peak = measRecord.getFootprint().getPeaks()[0]
443 measRecord.set(self.
keyX, peak.getFx())
444 measRecord.set(self.
keyY, peak.getFy())
446 def fail(self, measRecord, error=None):
447 measRecord.set(self.
flag,
True)
451 return SimpleCentroidTransform
455 """Configuration for the sky coordinates algorithm. 462 """Record the sky position of an object based on its centroid slot and WCS. 464 The position is record in the ``coord`` field, which is part of the 465 `~lsst.afw.table.SourceCatalog` minimal schema. 469 config : `SingleFrameSkyCoordConfig` 473 schema : `lsst.afw.table.Schema` 474 The schema for the measurement output catalog. New fields will be 475 added to hold measurements produced by this plugin. 476 metadata : `lsst.daf.base.PropertySet` 477 Plugin metadata that will be attached to the output catalog 480 ConfigClass = SingleFrameSkyCoordConfig
490 if not exposure.hasWcs():
491 raise Exception(
"Wcs not attached to exposure. Required for " + self.
name +
" algorithm")
492 measRecord.updateCoord(exposure.getWcs())
494 def fail(self, measRecord, error=None):
502 class ForcedPeakCentroidConfig(ForcedPluginConfig):
503 """Configuration for the forced peak centroid algorithm. 510 """Record the highest peak in a source footprint as its centroid. 512 This is of course a relatively poor measure of the true centroid of the 513 object; this algorithm is provided mostly for testing and debugging. 515 This is similar to `SingleFramePeakCentroidPlugin`, except that transforms 516 the peak coordinate from the original (reference) coordinate system to the 517 coordinate system of the exposure being measured. 521 config : `ForcedPeakCentroidConfig` 525 schemaMapper : `lsst.afw.table.SchemaMapper` 526 A mapping from reference catalog fields to output 527 catalog fields. Output fields are added to the output schema. 528 metadata : `lsst.daf.base.PropertySet` 529 Plugin metadata that will be attached to the output catalog. 532 ConfigClass = ForcedPeakCentroidConfig
538 def __init__(self, config, name, schemaMapper, metadata):
539 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
540 schema = schemaMapper.editOutputSchema()
541 self.
keyX = schema.addField(name +
"_x", type=
"D", doc=
"peak centroid", units=
"pixel")
542 self.
keyY = schema.addField(name +
"_y", type=
"D", doc=
"peak centroid", units=
"pixel")
544 def measure(self, measRecord, exposure, refRecord, refWcs):
545 targetWcs = exposure.getWcs()
546 peak = refRecord.getFootprint().getPeaks()[0]
548 result = targetWcs.skyToPixel(refWcs.pixelToSky(result))
549 measRecord.set(self.
keyX, result.getX())
550 measRecord.set(self.
keyY, result.getY())
554 return SimpleCentroidTransform
558 """Configuration for the forced transformed centroid algorithm. 563 @
register(
"base_TransformedCentroid")
565 """Record the transformation of the reference catalog centroid. 567 The centroid recorded in the reference catalog is tranformed to the 568 measurement coordinate system and stored. 572 config : `ForcedTransformedCentroidConfig` 576 schemaMapper : `lsst.afw.table.SchemaMapper` 577 A mapping from reference catalog fields to output 578 catalog fields. Output fields are added to the output schema. 579 metadata : `lsst.daf.base.PropertySet` 580 Plugin metadata that will be attached to the output catalog. 584 This is used as the slot centroid by default in forced measurement, 585 allowing subsequent measurements to simply refer to the slot value just as 586 they would in single-frame measurement. 589 ConfigClass = ForcedTransformedCentroidConfig
595 def __init__(self, config, name, schemaMapper, metadata):
596 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
597 schema = schemaMapper.editOutputSchema()
599 xKey = schema.addField(name +
"_x", type=
"D", doc=
"transformed reference centroid column",
601 yKey = schema.addField(name +
"_y", type=
"D", doc=
"transformed reference centroid row",
607 if "slot_Centroid_flag" in schemaMapper.getInputSchema():
608 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
609 doc=
"whether the reference centroid is marked as bad")
613 def measure(self, measRecord, exposure, refRecord, refWcs):
614 targetWcs = exposure.getWcs()
615 if not refWcs == targetWcs:
616 targetPos = targetWcs.skyToPixel(refWcs.pixelToSky(refRecord.getCentroid()))
619 measRecord.set(self.
centroidKey, refRecord.getCentroid())
621 measRecord.set(self.
flagKey, refRecord.getCentroidFlag())
625 """Configuration for the forced transformed shape algorithm. 632 """Record the transformation of the reference catalog shape. 634 The shape recorded in the reference catalog is tranformed to the 635 measurement coordinate system and stored. 639 config : `ForcedTransformedShapeConfig` 643 schemaMapper : `lsst.afw.table.SchemaMapper` 644 A mapping from reference catalog fields to output 645 catalog fields. Output fields are added to the output schema. 646 metadata : `lsst.daf.base.PropertySet` 647 Plugin metadata that will be attached to the output catalog. 651 This is used as the slot shape by default in forced measurement, allowing 652 subsequent measurements to simply refer to the slot value just as they 653 would in single-frame measurement. 656 ConfigClass = ForcedTransformedShapeConfig
662 def __init__(self, config, name, schemaMapper, metadata):
663 ForcedPlugin.__init__(self, config, name, schemaMapper, metadata)
664 schema = schemaMapper.editOutputSchema()
666 xxKey = schema.addField(name +
"_xx", type=
"D", doc=
"transformed reference shape x^2 moment",
668 yyKey = schema.addField(name +
"_yy", type=
"D", doc=
"transformed reference shape y^2 moment",
670 xyKey = schema.addField(name +
"_xy", type=
"D", doc=
"transformed reference shape xy moment",
676 if "slot_Shape_flag" in schemaMapper.getInputSchema():
677 self.
flagKey = schema.addField(name +
"_flag", type=
"Flag",
678 doc=
"whether the reference shape is marked as bad")
682 def measure(self, measRecord, exposure, refRecord, refWcs):
683 targetWcs = exposure.getWcs()
684 if not refWcs == targetWcs:
687 measRecord.set(self.
shapeKey, refRecord.getShape().
transform(localTransform.getLinear()))
689 measRecord.set(self.
shapeKey, refRecord.getShape())
691 measRecord.set(self.
flagKey, refRecord.getShapeFlag())
def measure(self, measRecord, exposure)
def getExecutionOrder(cls)
def getExecutionOrder(cls)
def fail(self, measRecord, error=None)
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
Approximate a Transform by its local linearization.
def __init__(self, config, name, schema, metadata)
def fail(self, measRecord, error=None)
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
def fail(self, measRecord, error=None)
daf::base::PropertySet * set
def __init__(self, config, name, schema, metadata)
def measure(self, measRecord, exposure)
def getExecutionOrder(cls)
int FAILURE_EMPTY_FOOTPRINT
def fail(self, measRecord, error=None)
def __init__(self, config, name, schemaMapper, metadata)
An ellipse defined by an arbitrary BaseCore and a center point.
def getExecutionOrder(cls)
def fail(self, measRecord, error=None)
def getExecutionOrder(cls)
def getExecutionOrder(cls)
def measure(self, measRecord, exposure)
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
def wrapTransform(transformClass, hasLogName=False)
def measure(self, measRecord, exposure, refRecord, refWcs)
def __init__(self, config, name, schema, metadata)
def measure(self, measRecord, exposure)
def measure(self, measRecord, exposure, center)
A FunctorKey used to get or set a geom::ellipses::Quadrupole from a tuple of constituent Keys...
def wrapSimpleAlgorithm(AlgClass, executionOrder, name=None, needsMetadata=False, hasMeasureN=False, hasLogName=False, kwds)
def __init__(self, config, name, schema, metadata)
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=NULL)
Create a HeavyFootprint with footprint defined by the given Footprint and pixel values from the given...