LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
characterizeImage.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2015 AURA/LSST.
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 <https://www.lsstcorp.org/LegalNotices/>.
21 #
22 import numpy as np
23 
24 from lsstDebug import getDebugFrame
25 import lsst.pex.config as pexConfig
26 import lsst.pipe.base as pipeBase
27 import lsst.daf.base as dafBase
28 from lsst.afw.math import BackgroundList
29 from lsst.afw.table import SourceTable, SourceCatalog, IdFactory
30 from lsst.meas.algorithms import SubtractBackgroundTask, SourceDetectionTask, MeasureApCorrTask
31 from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask
32 from lsst.meas.astrom import AstrometryTask, displayAstrometry, LoadAstrometryNetObjectsTask
33 from lsst.daf.butlerUtils import ExposureIdInfo
34 from lsst.meas.astrom import AstrometryTask, displayAstrometry
35 from lsst.meas.base import SingleFrameMeasurementTask, ApplyApCorrTask, CatalogCalculationTask
36 from lsst.meas.deblender import SourceDeblendTask
37 from .measurePsf import MeasurePsfTask
38 from .repair import RepairTask
39 
40 __all__ = ["CharacterizeImageConfig", "CharacterizeImageTask"]
41 
42 
43 class CharacterizeImageConfig(pexConfig.Config):
44  """!Config for CharacterizeImageTask"""
45  doMeasurePsf = pexConfig.Field(
46  dtype=bool,
47  default=True,
48  doc="Measure PSF? If False then keep the existing PSF model (which must exist) "
49  "and use that model for all operations."
50  )
51  doWrite = pexConfig.Field(
52  dtype=bool,
53  default=True,
54  doc="Persist results?",
55  )
56  doWriteExposure = pexConfig.Field(
57  dtype=bool,
58  default=True,
59  doc="Write icExp and icExpBackground in addition to icSrc? Ignored if doWrite False.",
60  )
61  psfIterations = pexConfig.RangeField(
62  dtype=int,
63  default=2,
64  min=1,
65  doc="Number of iterations of detect sources, measure sources, estimate PSF. "
66  "If useSimplePsf='all_iter' then 2 should be plenty; otherwise more may be wanted.",
67  )
68  background = pexConfig.ConfigurableField(
69  target=SubtractBackgroundTask,
70  doc="Configuration for initial background estimation",
71  )
72  detection = pexConfig.ConfigurableField(
73  target=SourceDetectionTask,
74  doc="Detect sources"
75  )
76  doDeblend = pexConfig.Field(
77  dtype=bool,
78  default=True,
79  doc="Run deblender input exposure"
80  )
81  deblend = pexConfig.ConfigurableField(
82  target=SourceDeblendTask,
83  doc="Split blended source into their components"
84  )
85  measurement = pexConfig.ConfigurableField(
86  target=SingleFrameMeasurementTask,
87  doc="Measure sources"
88  )
89  doApCorr = pexConfig.Field(
90  dtype=bool,
91  default=True,
92  doc="Run subtasks to measure and apply aperture corrections"
93  )
94  measureApCorr = pexConfig.ConfigurableField(
95  target=MeasureApCorrTask,
96  doc="Subtask to measure aperture corrections"
97  )
98  applyApCorr = pexConfig.ConfigurableField(
99  target=ApplyApCorrTask,
100  doc="Subtask to apply aperture corrections"
101  )
102  # If doApCorr is False, and the exposure does not have apcorrections already applied, the
103  # active plugins in catalogCalculation almost certainly should not contain the characterization plugin
104  catalogCalculation = pexConfig.ConfigurableField(
105  target=CatalogCalculationTask,
106  doc="Subtask to run catalogCalculation plugins on catalog"
107  )
108  useSimplePsf = pexConfig.Field(
109  dtype=bool,
110  default=True,
111  doc="Replace the existing PSF model with a simplified version that has the same sigma "
112  "at the start of each PSF determination iteration? Doing so makes PSF determination "
113  "converge more robustly and quickly.",
114  )
115  installSimplePsf = pexConfig.ConfigurableField(
116  target=InstallGaussianPsfTask,
117  doc="Install a simple PSF model",
118  )
119  refObjLoader = pexConfig.ConfigurableField(
120  target = LoadAstrometryNetObjectsTask,
121  doc = "reference object loader",
122  )
123  astrometry = pexConfig.ConfigurableField(
124  target=AstrometryTask,
125  doc="Task to load and match reference objects. Only used if measurePsf can use matches. "
126  "Warning: matching will only work well if the initial WCS is accurate enough "
127  "to give good matches (roughly: good to 3 arcsec across the CCD).",
128  )
129  measurePsf = pexConfig.ConfigurableField(
130  target=MeasurePsfTask,
131  doc="Measure PSF",
132  )
133  repair = pexConfig.ConfigurableField(
134  target=RepairTask,
135  doc="Remove cosmic rays",
136  )
137  checkUnitsParseStrict = pexConfig.Field(
138  doc="Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'",
139  dtype=str,
140  default="raise",
141  )
142 
143  def setDefaults(self):
144  pexConfig.Config.setDefaults(self)
145  # just detect bright stars; includeThresholdMultipler=10 seems large,
146  # but these are the values we have been using
147  self.detection.thresholdValue = 5.0
148  self.detection.includeThresholdMultiplier = 10.0
149  # do not deblend, as it makes a mess
150  self.doDeblend = False
151  # measure and apply aperture correction; note: measuring and applying aperture
152  # correction are disabled until the final measurement, after PSF is measured
153  self.doApCorr = True
154  # minimal set of measurements needed to determine PSF
155  self.measurement.plugins.names = [
156  "base_PixelFlags",
157  "base_SdssCentroid",
158  "base_SdssShape",
159  "base_GaussianFlux",
160  "base_PsfFlux",
161  "base_CircularApertureFlux",
162  ]
163 
164  def validate(self):
165  if self.doApCorr and not self.measurePsf:
166  raise RuntimeError("Must measure PSF to measure aperture correction, "
167  "because flags determined by PSF measurement are used to identify "
168  "sources used to measure aperture correction")
169 
170 ## \addtogroup LSST_task_documentation
171 ## \{
172 ## \page CharacterizeImageTask
173 ## \ref CharacterizeImageTask_ "CharacterizeImageTask"
174 ## \copybrief CharacterizeImageTask
175 ## \}
176 
177 
178 class CharacterizeImageTask(pipeBase.CmdLineTask):
179  """!Measure bright sources and use this to estimate background and PSF of an exposure
180 
181  @anchor CharacterizeImageTask_
182 
183  @section pipe_tasks_characterizeImage_Contents Contents
184 
185  - @ref pipe_tasks_characterizeImage_Purpose
186  - @ref pipe_tasks_characterizeImage_Initialize
187  - @ref pipe_tasks_characterizeImage_IO
188  - @ref pipe_tasks_characterizeImage_Config
189  - @ref pipe_tasks_characterizeImage_Debug
190  - @ref pipe_tasks_characterizeImage_Example
191 
192  @section pipe_tasks_characterizeImage_Purpose Description
193 
194  Given an exposure with defects repaired (masked and interpolated over, e.g. as output by IsrTask):
195  - detect and measure bright sources
196  - repair cosmic rays
197  - measure and subtract background
198  - measure PSF
199 
200  @section pipe_tasks_characterizeImage_Initialize Task initialisation
201 
202  @copydoc \_\_init\_\_
203 
204  @section pipe_tasks_characterizeImage_IO Invoking the Task
205 
206  If you want this task to unpersist inputs or persist outputs, then call
207  the `run` method (a thin wrapper around the `characterize` method).
208 
209  If you already have the inputs unpersisted and do not want to persist the output
210  then it is more direct to call the `characterize` method:
211 
212  @section pipe_tasks_characterizeImage_Config Configuration parameters
213 
214  See @ref CharacterizeImageConfig
215 
216  @section pipe_tasks_characterizeImage_Debug Debug variables
217 
218  The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag
219  `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`.
220 
221  CharacterizeImageTask has a debug dictionary with the following keys:
222  <dl>
223  <dt>frame
224  <dd>int: if specified, the frame of first debug image displayed (defaults to 1)
225  <dt>repair_iter
226  <dd>bool; if True display image after each repair in the measure PSF loop
227  <dt>background_iter
228  <dd>bool; if True display image after each background subtraction in the measure PSF loop
229  <dt>measure_iter
230  <dd>bool; if True display image and sources at the end of each iteration of the measure PSF loop
231  See @ref lsst.meas.astrom.displayAstrometry for the meaning of the various symbols.
232  <dt>psf
233  <dd>bool; if True display image and sources after PSF is measured;
234  this will be identical to the final image displayed by measure_iter if measure_iter is true
235  <dt>repair
236  <dd>bool; if True display image and sources after final repair
237  <dt>measure
238  <dd>bool; if True display image and sources after final measurement
239  </dl>
240 
241  For example, put something like:
242  @code{.py}
243  import lsstDebug
244  def DebugInfo(name):
245  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
246  if name == "lsst.pipe.tasks.characterizeImage":
247  di.display = dict(
248  repair = True,
249  )
250 
251  return di
252 
253  lsstDebug.Info = DebugInfo
254  @endcode
255  into your `debug.py` file and run `calibrateTask.py` with the `--debug` flag.
256 
257  Some subtasks may have their own debug variables; see individual Task documentation.
258 
259  @section pipe_tasks_characterizeImage_Example A complete example of using CharacterizeImageTask
260 
261  This code is in @link calibrateTask.py@endlink (which calls CharacterizeImageTask
262  before calling CalibrateTask) in the examples directory, and can be run as, e.g.:
263  @code
264  python examples/calibrateTask.py --display
265  @endcode
266  @dontinclude calibrateTask.py
267 
268  Import the task (there are some other standard imports; read the file if you're curious)
269  @skipline CharacterizeImageTask
270 
271  Create the task.
272  @skip CharacterizeImageTask.ConfigClass
273  @until config=config
274 
275  We're now ready to process the data. This occurs in two steps:
276  - Characterize the image: measure bright sources, fit a background and PSF, and repairs cosmic rays
277  - Calibrate the exposure: measure faint sources, fit an improved WCS and photometric zero-point
278  @skip loadData
279  @until dot
280  """
281  ConfigClass = CharacterizeImageConfig
282  _DefaultName = "characterizeImage"
283  RunnerClass = pipeBase.ButlerInitializedTaskRunner
284 
285  def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs):
286  """!Construct a CharacterizeImageTask
287 
288  @param[in] butler A butler object is passed to the refObjLoader constructor in case
289  it is needed to load catalogs. May be None if a catalog-based star selector is
290  not used, if the reference object loader constructor does not require a butler,
291  or if a reference object loader is passed directly via the refObjLoader argument.
292  @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an
293  external reference catalog to a catalog-based star selector. May be None if a
294  catalog star selector is not used or the loader can be constructed from the
295  butler argument.
296  @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None
297  @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask
298  """
299  pipeBase.CmdLineTask.__init__(self, **kwargs)
300  if schema is None:
301  schema = SourceTable.makeMinimalSchema()
302  self.schema = schema
303  self.makeSubtask("background")
304  self.makeSubtask("installSimplePsf")
305  self.makeSubtask("repair")
306  self.makeSubtask("measurePsf", schema=self.schema)
307  if self.config.doMeasurePsf and self.measurePsf.usesMatches:
308  if not refObjLoader:
309  self.makeSubtask('refObjLoader', butler=butler)
310  refObjLoader = self.refObjLoader
311  self.makeSubtask("astrometry", refObjLoader=refObjLoader)
313  self.makeSubtask('detection', schema=self.schema)
314  if self.config.doDeblend:
315  self.makeSubtask("deblend", schema=self.schema)
316  self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata)
317  if self.config.doApCorr:
318  self.makeSubtask('measureApCorr', schema=self.schema)
319  self.makeSubtask('applyApCorr', schema=self.schema)
320  self.makeSubtask('catalogCalculation', schema=self.schema)
321  self._initialFrame = getDebugFrame(self._display, "frame") or 1
322  self._frame = self._initialFrame
323  self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
324 
325  @pipeBase.timeMethod
326  def run(self, dataRef, exposure=None, background=None, doUnpersist=True):
327  """!Characterize a science image and, if wanted, persist the results
328 
329  This simply unpacks the exposure and passes it to the characterize method to do the work.
330 
331  @param[in] dataRef: butler data reference for science exposure
332  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
333  If None then unpersist from "postISRCCD".
334  The following changes are made, depending on the config:
335  - set psf to the measured PSF
336  - set apCorrMap to the measured aperture correction
337  - subtract background
338  - interpolate over cosmic rays
339  - update detection and cosmic ray mask planes
340  @param[in,out] background initial model of background already subtracted from exposure
341  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
342  which is typical for image characterization.
343  A refined background model is output.
344  @param[in] doUnpersist if True the exposure is read from the repository
345  and the exposure and background arguments must be None;
346  if False the exposure must be provided.
347  True is intended for running as a command-line task, False for running as a subtask
348 
349  @return same data as the characterize method
350  """
351  self._frame = self._initialFrame # reset debug display frame
352  self.log.info("Processing %s" % (dataRef.dataId))
353 
354  if doUnpersist:
355  if exposure is not None or background is not None:
356  raise RuntimeError("doUnpersist true; exposure and background must be None")
357  exposure = dataRef.get("postISRCCD", immediate=True)
358  elif exposure is None:
359  raise RuntimeError("doUnpersist false; exposure must be provided")
360 
361  exposureIdInfo = dataRef.get("expIdInfo")
362 
363  charRes = self.characterize(
364  exposure=exposure,
365  exposureIdInfo=exposureIdInfo,
366  background=background,
367  )
368 
369  if self.config.doWrite:
370  dataRef.put(charRes.sourceCat, "icSrc")
371  if self.config.doWriteExposure:
372  dataRef.put(charRes.exposure, "icExp")
373  dataRef.put(charRes.background, "icExpBackground")
374 
375  return charRes
376 
377  @pipeBase.timeMethod
378  def characterize(self, exposure, exposureIdInfo=None, background=None):
379  """!Characterize a science image
380 
381  Peforms the following operations:
382  - Iterate the following config.psfIterations times, or once if config.doMeasurePsf false:
383  - detect and measure sources and estimate PSF (see detectMeasureAndEstimatePsf for details)
384  - interpolate over cosmic rays
385  - perform final measurement
386 
387  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
388  The following changes are made:
389  - update or set psf
390  - set apCorrMap
391  - update detection and cosmic ray mask planes
392  - subtract background and interpolate over cosmic rays
393  @param[in] exposureIdInfo ID info for exposure (an lsst.daf.butlerUtils.ExposureIdInfo).
394  If not provided, returned SourceCatalog IDs will not be globally unique.
395  @param[in,out] background initial model of background already subtracted from exposure
396  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
397  which is typical for image characterization.
398 
399  @return pipe_base Struct containing these fields, all from the final iteration
400  of detectMeasureAndEstimatePsf:
401  - exposure: characterized exposure; image is repaired by interpolating over cosmic rays,
402  mask is updated accordingly, and the PSF model is set
403  - sourceCat: detected sources (an lsst.afw.table.SourceCatalog)
404  - background: model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
405  - psfCellSet: spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
406  """
407  self._frame = self._initialFrame # reset debug display frame
408 
409  if not self.config.doMeasurePsf and not exposure.hasPsf():
410  raise RuntimeError("exposure has no PSF model and config.doMeasurePsf false")
411 
412  if exposureIdInfo is None:
413  exposureIdInfo = ExposureIdInfo()
414 
415  # subtract an initial estimate of background level
416  background = self.background.run(exposure).background
417 
418  psfIterations = self.config.psfIterations if self.config.doMeasurePsf else 1
419  for i in range(psfIterations):
420  dmeRes = self.detectMeasureAndEstimatePsf(
421  exposure=exposure,
422  exposureIdInfo=exposureIdInfo,
423  background=background,
424  )
425 
426  psf = dmeRes.exposure.getPsf()
427  psfSigma = psf.computeShape().getDeterminantRadius()
428  psfDimensions = psf.computeImage().getDimensions()
429  medBackground = np.median(dmeRes.background.getImage().getArray())
430  self.log.info("iter %s; PSF sigma=%0.2f, dimensions=%s; median background=%0.2f" %
431  (i + 1, psfSigma, psfDimensions, medBackground))
432 
433  self.display("psf", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
434 
435  # perform final repair with final PSF
436  self.repair.run(exposure=dmeRes.exposure)
437  self.display("repair", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
438 
439  # perform final measurement with final PSF, including measuring and applying aperture correction,
440  # if wanted
441  self.measurement.run(
442  measCat=dmeRes.sourceCat,
443  exposure=dmeRes.exposure,
444  exposureId=exposureIdInfo.expId
445  )
446  if self.config.doApCorr:
447  apCorrMap = self.measureApCorr.run(exposure=dmeRes.exposure, catalog=dmeRes.sourceCat).apCorrMap
448  dmeRes.exposure.getInfo().setApCorrMap(apCorrMap)
449  self.applyApCorr.run(
450  catalog=dmeRes.sourceCat,
451  apCorrMap=exposure.getInfo().getApCorrMap()
452  )
453  self.catalogCalculation.run(dmeRes.sourceCat)
454 
455  self.display("measure", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
456 
457  return dmeRes
458 
459  @pipeBase.timeMethod
460  def detectMeasureAndEstimatePsf(self, exposure, exposureIdInfo, background):
461  """!Perform one iteration of detect, measure and estimate PSF
462 
463  Performs the following operations:
464  - if config.doMeasurePsf:
465  - install a simple PSF model (replacing the existing one, if need be)
466  - interpolate over cosmic rays with keepCRs=True
467  - estimate background and subtract it from the exposure
468  - detect, deblend and measure sources, and subtract a refined background model;
469  - if config.doMeasurePsf:
470  - measure PSF
471 
472  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar)
473  The following changes are made:
474  - update or set psf
475  - update detection and cosmic ray mask planes
476  - subtract background
477  @param[in] exposureIdInfo ID info for exposure (an lsst.daf.butlerUtils.ExposureIdInfo)
478  @param[in,out] background initial model of background already subtracted from exposure
479  (an lsst.afw.math.BackgroundList).
480 
481  @return pipe_base Struct containing these fields, all from the final iteration
482  of detect sources, measure sources and estimate PSF:
483  - exposure characterized exposure; image is repaired by interpolating over cosmic rays,
484  mask is updated accordingly, and the PSF model is set
485  - sourceCat detected sources (an lsst.afw.table.SourceCatalog)
486  - background model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
487  - psfCellSet spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
488  """
489  # install a simple PSF model, if wanted
490  if self.config.doMeasurePsf:
491  if self.config.useSimplePsf or not exposure.hasPsf():
492  self.installSimplePsf.run(exposure=exposure)
493  elif not exposure.hasPsf():
494  raise RuntimeError("exposure has no PSF model and config.doMeasurePsf false")
495 
496  # run repair, but do not interpolate over cosmic rays (do that elsewhere, with the final PSF model)
497  self.repair.run(exposure=exposure, keepCRs=True)
498  self.display("repair_iter", exposure=exposure)
499 
500  if background is None:
501  background = BackgroundList()
502 
503  sourceIdFactory = IdFactory.makeSource(exposureIdInfo.expId, exposureIdInfo.unusedBits)
504  table = SourceTable.make(self.schema, sourceIdFactory)
505  table.setMetadata(self.algMetadata)
506 
507  detRes = self.detection.run(table=table, exposure=exposure, doSmooth=True)
508  sourceCat = detRes.sources
509  if detRes.fpSets.background:
510  background.append(detRes.fpSets.background)
511 
512  if self.config.doDeblend:
513  self.deblend.run(exposure=exposure, sources=sourceCat)
514 
515  self.measurement.run(
516  measCat=sourceCat,
517  exposure=exposure,
518  exposureId=exposureIdInfo.expId
519  )
520 
521  measPsfRes = pipeBase.Struct(
522  cellSet=None
523  )
524  if self.config.doMeasurePsf:
525  if self.measurePsf.usesMatches:
526  matches = self.astrometry.loadAndMatch(
527  exposure=exposure,
528  sourceCat=sourceCat,
529  ).matches
530  else:
531  matches = None
532  measPsfRes = self.measurePsf.run(
533  exposure=exposure,
534  sources=sourceCat,
535  matches=matches,
536  )
537  self.display("measure_iter", exposure=exposure, sourceCat=sourceCat)
538 
539  return pipeBase.Struct(
540  exposure=exposure,
541  sourceCat=sourceCat,
542  background=background,
543  psfCellSet=measPsfRes.cellSet,
544  )
545 
546  def getSchemaCatalogs(self):
547  """Return a dict of empty catalogs for each catalog dataset produced by this task.
548  """
549  sourceCat = SourceCatalog(self.schema)
550  sourceCat.getTable().setMetadata(self.algMetadata)
551  return {"icSrc": sourceCat}
552 
553  def display(self, itemName, exposure, sourceCat=None):
554  """Display exposure and sources on next frame, if display of itemName has been requested
555 
556  @param[in] itemName name of item in debugInfo
557  @param[in] exposure exposure to display
558  @param[in] sourceCat source catalog to display
559  """
560  val = getDebugFrame(self._display, itemName)
561  if not val:
562  return
563 
565  exposure=exposure,
566  sourceCat=sourceCat,
567  frame=self._frame,
568  pause=False,
569  )
570  self._frame += 1
def detectMeasureAndEstimatePsf
Perform one iteration of detect, measure and estimate PSF.
def __init__
Construct a CharacterizeImageTask.
Class for storing ordered metadata with comments.
Definition: PropertyList.h:82
Measure bright sources and use this to estimate background and PSF of an exposure.
def run
Characterize a science image and, if wanted, persist the results.
SortedCatalogT< SourceRecord > SourceCatalog
Definition: fwd.h:75
def getDebugFrame
Definition: lsstDebug.py:66