29 from .
import algorithmsLib
30 from .algorithmRegistry
import *
31 from .replaceWithNoise
import *
33 __all__ =
"SourceSlotConfig",
"SourceMeasurementConfig",
"SourceMeasurementTask"
37 centroid = pexConfig.Field(dtype=str, default=
"centroid.sdss", optional=
True,
38 doc=
"the name of the centroiding algorithm used to set source x,y")
39 shape = pexConfig.Field(dtype=str, default=
"shape.sdss", optional=
True,
40 doc=
"the name of the algorithm used to set source moments parameters")
41 apFlux = pexConfig.Field(dtype=str, default=
"flux.sinc", optional=
True,
42 doc=
"the name of the algorithm used to set the source aperture flux slot")
43 modelFlux = pexConfig.Field(dtype=str, default=
"flux.gaussian", optional=
True,
44 doc=
"the name of the algorithm used to set the source model flux slot")
45 psfFlux = pexConfig.Field(dtype=str, default=
"flux.psf", optional=
True,
46 doc=
"the name of the algorithm used to set the source psf flux slot")
47 instFlux = pexConfig.Field(dtype=str, default=
"flux.gaussian", optional=
True,
48 doc=
"the name of the algorithm used to set the source inst flux slot")
51 """Convenience method to setup a table's slots according to the config definition.
53 This is defined in the Config class to support use in unit tests without needing
54 to construct a Task object.
56 if prefix
is None: prefix =
""
58 if self.
shape is not None: table.defineShape(prefix + self.
shape)
59 if self.
apFlux is not None: table.defineApFlux(prefix + self.
apFlux)
61 if self.
psfFlux is not None: table.definePsfFlux(prefix + self.
psfFlux)
66 Configuration for SourceMeasurementTask.
67 A configured instance of MeasureSources can be created using the
68 makeMeasureSources method.
71 slots = pexConfig.ConfigField(
72 dtype = SourceSlotConfig,
73 doc=
"Mapping from algorithms to special aliases in Source.\n"
76 algorithms = AlgorithmRegistry.all.makeField(
78 default=[
"flags.pixel",
79 "centroid.gaussian",
"centroid.naive",
81 "flux.gaussian",
"flux.naive",
"flux.psf",
"flux.sinc",
83 "classification.extendedness",
86 doc=
"Algorithms that will be run by default."
89 centroider = AlgorithmRegistry.filter(CentroidConfig).makeField(
90 multi=
False, default=
"centroid.sdss", optional=
True,
91 doc=
"Configuration for the initial centroid algorithm used to\n"\
92 "feed center points to other algorithms.\n\n"\
93 "Note that this is in addition to the centroider listed in\n"\
94 "the 'algorithms' field; the same name should not appear in\n"\
96 "This field DOES NOT set which field name will be used to define\n"\
97 "the alias for source.getX(), source.getY(), etc.\n"
100 doReplaceWithNoise = pexConfig.Field(dtype=bool, default=
True, optional=
False,
101 doc=
'When measuring, replace other detected footprints with noise?')
103 replaceWithNoise = pexConfig.ConfigurableField(
104 target = ReplaceWithNoiseTask,
105 doc = (
"Task for replacing other sources by noise when measuring sources; run when " +
106 "'doReplaceWithNoise' is set."),
109 prefix = pexConfig.Field(dtype=str, optional=
True, default=
None, doc=
"prefix for all measurement fields")
112 pexConfig.Config.validate(self)
113 if self.centroider.name
in self.algorithms.names:
114 raise ValueError(
"The algorithm in the 'centroider' field must not also appear in the "\
115 "'algorithms' field.")
116 if self.slots.centroid
is not None and (self.slots.centroid
not in self.algorithms.names
117 and self.slots.centroid != self.centroider.name):
118 raise ValueError(
"source centroid slot algorithm '%s' is not being run." % self.slots.astrom)
119 if self.slots.shape
is not None and self.slots.shape
not in self.algorithms.names:
120 raise ValueError(
"source shape slot algorithm '%s' is not being run." % self.slots.shape)
121 for slot
in (self.slots.psfFlux, self.slots.apFlux, self.slots.modelFlux, self.slots.instFlux):
123 for name
in self.algorithms.names:
124 if len(name) <= len(slot)
and name == slot[:len(name)]:
127 raise ValueError(
"source flux slot algorithm '%s' is not being run." % slot)
131 """ Convenience method to make a MeasureSources instance and
132 fill it with the configured algorithms.
134 This is defined in the Config class to support use in unit tests without needing
135 to construct a Task object.
137 builder = algorithmsLib.MeasureSourcesBuilder(self.
prefix if self.
prefix is not None else "")
138 if self.centroider.name
is not None:
139 builder.setCentroider(self.centroider.apply())
140 builder.addAlgorithms(self.algorithms.apply())
141 return builder.build(schema, metadata)
152 \anchor SourceMeasurementTask_
153 \brief Measure the properties of sources on a single exposure.
155 \section meas_algorithms_measurement_Contents Contents
157 - \ref meas_algorithms_measurement_Purpose
158 - \ref meas_algorithms_measurement_Initialize
159 - \ref meas_algorithms_measurement_Invoke
160 - \ref meas_algorithms_measurement_Config
161 - \ref meas_algorithms_measurement_Debug
162 - \ref meas_algorithms_measurement_Example
164 \section meas_algorithms_measurement_Purpose Description
166 \copybrief SourceMeasurementTask
168 \section meas_algorithms_measurement_Initialize Task initialisation
172 \section meas_algorithms_measurement_Invoke Invoking the Task
174 \deprecated This Task's \c run method is currently called \c measure
178 \subsection SourceMeasurementTask_Hooks Hooks called by measure
180 There are some additional methods available which are typically used to provide extra debugging information.
183 def measure(self, exposure, sources, ...):
184 self.preMeasureHook(exposure, sources)
186 self.preSingleMeasureHook(exposure, sources, -1)
187 for i, source in enumerate(sources):
188 self.preSingleMeasureHook(exposure, sources, i)
189 self.measurer.apply(source, exposure) # Do the actual measuring
190 self.postSingleMeasureHook(exposure, sources, i)
192 self.postMeasureHook(exposure, sources)
195 See SourceMeasurementTask.preMeasureHook, SourceMeasurementTask.preSingleMeasureHook,
196 SourceMeasurementTask.preSingleMeasureHook, SourceMeasurementTask.postSingleMeasureHook, and
197 SourceMeasurementTask.postMeasureHook.
199 \section meas_algorithms_measurement_Config Configuration parameters
201 See \ref SourceMeasurementConfig
203 \section meas_algorithms_measurement_Debug Debug variables
205 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
206 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
208 The available variables in SourceMeasurementTask are:
212 - If True, display the exposure on ds9's frame 0. +ve detections in blue, -ve detections in cyan
213 - Measured sources are labelled:
214 - Objects deblended as PSFs with a * and other objects with a +
215 - Brightest peak in red if parent else magenta
216 - All other peaks in yellow
217 - If display > 1, instead label each point by its ID and draw an error ellipse for its centroid
218 - If display > 2, also print a table of (id, ix, iy) for all measured sources
221 \section meas_algorithms_measurement_Example A complete example of using SourceMeasurementTask
223 This code is in \link measAlgTasks.py\endlink in the examples directory, and can be run as \em e.g.
225 examples/measAlgTasks.py --ds9
227 \dontinclude measAlgTasks.py
229 See \ref meas_algorithms_detection_Example for a few more details on the DetectionTask.
231 Import the tasks (there are some other standard imports; read the file if you're confused)
232 \skip SourceDetectionTask
233 \until SourceMeasurementTask
235 We need to create our tasks before processing any data as the task constructors
236 can add extra columns to the schema. First the detection task
237 \skipline makeMinimalSchema
238 \skip SourceDetectionTask.ConfigClass
240 and then the measurement task using the default algorithms (as set by SourceMeasurementConfig.algorithms):
241 \skipline SourceMeasurementTask.ConfigClass
244 (\c algMetadata is used to return information about the active algorithms).
246 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
247 task objects). First create the output table and process the image to find sources:
255 We then might plot the results (\em e.g. if you set \c --ds9 on the command line)
259 \dontinclude measAlgTasks.py
260 Rather than accept a default set you can select which algorithms should be run.
261 First create the Config object:
262 \skipline SourceMeasurementTask.ConfigClass
263 Then specify which algorithms we're interested in and set any needed parameters:
266 Unfortunately that won't quite work as there are still "slots" (mappings between measurements like PSF fluxes
267 and the algorithms that calculate them) pointing to some of the discarded algorithms (see SourceSlotConfig,
268 \em e.g. SourceSlotConfig.psfFlux), so:
272 and create the task as before:
273 \skipline measureTask
274 We can find out what aperture radii were chosen with
276 and add them to the display code:
280 and end up with something like
281 \image html measAlgTasks-ds9.png
284 To investigate the \ref meas_algorithms_measurement_Debug, put something like
288 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
289 if name == "lsst.meas.algorithms.measurement":
294 lsstDebug.Info = DebugInfo
296 into your debug.py file and run measAlgTasks.py with the \c --debug flag.
298 ConfigClass = SourceMeasurementConfig
299 _DefaultName =
"sourceMeasurement"
302 def init(self, schema, algMetadata=None, **kwds):
303 """!Create the task, adding necessary fields to the given schema.
305 \param[in,out] schema Schema object for measurement fields; will be modified in-place.
306 \param[in,out] algMetadata Passed to MeasureSources object to be filled with initialization
307 metadata by algorithms (e.g. radii for aperture photometry).
308 \param **kwds Keyword arguments passed to lsst.pipe.base.task.Task.__init__.
310 self.
__init__(schema, algMetadata, **kwds)
312 def __init__(self, schema, algMetadata=None, **kwds):
313 """!Create the measurement task. See SourceMeasurementTask.init for documentation
315 pipeBase.Task.__init__(self, **kwds)
316 self.
measurer = self.config.makeMeasureSources(schema, algMetadata)
317 if self.config.doReplaceWithNoise:
318 self.makeSubtask(
'replaceWithNoise')
321 '''!A hook, for debugging purposes, that is called at the start of the
322 measure() method (before any noise replacement has occurred)
323 \param exposure The Exposure being measured
324 \param sources The afwTable of Sources to set
330 ds9.mtv(exposure, title=
"input", frame=frame)
333 '''!A hook, for debugging purposes, that is called at the end of the
334 measure() method, after the sources have been returned to the Exposure.
335 \param exposure The Exposure we just measured
336 \param sources The afwTable of Sources we just measured
341 '''!A hook, for debugging purposes, that is called immediately
342 before the measurement algorithms for each source (after the Source's Footprint
343 has been inserted into the Exposure)
345 \param exposure The Exposure being measured
346 \param sources The afwTable of Sources being measured
347 \param i The index into sources of the Source we're about to measure
349 Note that this will also be called with i=-1 just before entering the
350 loop over measuring sources, *after* the sources have been replaced by noise (if noiseout is True).
362 if self._display > 2
and i >= 0:
363 peak = sources[i].getFootprint().getPeaks()[0]
364 print "%-9d %4d %4d" % (sources[i].getId(), peak.getIx(), peak.getIy())
367 '''!A hook, for debugging purposes, that is called immediately after
368 the measurement algorithms (before the Source has once again been replaced by noise)
370 \param exposure The Exposure being measured
371 \param sources The afwTable of Sources being measured
372 \param i The index into sources of the Source we just measured
377 '''!A hook, for debugging purposes, called by postSingleMeasureHook
379 \param exposure The Exposure being measured
380 \param source The Source we just measured
383 if self._display > 1:
384 ds9.dot(str(source.getId()), source.getX() + 2, source.getY(),
385 size=3, ctype=ds9.RED)
386 cov = source.getCentroidErr()
387 ds9.dot((
"@:%.1f,%.1f,%1f" % (cov[0,0], cov[0,1], cov[1,1])),
388 *source.getCentroid(), size=3, ctype=ds9.RED)
389 symb =
"%d" % source.getId()
392 ds9.dot(symb, *source.getCentroid(), size=3,
393 ctype=ds9.RED
if source.get(
"parent") == 0
else ds9.MAGENTA)
395 for p
in source.getFootprint().getPeaks():
396 ds9.dot(
"+", *p.getF(), size=0.5, ctype=ds9.YELLOW)
399 def measure(self, exposure, sources, noiseImage=None, noiseMeanVar=None, references=None, refWcs=None):
400 """!Measure sources on an exposure, with no aperture correction.
402 \param[in] exposure Exposure to process
403 \param[in,out] sources SourceCatalog containing sources detected on this exposure.
404 \param[in] noiseImage If 'config.doReplaceWithNoise = True', you can pass in
405 an Image containing noise. This overrides the "config.noiseSource" setting.
406 \param[in] noiseMeanVar: if 'config.doReplaceWithNoise = True', you can specify
407 the mean and variance of the Gaussian noise that will be added, by passing
408 a tuple of (mean, variance) floats. This overrides the "config.noiseSource"
409 setting (but is overridden by noiseImage).
410 \param[in] references SourceCatalog containing reference sources detected on reference exposure.
411 \param[in] refWcs Wcs for the reference exposure.
414 if references
is None:
415 references = [
None] * len(sources)
416 if len(sources) != len(references):
417 raise RuntimeError(
"Number of sources (%d) and references (%d) don't match" %
418 (len(sources), len(references)))
420 if self.config.doReplaceWithNoise
and not hasattr(self,
'replaceWithNoise'):
421 self.makeSubtask(
'replaceWithNoise')
423 self.log.info(
"Measuring %d sources" % len(sources))
424 self.config.slots.setupTable(sources.table, prefix=self.config.prefix)
435 noiseout = self.config.doReplaceWithNoise
437 self.replaceWithNoise.begin(exposure, sources, noiseImage, noiseMeanVar)
444 with ds9.Buffering():
445 for i, (source, ref)
in enumerate(zip(sources, references)):
447 self.replaceWithNoise.insertSource(exposure, i)
453 self.measurer.apply(source, exposure)
455 self.measurer.apply(source, exposure, ref, refWcs)
461 self.replaceWithNoise.removeSource(exposure, sources, source)
465 self.replaceWithNoise.end(exposure, sources)
def __init__
Create the measurement task.
def preMeasureHook
A hook, for debugging purposes, that is called at the start of the measure() method (before any noise...
def postSingleMeasurementDisplay
A hook, for debugging purposes, called by postSingleMeasureHook.
def preSingleMeasureHook
A hook, for debugging purposes, that is called immediately before the measurement algorithms for each...
def postSingleMeasureHook
A hook, for debugging purposes, that is called immediately after the measurement algorithms (before t...
def init
Create the task, adding necessary fields to the given schema.
def measure
Measure sources on an exposure, with no aperture correction.
Measure the properties of sources on a single exposure.
def postMeasureHook
A hook, for debugging purposes, that is called at the end of the measure() method, after the sources have been returned to the Exposure.