22 r"""Base classes for single-frame measurement plugins and the associated task. 24 In single-frame measurement, we assume that detection and probably deblending 25 have already been run on the same frame, so a `~lsst.afw.table.SourceCatalog` 26 has already been created with `lsst.afw.detection.Footprint`\ s (which may be 27 "heavy" — that is, include pixel data). Measurements are generally recorded in 28 the coordinate system of the image being measured (and all slot-eligible 29 fields must be), but non-slot fields may be recorded in other coordinate 30 systems if necessary to avoid information loss (this should, of course, be 31 indicated in the field documentation). 36 from .pluginRegistry
import PluginRegistry
37 from .baseMeasurement
import (BaseMeasurementPluginConfig, BaseMeasurementPlugin,
38 BaseMeasurementConfig, BaseMeasurementTask)
39 from .noiseReplacer
import NoiseReplacer, DummyNoiseReplacer
41 __all__ = (
"SingleFramePluginConfig",
"SingleFramePlugin",
42 "SingleFrameMeasurementConfig",
"SingleFrameMeasurementTask")
46 """Base class for single-frame plugin configuration classes. 52 """Base class for single-frame measurement plugin. 56 config : `SingleFramePlugin.ConfigClass` 57 Configuration for this plugin. 59 The string with which the plugin was registered. 60 schema : `lsst.afw.table.Schema` 61 The schema for the source table . New fields are added here to 62 hold measurements produced by this plugin. 63 metadata : `lsst.daf.base.PropertySet` 64 Plugin metadata that will be attached to the output catalog 65 logName : `str`, optional 66 Name to use when logging errors. 70 New plugins can be created in Python by inheriting directly from this 71 class and implementing the `measure`, `fail` (from `BasePlugin`), and 72 optionally `__init__` and `measureN` methods. Plugins can also be defined 73 in C++ via the `WrappedSingleFramePlugin` class. 77 """Registry of subclasses of `SingleFramePlugin` (`PluginRegistry`). 80 ConfigClass = SingleFramePluginConfig
82 def __init__(self, config, name, schema, metadata, logName=None, **kwds):
83 BaseMeasurementPlugin.__init__(self, config, name, logName=logName)
86 """Measure the properties of a source on a single image. 88 The image may be from a single epoch, or it may be a coadd. 92 measRecord : `lsst.afw.table.SourceRecord` 93 Record describing the object being measured. Previously-measured 94 quantities may be retrieved from here, and it will be updated 95 in-place tih the outputs of this plugin. 96 exposure : `lsst.afw.image.ExposureF` 97 The pixel data to be measured, together with the associated PSF, 98 WCS, etc. All other sources in the image should have been replaced 99 by noise according to deblender outputs. 101 raise NotImplementedError()
104 """Measure the properties of blended sources on a single image. 106 This operates on all members of a blend family at once. The image may 107 be from a single epoch, or it may be a coadd. 111 measCat : `lsst.afw.table.SourceCatalog` 112 Catalog describing the objects (and only those objects) being 113 measured. Previously-measured quantities will be retrieved from 114 here, and it will be updated in-place with the outputs of this 116 exposure : `lsst.afw.image.ExposureF` 117 The pixel data to be measured, together with the associated PSF, 118 WCS, etc. All other sources in the image should have been replaced 119 by noise according to deblender outputs. 123 Derived classes that do not implement ``measureN`` should just inherit 124 this disabled version. Derived classes that do implement ``measureN`` 125 should additionally add a bool doMeasureN config field to their config 126 class to signal that measureN-mode is available. 128 raise NotImplementedError()
132 """Config class for single frame measurement driver task. 135 plugins = SingleFramePlugin.registry.makeField(
137 default=[
"base_PixelFlags",
139 "base_NaiveCentroid",
143 "base_CircularApertureFlux",
147 "base_LocalBackground",
149 doc=
"Plugins to be run and their configuration" 151 algorithms = property(
lambda self: self.
plugins, doc=
"backwards-compatibility alias for plugins")
152 undeblended = SingleFramePlugin.registry.makeField(
155 doc=
"Plugins to run on undeblended image" 160 """A subtask for measuring the properties of sources on a single exposure. 164 schema : `lsst.afw.table.Schema` 165 Schema of the output resultant catalog. Will be updated to provide 166 fields to accept the outputs of plugins which will be executed by this 168 algMetadata : `lsst.daf.base.PropertyList`, optional 169 Used to record metadaa about algorithm execution. An empty 170 `lsst.daf.base.PropertyList` will be created if `None`. 172 Keyword arguments forwarded to `BaseMeasurementTask`. 175 ConfigClass = SingleFrameMeasurementConfig
177 NOISE_SEED_MULTIPLIER =
"NOISE_SEED_MULTIPLIER" 178 """Name by which the noise seed multiplier is recorded in metadata ('str'). 181 NOISE_SOURCE =
"NOISE_SOURCE" 182 """Name by which the noise source is recorded in metadata ('str'). 185 NOISE_OFFSET =
"NOISE_OFFSET" 186 """Name by which the noise offset is recorded in metadata ('str'). 189 NOISE_EXPOSURE_ID =
"NOISE_EXPOSURE_ID" 190 """Name by which the noise exposire ID is recorded in metadata ('str'). 193 def __init__(self, schema, algMetadata=None, **kwds):
194 super(SingleFrameMeasurementTask, self).
__init__(algMetadata=algMetadata, **kwds)
200 if 'base_Blendedness' in self.
plugins:
207 def run(self, measCat, exposure, noiseImage=None, exposureId=None, beginOrder=None, endOrder=None):
208 r"""Run single frame measurement over an exposure and source catalog. 212 measCat : `lsst.afw.table.SourceCatalog` 213 Catalog to be filled with the results of measurement. Must contain 214 all the `lsst.afw.table.SourceRecord`\ s to be measured (with 215 `lsst.afw.detection.Footprint`\ s attached), and have a schema 216 that is a superset of ``self.schema``. 217 exposure : `lsst.afw.image.ExposureF` 218 Image containing the pixel data to be measured together with 219 associated PSF, WCS, etc. 220 noiseImage : `lsst.afw.image.ImageF`, optional 221 Can be used to specify the a predictable noise replacement field 222 for testing purposes. 223 exposureId : `int`, optional 224 Unique exposure identifier used to calculate the random number 225 generator seed during noise replacement. 226 beginOrder : `float`, optional 227 Start execution order (inclusive): measurements with 228 ``executionOrder < beginOrder`` are not executed. `None` for no 230 endOrder : `float`, optional 231 Final execution order (exclusive): measurements with 232 ``executionOrder >= endOrder`` are not executed. `None` for no 236 footprints = {measRecord.getId(): (measRecord.getParent(), measRecord.getFootprint())
237 for measRecord
in measCat}
245 if self.
config.doReplaceWithNoise:
247 noiseImage=noiseImage, log=self.
log, exposureId=exposureId)
248 algMetadata = measCat.getMetadata()
249 if algMetadata
is not None:
253 if exposureId
is not None:
258 self.
runPlugins(noiseReplacer, measCat, exposure, beginOrder, endOrder)
260 def runPlugins(self, noiseReplacer, measCat, exposure, beginOrder=None, endOrder=None):
261 r"""Call the configured measument plugins on an image. 265 noiseReplacer : `NoiseReplacer` 266 Used to fill sources not being measured with noise. 267 measCat : `lsst.afw.table.SourceCatalog` 268 Catalog to be filled with the results of measurement. Must contain 269 all the `lsst.afw.table.SourceRecord`\ s to be measured (with 270 `lsst.afw.detection.Footprint`\ s attached), and have a schema 271 that is a superset of ``self.schema``. 272 exposure : `lsst.afw.image.ExposureF` 273 Image containing the pixel data to be measured together with 274 associated PSF, WCS, etc. 275 beginOrder : `float`, optional 276 Start execution order (inclusive): measurements with 277 ``executionOrder < beginOrder`` are not executed. `None` for no 279 endOrder : `float`, optional 280 Final execution order (exclusive): measurements with 281 ``executionOrder >= endOrder`` are not executed. `None` for no 286 measParentCat = measCat.getChildren(0)
288 nMeasCat = len(measCat)
289 nMeasParentCat = len(measParentCat)
290 self.
log.
info(
"Measuring %d source%s (%d parent%s, %d child%s) ",
291 nMeasCat, (
"" if nMeasCat == 1
else "s"),
292 nMeasParentCat, (
"" if nMeasParentCat == 1
else "s"),
293 nMeasCat - nMeasParentCat, (
"" if nMeasCat - nMeasParentCat == 1
else "ren"))
295 for parentIdx, measParentRecord
in enumerate(measParentCat):
298 measChildCat = measCat.getChildren(measParentRecord.getId())
301 for measChildRecord
in measChildCat:
302 noiseReplacer.insertSource(measChildRecord.getId())
303 self.
callMeasure(measChildRecord, exposure, beginOrder=beginOrder, endOrder=endOrder)
306 self.
blendPlugin.cpp.measureChildPixels(exposure.getMaskedImage(), measChildRecord)
308 noiseReplacer.removeSource(measChildRecord.getId())
311 noiseReplacer.insertSource(measParentRecord.getId())
312 self.
callMeasure(measParentRecord, exposure, beginOrder=beginOrder, endOrder=endOrder)
315 self.
blendPlugin.cpp.measureChildPixels(exposure.getMaskedImage(), measParentRecord)
318 self.
callMeasureN(measParentCat[parentIdx:parentIdx+1], exposure,
319 beginOrder=beginOrder, endOrder=endOrder)
320 self.
callMeasureN(measChildCat, exposure, beginOrder=beginOrder, endOrder=endOrder)
321 noiseReplacer.removeSource(measParentRecord.getId())
328 for source
in measCat:
334 for source
in measCat:
335 self.
blendPlugin.cpp.measureParentPixels(exposure.getMaskedImage(), source)
338 """Backwards-compatibility alias for `run`. 340 self.
run(measCat, exposure)
def callMeasure(self, measRecord, args, kwds)
def measure(self, measRecord, exposure)
def measureN(self, measCat, exposure)
def measure(self, measCat, exposure)
def runPlugins(self, noiseReplacer, measCat, exposure, beginOrder=None, endOrder=None)
string NOISE_SEED_MULTIPLIER
def callMeasureN(self, measCat, args, kwds)
def __init__(self, config, name, schema, metadata, logName=None, kwds)
def run(self, measCat, exposure, noiseImage=None, exposureId=None, beginOrder=None, endOrder=None)
def __init__(self, schema, algMetadata=None, kwds)
def initializePlugins(self, kwds)
def doMeasurement(self, plugin, measRecord, args, kwds)