LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask Class Reference
Inheritance diagram for lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask:
lsst.meas.algorithms.detection.SourceDetectionTask

Public Member Functions

def __init__ (self, *args, **kwargs)
 
def calculateThreshold (self, exposure, seed, sigma=None)
 
def detectFootprints (self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None)
 
def tweakBackground (self, exposure, bgLevel, bgList=None)
 
def run (self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None)
 
def display (self, exposure, results, convolvedImage=None)
 
def applyTempLocalBackground (self, exposure, middle, results)
 
def clearMask (self, mask)
 
def calculateKernelSize (self, sigma)
 
def getPsf (self, exposure, sigma=None)
 
def convolveImage (self, maskedImage, psf, doSmooth=True)
 
def applyThreshold (self, middle, bbox, factor=1.0)
 
def finalizeFootprints (self, mask, results, sigma, factor=1.0)
 
def reEstimateBackground (self, maskedImage, backgrounds)
 
def clearUnwantedResults (self, mask, results)
 
def makeThreshold (self, image, thresholdParity, factor=1.0)
 
def updatePeaks (self, fpSet, image, threshold)
 
def tempWideBackgroundContext (self, exposure)
 

Static Public Member Functions

def setEdgeBits (maskedImage, goodBBox, edgeBitmask)
 

Public Attributes

 skySchema
 
 skyMeasurement
 
 negativeFlagKey
 

Static Public Attributes

 ConfigClass = DynamicDetectionConfig
 

Detailed Description

Detection of sources on an image with a dynamic threshold

We first detect sources using a lower threshold than normal (see config
parameter ``prelimThresholdFactor``) in order to identify good sky regions
(configurable ``skyObjects``). Then we perform forced PSF photometry on
those sky regions. Using those PSF flux measurements and estimated errors,
we set the threshold so that the stdev of the measurements matches the
median estimated error.

Besides the usual initialisation of configurables, we also set up
the forced measurement which is deliberately not represented in
this Task's configuration parameters because we're using it as
part of the algorithm and we don't want to allow it to be modified.

Definition at line 37 of file dynamicDetection.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.__init__ (   self,
args,
**  kwargs 
)

Definition at line 55 of file dynamicDetection.py.

55  def __init__(self, *args, **kwargs):
56 
57  SourceDetectionTask.__init__(self, *args, **kwargs)
58  self.makeSubtask("skyObjects")
59 
60  # Set up forced measurement.
61  config = ForcedMeasurementTask.ConfigClass()
62  config.plugins.names = ['base_TransformedCentroid', 'base_PsfFlux', 'base_LocalBackground']
63  # We'll need the "centroid" and "psfFlux" slots
64  for slot in ("shape", "psfShape", "apFlux", "modelFlux", "gaussianFlux", "calibFlux"):
65  setattr(config.slots, slot, None)
66  config.copyColumns = {}
67  self.skySchema = SourceTable.makeMinimalSchema()
68  self.skyMeasurement = ForcedMeasurementTask(config=config, name="skyMeasurement", parentTask=self,
69  refSchema=self.skySchema)
70 

Member Function Documentation

◆ applyTempLocalBackground()

def lsst.meas.algorithms.detection.SourceDetectionTask.applyTempLocalBackground (   self,
  exposure,
  middle,
  results 
)
inherited
Apply a temporary local background subtraction

This temporary local background serves to suppress noise fluctuations
in the wings of bright objects.

Peaks in the footprints will be updated.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure for which to fit local background.
middle : `lsst.afw.image.MaskedImage`
    Convolved image on which detection will be performed
    (typically smaller than ``exposure`` because the
    half-kernel has been removed around the edges).
results : `lsst.pipe.base.Struct`
    Results of the 'detectFootprints' method, containing positive and
    negative footprints (which contain the peak positions that we will
    plot). This is a `Struct` with ``positive`` and ``negative``
    elements that are of type `lsst.afw.detection.FootprintSet`.

Definition at line 319 of file detection.py.

319  def applyTempLocalBackground(self, exposure, middle, results):
320  """Apply a temporary local background subtraction
321 
322  This temporary local background serves to suppress noise fluctuations
323  in the wings of bright objects.
324 
325  Peaks in the footprints will be updated.
326 
327  Parameters
328  ----------
329  exposure : `lsst.afw.image.Exposure`
330  Exposure for which to fit local background.
331  middle : `lsst.afw.image.MaskedImage`
332  Convolved image on which detection will be performed
333  (typically smaller than ``exposure`` because the
334  half-kernel has been removed around the edges).
335  results : `lsst.pipe.base.Struct`
336  Results of the 'detectFootprints' method, containing positive and
337  negative footprints (which contain the peak positions that we will
338  plot). This is a `Struct` with ``positive`` and ``negative``
339  elements that are of type `lsst.afw.detection.FootprintSet`.
340  """
341  # Subtract the local background from the smoothed image. Since we
342  # never use the smoothed again we don't need to worry about adding
343  # it back in.
344  bg = self.tempLocalBackground.fitBackground(exposure.getMaskedImage())
345  bgImage = bg.getImageF(self.tempLocalBackground.config.algorithm,
346  self.tempLocalBackground.config.undersampleStyle)
347  middle -= bgImage.Factory(bgImage, middle.getBBox())
348  thresholdPos = self.makeThreshold(middle, "positive")
349  thresholdNeg = self.makeThreshold(middle, "negative")
350  if self.config.thresholdPolarity != "negative":
351  self.updatePeaks(results.positive, middle, thresholdPos)
352  if self.config.thresholdPolarity != "positive":
353  self.updatePeaks(results.negative, middle, thresholdNeg)
354 

◆ applyThreshold()

def lsst.meas.algorithms.detection.SourceDetectionTask.applyThreshold (   self,
  middle,
  bbox,
  factor = 1.0 
)
inherited
Apply thresholds to the convolved image

Identifies ``Footprint``s, both positive and negative.

The threshold can be modified by the provided multiplication
``factor``.

Parameters
----------
middle : `lsst.afw.image.MaskedImage`
    Convolved image to threshold.
bbox : `lsst.geom.Box2I`
    Bounding box of unconvolved image.
factor : `float`
    Multiplier for the configured threshold.

Return Struct contents
----------------------
positive : `lsst.afw.detection.FootprintSet` or `None`
    Positive detection footprints, if configured.
negative : `lsst.afw.detection.FootprintSet` or `None`
    Negative detection footprints, if configured.
factor : `float`
    Multiplier for the configured threshold.

Definition at line 476 of file detection.py.

476  def applyThreshold(self, middle, bbox, factor=1.0):
477  """Apply thresholds to the convolved image
478 
479  Identifies ``Footprint``s, both positive and negative.
480 
481  The threshold can be modified by the provided multiplication
482  ``factor``.
483 
484  Parameters
485  ----------
486  middle : `lsst.afw.image.MaskedImage`
487  Convolved image to threshold.
488  bbox : `lsst.geom.Box2I`
489  Bounding box of unconvolved image.
490  factor : `float`
491  Multiplier for the configured threshold.
492 
493  Return Struct contents
494  ----------------------
495  positive : `lsst.afw.detection.FootprintSet` or `None`
496  Positive detection footprints, if configured.
497  negative : `lsst.afw.detection.FootprintSet` or `None`
498  Negative detection footprints, if configured.
499  factor : `float`
500  Multiplier for the configured threshold.
501  """
502  results = pipeBase.Struct(positive=None, negative=None, factor=factor)
503  # Detect the Footprints (peaks may be replaced if doTempLocalBackground)
504  if self.config.reEstimateBackground or self.config.thresholdPolarity != "negative":
505  threshold = self.makeThreshold(middle, "positive", factor=factor)
506  results.positive = afwDet.FootprintSet(
507  middle,
508  threshold,
509  "DETECTED",
510  self.config.minPixels
511  )
512  results.positive.setRegion(bbox)
513  if self.config.reEstimateBackground or self.config.thresholdPolarity != "positive":
514  threshold = self.makeThreshold(middle, "negative", factor=factor)
515  results.negative = afwDet.FootprintSet(
516  middle,
517  threshold,
518  "DETECTED_NEGATIVE",
519  self.config.minPixels
520  )
521  results.negative.setRegion(bbox)
522 
523  return results
524 
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53

◆ calculateKernelSize()

def lsst.meas.algorithms.detection.SourceDetectionTask.calculateKernelSize (   self,
  sigma 
)
inherited
Calculate size of smoothing kernel

Uses the ``nSigmaForKernel`` configuration parameter. Note
that that is the full width of the kernel bounding box
(so a value of 7 means 3.5 sigma on either side of center).
The value will be rounded up to the nearest odd integer.

Parameters
----------
sigma : `float`
    Gaussian sigma of smoothing kernel.

Returns
-------
size : `int`
    Size of the smoothing kernel.

Definition at line 368 of file detection.py.

368  def calculateKernelSize(self, sigma):
369  """Calculate size of smoothing kernel
370 
371  Uses the ``nSigmaForKernel`` configuration parameter. Note
372  that that is the full width of the kernel bounding box
373  (so a value of 7 means 3.5 sigma on either side of center).
374  The value will be rounded up to the nearest odd integer.
375 
376  Parameters
377  ----------
378  sigma : `float`
379  Gaussian sigma of smoothing kernel.
380 
381  Returns
382  -------
383  size : `int`
384  Size of the smoothing kernel.
385  """
386  return (int(sigma * self.config.nSigmaForKernel + 0.5)//2)*2 + 1 # make sure it is odd
387 

◆ calculateThreshold()

def lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.calculateThreshold (   self,
  exposure,
  seed,
  sigma = None 
)
Calculate new threshold

This is the main functional addition to the vanilla
`SourceDetectionTask`.

We identify sky objects and perform forced PSF photometry on
them. Using those PSF flux measurements and estimated errors,
we set the threshold so that the stdev of the measurements
matches the median estimated error.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure on which we're detecting sources.
seed : `int`
    RNG seed to use for finding sky objects.
sigma : `float`, optional
    Gaussian sigma of smoothing kernel; if not provided,
    will be deduced from the exposure's PSF.

Returns
-------
result : `lsst.pipe.base.Struct`
    Result struct with components:

    - ``multiplicative``: multiplicative factor to be applied to the
        configured detection threshold (`float`).
    - ``additive``: additive factor to be applied to the background
        level (`float`).

Definition at line 71 of file dynamicDetection.py.

71  def calculateThreshold(self, exposure, seed, sigma=None):
72  """Calculate new threshold
73 
74  This is the main functional addition to the vanilla
75  `SourceDetectionTask`.
76 
77  We identify sky objects and perform forced PSF photometry on
78  them. Using those PSF flux measurements and estimated errors,
79  we set the threshold so that the stdev of the measurements
80  matches the median estimated error.
81 
82  Parameters
83  ----------
84  exposure : `lsst.afw.image.Exposure`
85  Exposure on which we're detecting sources.
86  seed : `int`
87  RNG seed to use for finding sky objects.
88  sigma : `float`, optional
89  Gaussian sigma of smoothing kernel; if not provided,
90  will be deduced from the exposure's PSF.
91 
92  Returns
93  -------
94  result : `lsst.pipe.base.Struct`
95  Result struct with components:
96 
97  - ``multiplicative``: multiplicative factor to be applied to the
98  configured detection threshold (`float`).
99  - ``additive``: additive factor to be applied to the background
100  level (`float`).
101  """
102  # Make a catalog of sky objects
103  fp = self.skyObjects.run(exposure.maskedImage.mask, seed)
104  skyFootprints = FootprintSet(exposure.getBBox())
105  skyFootprints.setFootprints(fp)
106  table = SourceTable.make(self.skyMeasurement.schema)
107  catalog = SourceCatalog(table)
108  catalog.reserve(len(skyFootprints.getFootprints()))
109  skyFootprints.makeSources(catalog)
110  key = catalog.getCentroidSlot().getMeasKey()
111  for source in catalog:
112  peaks = source.getFootprint().getPeaks()
113  assert len(peaks) == 1
114  source.set(key, peaks[0].getF())
115  source.updateCoord(exposure.getWcs())
116 
117  # Forced photometry on sky objects
118  self.skyMeasurement.run(catalog, exposure, catalog, exposure.getWcs())
119 
120  # Calculate new threshold
121  fluxes = catalog["base_PsfFlux_instFlux"]
122  area = catalog["base_PsfFlux_area"]
123  bg = catalog["base_LocalBackground_instFlux"]
124 
125  good = (~catalog["base_PsfFlux_flag"] & ~catalog["base_LocalBackground_flag"]
126  & np.isfinite(fluxes) & np.isfinite(area) & np.isfinite(bg))
127 
128  if good.sum() < self.config.minNumSources:
129  self.log.warning("Insufficient good flux measurements (%d < %d) for dynamic threshold"
130  " calculation", good.sum(), self.config.minNumSources)
131  return Struct(multiplicative=1.0, additive=0.0)
132 
133  bgMedian = np.median((fluxes/area)[good])
134 
135  lq, uq = np.percentile((fluxes - bg*area)[good], [25.0, 75.0])
136  stdevMeas = 0.741*(uq - lq)
137  medianError = np.median(catalog["base_PsfFlux_instFluxErr"][good])
138  return Struct(multiplicative=medianError/stdevMeas, additive=bgMedian)
139 
SortedCatalogT< SourceRecord > SourceCatalog
Definition: fwd.h:85
def run(self, coaddExposures, bbox, wcs)
Definition: getTemplate.py:603

◆ clearMask()

def lsst.meas.algorithms.detection.SourceDetectionTask.clearMask (   self,
  mask 
)
inherited
Clear the DETECTED and DETECTED_NEGATIVE mask planes

Removes any previous detection mask in preparation for a new
detection pass.

Parameters
----------
mask : `lsst.afw.image.Mask`
    Mask to be cleared.

Definition at line 355 of file detection.py.

355  def clearMask(self, mask):
356  """Clear the DETECTED and DETECTED_NEGATIVE mask planes
357 
358  Removes any previous detection mask in preparation for a new
359  detection pass.
360 
361  Parameters
362  ----------
363  mask : `lsst.afw.image.Mask`
364  Mask to be cleared.
365  """
366  mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE"))
367 

◆ clearUnwantedResults()

def lsst.meas.algorithms.detection.SourceDetectionTask.clearUnwantedResults (   self,
  mask,
  results 
)
inherited
Clear unwanted results from the Struct of results

If we specifically want only positive or only negative detections,
drop the ones we don't want, and its associated mask plane.

Parameters
----------
mask : `lsst.afw.image.Mask`
    Mask image.
results : `lsst.pipe.base.Struct`
    Detection results, with ``positive`` and ``negative`` elements;
    modified.

Definition at line 616 of file detection.py.

616  def clearUnwantedResults(self, mask, results):
617  """Clear unwanted results from the Struct of results
618 
619  If we specifically want only positive or only negative detections,
620  drop the ones we don't want, and its associated mask plane.
621 
622  Parameters
623  ----------
624  mask : `lsst.afw.image.Mask`
625  Mask image.
626  results : `lsst.pipe.base.Struct`
627  Detection results, with ``positive`` and ``negative`` elements;
628  modified.
629  """
630  if self.config.thresholdPolarity == "positive":
631  if self.config.reEstimateBackground:
632  mask &= ~mask.getPlaneBitMask("DETECTED_NEGATIVE")
633  results.negative = None
634  elif self.config.thresholdPolarity == "negative":
635  if self.config.reEstimateBackground:
636  mask &= ~mask.getPlaneBitMask("DETECTED")
637  results.positive = None
638 

◆ convolveImage()

def lsst.meas.algorithms.detection.SourceDetectionTask.convolveImage (   self,
  maskedImage,
  psf,
  doSmooth = True 
)
inherited
Convolve the image with the PSF

We convolve the image with a Gaussian approximation to the PSF,
because this is separable and therefore fast. It's technically a
correlation rather than a convolution, but since we use a symmetric
Gaussian there's no difference.

The convolution can be disabled with ``doSmooth=False``. If we do
convolve, we mask the edges as ``EDGE`` and return the convolved image
with the edges removed. This is because we can't convolve the edges
because the kernel would extend off the image.

Parameters
----------
maskedImage : `lsst.afw.image.MaskedImage`
    Image to convolve.
psf : `lsst.afw.detection.Psf`
    PSF to convolve with (actually with a Gaussian approximation
    to it).
doSmooth : `bool`
    Actually do the convolution? Set to False when running on
    e.g. a pre-convolved image, or a mask plane.

Return Struct contents
----------------------
middle : `lsst.afw.image.MaskedImage`
    Convolved image, without the edges.
sigma : `float`
    Gaussian sigma used for the convolution.

Definition at line 415 of file detection.py.

415  def convolveImage(self, maskedImage, psf, doSmooth=True):
416  """Convolve the image with the PSF
417 
418  We convolve the image with a Gaussian approximation to the PSF,
419  because this is separable and therefore fast. It's technically a
420  correlation rather than a convolution, but since we use a symmetric
421  Gaussian there's no difference.
422 
423  The convolution can be disabled with ``doSmooth=False``. If we do
424  convolve, we mask the edges as ``EDGE`` and return the convolved image
425  with the edges removed. This is because we can't convolve the edges
426  because the kernel would extend off the image.
427 
428  Parameters
429  ----------
430  maskedImage : `lsst.afw.image.MaskedImage`
431  Image to convolve.
432  psf : `lsst.afw.detection.Psf`
433  PSF to convolve with (actually with a Gaussian approximation
434  to it).
435  doSmooth : `bool`
436  Actually do the convolution? Set to False when running on
437  e.g. a pre-convolved image, or a mask plane.
438 
439  Return Struct contents
440  ----------------------
441  middle : `lsst.afw.image.MaskedImage`
442  Convolved image, without the edges.
443  sigma : `float`
444  Gaussian sigma used for the convolution.
445  """
446  self.metadata["doSmooth"] = doSmooth
447  sigma = psf.computeShape().getDeterminantRadius()
448  self.metadata["sigma"] = sigma
449 
450  if not doSmooth:
451  middle = maskedImage.Factory(maskedImage, deep=True)
452  return pipeBase.Struct(middle=middle, sigma=sigma)
453 
454  # Smooth using a Gaussian (which is separable, hence fast) of width sigma
455  # Make a SingleGaussian (separable) kernel with the 'sigma'
456  kWidth = self.calculateKernelSize(sigma)
457  self.metadata["smoothingKernelWidth"] = kWidth
458  gaussFunc = afwMath.GaussianFunction1D(sigma)
459  gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)
460 
461  convolvedImage = maskedImage.Factory(maskedImage.getBBox())
462 
463  afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
464  #
465  # Only search psf-smoothed part of frame
466  #
467  goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
468  middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
469  #
470  # Mark the parts of the image outside goodBBox as EDGE
471  #
472  self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))
473 
474  return pipeBase.Struct(middle=middle, sigma=sigma)
475 
Parameters to control convolution.
Definition: ConvolveImage.h:50
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
Definition: Kernel.h:860
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image.

◆ detectFootprints()

def lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.detectFootprints (   self,
  exposure,
  doSmooth = True,
  sigma = None,
  clearMask = True,
  expId = None 
)
Detect footprints with a dynamic threshold

This varies from the vanilla ``detectFootprints`` method because we
do detection twice: one with a low threshold so that we can find
sky uncontaminated by objects, then one more with the new calculated
threshold.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to process; DETECTED{,_NEGATIVE} mask plane will be
    set in-place.
doSmooth : `bool`, optional
    If True, smooth the image before detection using a Gaussian
    of width ``sigma``.
sigma : `float`, optional
    Gaussian Sigma of PSF (pixels); used for smoothing and to grow
    detections; if `None` then measure the sigma of the PSF of the
    ``exposure``.
clearMask : `bool`, optional
    Clear both DETECTED and DETECTED_NEGATIVE planes before running
    detection.
expId : `int`, optional
    Exposure identifier, used as a seed for the random number
    generator. If absent, the seed will be the sum of the image.

Return Struct contents
----------------------
positive : `lsst.afw.detection.FootprintSet`
    Positive polarity footprints (may be `None`)
negative : `lsst.afw.detection.FootprintSet`
    Negative polarity footprints (may be `None`)
numPos : `int`
    Number of footprints in positive or 0 if detection polarity was
    negative.
numNeg : `int`
    Number of footprints in negative or 0 if detection polarity was
    positive.
background : `lsst.afw.math.BackgroundList`
    Re-estimated background.  `None` if
    ``reEstimateBackground==False``.
factor : `float`
    Multiplication factor applied to the configured detection
    threshold.
prelim : `lsst.pipe.base.Struct`
    Results from preliminary detection pass.

Reimplemented from lsst.meas.algorithms.detection.SourceDetectionTask.

Definition at line 140 of file dynamicDetection.py.

140  def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
141  """Detect footprints with a dynamic threshold
142 
143  This varies from the vanilla ``detectFootprints`` method because we
144  do detection twice: one with a low threshold so that we can find
145  sky uncontaminated by objects, then one more with the new calculated
146  threshold.
147 
148  Parameters
149  ----------
150  exposure : `lsst.afw.image.Exposure`
151  Exposure to process; DETECTED{,_NEGATIVE} mask plane will be
152  set in-place.
153  doSmooth : `bool`, optional
154  If True, smooth the image before detection using a Gaussian
155  of width ``sigma``.
156  sigma : `float`, optional
157  Gaussian Sigma of PSF (pixels); used for smoothing and to grow
158  detections; if `None` then measure the sigma of the PSF of the
159  ``exposure``.
160  clearMask : `bool`, optional
161  Clear both DETECTED and DETECTED_NEGATIVE planes before running
162  detection.
163  expId : `int`, optional
164  Exposure identifier, used as a seed for the random number
165  generator. If absent, the seed will be the sum of the image.
166 
167  Return Struct contents
168  ----------------------
169  positive : `lsst.afw.detection.FootprintSet`
170  Positive polarity footprints (may be `None`)
171  negative : `lsst.afw.detection.FootprintSet`
172  Negative polarity footprints (may be `None`)
173  numPos : `int`
174  Number of footprints in positive or 0 if detection polarity was
175  negative.
176  numNeg : `int`
177  Number of footprints in negative or 0 if detection polarity was
178  positive.
179  background : `lsst.afw.math.BackgroundList`
180  Re-estimated background. `None` if
181  ``reEstimateBackground==False``.
182  factor : `float`
183  Multiplication factor applied to the configured detection
184  threshold.
185  prelim : `lsst.pipe.base.Struct`
186  Results from preliminary detection pass.
187  """
188  maskedImage = exposure.maskedImage
189 
190  if clearMask:
191  self.clearMask(maskedImage.mask)
192  else:
193  oldDetected = maskedImage.mask.array & maskedImage.mask.getPlaneBitMask(["DETECTED",
194  "DETECTED_NEGATIVE"])
195 
196  with self.tempWideBackgroundContext(exposure):
197  # Could potentially smooth with a wider kernel than the PSF in order to better pick up the
198  # wings of stars and galaxies, but for now sticking with the PSF as that's more simple.
199  psf = self.getPsf(exposure, sigma=sigma)
200  convolveResults = self.convolveImage(maskedImage, psf, doSmooth=doSmooth)
201  middle = convolveResults.middle
202  sigma = convolveResults.sigma
203  prelim = self.applyThreshold(middle, maskedImage.getBBox(), self.config.prelimThresholdFactor)
204  self.finalizeFootprints(maskedImage.mask, prelim, sigma, self.config.prelimThresholdFactor)
205 
206  # Calculate the proper threshold
207  # seed needs to fit in a C++ 'int' so pybind doesn't choke on it
208  seed = (expId if expId is not None else int(maskedImage.image.array.sum())) % (2**31 - 1)
209  threshResults = self.calculateThreshold(exposure, seed, sigma=sigma)
210  factor = threshResults.multiplicative
211  self.log.info("Modifying configured detection threshold by factor %f to %f",
212  factor, factor*self.config.thresholdValue)
213 
214  # Blow away preliminary (low threshold) detection mask
215  self.clearMask(maskedImage.mask)
216  if not clearMask:
217  maskedImage.mask.array |= oldDetected
218 
219  # Rinse and repeat thresholding with new calculated threshold
220  results = self.applyThreshold(middle, maskedImage.getBBox(), factor)
221  results.prelim = prelim
222  results.background = lsst.afw.math.BackgroundList()
223  if self.config.doTempLocalBackground:
224  self.applyTempLocalBackground(exposure, middle, results)
225  self.finalizeFootprints(maskedImage.mask, results, sigma, factor)
226 
227  self.clearUnwantedResults(maskedImage.mask, results)
228 
229  if self.config.reEstimateBackground:
230  self.reEstimateBackground(maskedImage, results.background)
231 
232  self.display(exposure, results, middle)
233 
234  if self.config.doBackgroundTweak:
235  # Re-do the background tweak after any temporary backgrounds have been restored
236  #
237  # But we want to keep any large-scale background (e.g., scattered light from bright stars)
238  # from being selected for sky objects in the calculation, so do another detection pass without
239  # either the local or wide temporary background subtraction; the DETECTED pixels will mark
240  # the area to ignore.
241  originalMask = maskedImage.mask.array.copy()
242  try:
243  self.clearMask(exposure.mask)
244  convolveResults = self.convolveImage(maskedImage, psf, doSmooth=doSmooth)
245  tweakDetResults = self.applyThreshold(convolveResults.middle, maskedImage.getBBox(), factor)
246  self.finalizeFootprints(maskedImage.mask, tweakDetResults, sigma, factor)
247  bgLevel = self.calculateThreshold(exposure, seed, sigma=sigma).additive
248  finally:
249  maskedImage.mask.array[:] = originalMask
250  self.tweakBackground(exposure, bgLevel, results.background)
251 
252  return results
253 

◆ display()

def lsst.meas.algorithms.detection.SourceDetectionTask.display (   self,
  exposure,
  results,
  convolvedImage = None 
)
inherited
Display detections if so configured

Displays the ``exposure`` in frame 0, overlays the detection peaks.

Requires that ``lsstDebug`` has been set up correctly, so that
``lsstDebug.Info("lsst.meas.algorithms.detection")`` evaluates `True`.

If the ``convolvedImage`` is non-`None` and
``lsstDebug.Info("lsst.meas.algorithms.detection") > 1``, the
``convolvedImage`` will be displayed in frame 1.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to display, on which will be plotted the detections.
results : `lsst.pipe.base.Struct`
    Results of the 'detectFootprints' method, containing positive and
    negative footprints (which contain the peak positions that we will
    plot). This is a `Struct` with ``positive`` and ``negative``
    elements that are of type `lsst.afw.detection.FootprintSet`.
convolvedImage : `lsst.afw.image.Image`, optional
    Convolved image used for thresholding.

Definition at line 265 of file detection.py.

265  def display(self, exposure, results, convolvedImage=None):
266  """Display detections if so configured
267 
268  Displays the ``exposure`` in frame 0, overlays the detection peaks.
269 
270  Requires that ``lsstDebug`` has been set up correctly, so that
271  ``lsstDebug.Info("lsst.meas.algorithms.detection")`` evaluates `True`.
272 
273  If the ``convolvedImage`` is non-`None` and
274  ``lsstDebug.Info("lsst.meas.algorithms.detection") > 1``, the
275  ``convolvedImage`` will be displayed in frame 1.
276 
277  Parameters
278  ----------
279  exposure : `lsst.afw.image.Exposure`
280  Exposure to display, on which will be plotted the detections.
281  results : `lsst.pipe.base.Struct`
282  Results of the 'detectFootprints' method, containing positive and
283  negative footprints (which contain the peak positions that we will
284  plot). This is a `Struct` with ``positive`` and ``negative``
285  elements that are of type `lsst.afw.detection.FootprintSet`.
286  convolvedImage : `lsst.afw.image.Image`, optional
287  Convolved image used for thresholding.
288  """
289  try:
290  import lsstDebug
291  display = lsstDebug.Info(__name__).display
292  except ImportError:
293  try:
294  display
295  except NameError:
296  display = False
297  if not display:
298  return
299 
300  afwDisplay.setDefaultMaskTransparency(75)
301 
302  disp0 = afwDisplay.Display(frame=0)
303  disp0.mtv(exposure, title="detection")
304 
305  def plotPeaks(fps, ctype):
306  if fps is None:
307  return
308  with disp0.Buffering():
309  for fp in fps.getFootprints():
310  for pp in fp.getPeaks():
311  disp0.dot("+", pp.getFx(), pp.getFy(), ctype=ctype)
312  plotPeaks(results.positive, "yellow")
313  plotPeaks(results.negative, "red")
314 
315  if convolvedImage and display > 1:
316  disp1 = afwDisplay.Display(frame=1)
317  disp1.mtv(convolvedImage, title="PSF smoothed")
318 

◆ finalizeFootprints()

def lsst.meas.algorithms.detection.SourceDetectionTask.finalizeFootprints (   self,
  mask,
  results,
  sigma,
  factor = 1.0 
)
inherited
Finalize the detected footprints

Grows the footprints, sets the ``DETECTED`` and ``DETECTED_NEGATIVE``
mask planes, and logs the results.

``numPos`` (number of positive footprints), ``numPosPeaks`` (number
of positive peaks), ``numNeg`` (number of negative footprints),
``numNegPeaks`` (number of negative peaks) entries are added to the
detection results.

Parameters
----------
mask : `lsst.afw.image.Mask`
    Mask image on which to flag detected pixels.
results : `lsst.pipe.base.Struct`
    Struct of detection results, including ``positive`` and
    ``negative`` entries; modified.
sigma : `float`
    Gaussian sigma of PSF.
factor : `float`
    Multiplier for the configured threshold.

Definition at line 525 of file detection.py.

525  def finalizeFootprints(self, mask, results, sigma, factor=1.0):
526  """Finalize the detected footprints
527 
528  Grows the footprints, sets the ``DETECTED`` and ``DETECTED_NEGATIVE``
529  mask planes, and logs the results.
530 
531  ``numPos`` (number of positive footprints), ``numPosPeaks`` (number
532  of positive peaks), ``numNeg`` (number of negative footprints),
533  ``numNegPeaks`` (number of negative peaks) entries are added to the
534  detection results.
535 
536  Parameters
537  ----------
538  mask : `lsst.afw.image.Mask`
539  Mask image on which to flag detected pixels.
540  results : `lsst.pipe.base.Struct`
541  Struct of detection results, including ``positive`` and
542  ``negative`` entries; modified.
543  sigma : `float`
544  Gaussian sigma of PSF.
545  factor : `float`
546  Multiplier for the configured threshold.
547  """
548  for polarity, maskName in (("positive", "DETECTED"), ("negative", "DETECTED_NEGATIVE")):
549  fpSet = getattr(results, polarity)
550  if fpSet is None:
551  continue
552  if self.config.nSigmaToGrow > 0:
553  nGrow = int((self.config.nSigmaToGrow * sigma) + 0.5)
554  self.metadata["nGrow"] = nGrow
555  if self.config.combinedGrow:
556  fpSet = afwDet.FootprintSet(fpSet, nGrow, self.config.isotropicGrow)
557  else:
558  stencil = (afwGeom.Stencil.CIRCLE if self.config.isotropicGrow else
559  afwGeom.Stencil.MANHATTAN)
560  for fp in fpSet:
561  fp.dilate(nGrow, stencil)
562  fpSet.setMask(mask, maskName)
563  if not self.config.returnOriginalFootprints:
564  setattr(results, polarity, fpSet)
565 
566  results.numPos = 0
567  results.numPosPeaks = 0
568  results.numNeg = 0
569  results.numNegPeaks = 0
570  positive = ""
571  negative = ""
572 
573  if results.positive is not None:
574  results.numPos = len(results.positive.getFootprints())
575  results.numPosPeaks = sum(len(fp.getPeaks()) for fp in results.positive.getFootprints())
576  positive = " %d positive peaks in %d footprints" % (results.numPosPeaks, results.numPos)
577  if results.negative is not None:
578  results.numNeg = len(results.negative.getFootprints())
579  results.numNegPeaks = sum(len(fp.getPeaks()) for fp in results.negative.getFootprints())
580  negative = " %d negative peaks in %d footprints" % (results.numNegPeaks, results.numNeg)
581 
582  self.log.info("Detected%s%s%s to %g %s",
583  positive, " and" if positive and negative else "", negative,
584  self.config.thresholdValue*self.config.includeThresholdMultiplier*factor,
585  "DN" if self.config.thresholdType == "value" else "sigma")
586 

◆ getPsf()

def lsst.meas.algorithms.detection.SourceDetectionTask.getPsf (   self,
  exposure,
  sigma = None 
)
inherited
Retrieve the PSF for an exposure

If ``sigma`` is provided, we make a ``GaussianPsf`` with that,
otherwise use the one from the ``exposure``.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure from which to retrieve the PSF.
sigma : `float`, optional
    Gaussian sigma to use if provided.

Returns
-------
psf : `lsst.afw.detection.Psf`
    PSF to use for detection.

Definition at line 388 of file detection.py.

388  def getPsf(self, exposure, sigma=None):
389  """Retrieve the PSF for an exposure
390 
391  If ``sigma`` is provided, we make a ``GaussianPsf`` with that,
392  otherwise use the one from the ``exposure``.
393 
394  Parameters
395  ----------
396  exposure : `lsst.afw.image.Exposure`
397  Exposure from which to retrieve the PSF.
398  sigma : `float`, optional
399  Gaussian sigma to use if provided.
400 
401  Returns
402  -------
403  psf : `lsst.afw.detection.Psf`
404  PSF to use for detection.
405  """
406  if sigma is None:
407  psf = exposure.getPsf()
408  if psf is None:
409  raise RuntimeError("Unable to determine PSF to use for detection: no sigma provided")
410  sigma = psf.computeShape().getDeterminantRadius()
411  size = self.calculateKernelSize(sigma)
412  psf = afwDet.GaussianPsf(size, size, sigma)
413  return psf
414 
A circularly symmetric Gaussian Psf class with no spatial variation, intended mostly for testing purp...
Definition: GaussianPsf.h:42

◆ makeThreshold()

def lsst.meas.algorithms.detection.SourceDetectionTask.makeThreshold (   self,
  image,
  thresholdParity,
  factor = 1.0 
)
inherited
Make an afw.detection.Threshold object corresponding to the task's
configuration and the statistics of the given image.

Parameters
----------
image : `afw.image.MaskedImage`
    Image to measure noise statistics from if needed.
thresholdParity: `str`
    One of "positive" or "negative", to set the kind of fluctuations
    the Threshold will detect.
factor : `float`
    Factor by which to multiply the configured detection threshold.
    This is useful for tweaking the detection threshold slightly.

Returns
-------
threshold : `lsst.afw.detection.Threshold`
    Detection threshold.

Definition at line 708 of file detection.py.

708  def makeThreshold(self, image, thresholdParity, factor=1.0):
709  """Make an afw.detection.Threshold object corresponding to the task's
710  configuration and the statistics of the given image.
711 
712  Parameters
713  ----------
714  image : `afw.image.MaskedImage`
715  Image to measure noise statistics from if needed.
716  thresholdParity: `str`
717  One of "positive" or "negative", to set the kind of fluctuations
718  the Threshold will detect.
719  factor : `float`
720  Factor by which to multiply the configured detection threshold.
721  This is useful for tweaking the detection threshold slightly.
722 
723  Returns
724  -------
725  threshold : `lsst.afw.detection.Threshold`
726  Detection threshold.
727  """
728  parity = False if thresholdParity == "negative" else True
729  thresholdValue = self.config.thresholdValue
730  thresholdType = self.config.thresholdType
731  if self.config.thresholdType == 'stdev':
732  bad = image.getMask().getPlaneBitMask(self.config.statsMask)
733  sctrl = afwMath.StatisticsControl()
734  sctrl.setAndMask(bad)
735  stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl)
736  thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
737  thresholdType = 'value'
738 
739  threshold = afwDet.createThreshold(thresholdValue*factor, thresholdType, parity)
740  threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
741  return threshold
742 
Pass parameters to a Statistics object.
Definition: Statistics.h:92
Threshold createThreshold(const double value, const std::string type="value", const bool polarity=true)
Factory method for creating Threshold objects.
Definition: Threshold.cc:109
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
Definition: Statistics.h:359

◆ reEstimateBackground()

def lsst.meas.algorithms.detection.SourceDetectionTask.reEstimateBackground (   self,
  maskedImage,
  backgrounds 
)
inherited
Estimate the background after detection

Parameters
----------
maskedImage : `lsst.afw.image.MaskedImage`
    Image on which to estimate the background.
backgrounds : `lsst.afw.math.BackgroundList`
    List of backgrounds; modified.

Returns
-------
bg : `lsst.afw.math.backgroundMI`
    Empirical background model.

Definition at line 587 of file detection.py.

587  def reEstimateBackground(self, maskedImage, backgrounds):
588  """Estimate the background after detection
589 
590  Parameters
591  ----------
592  maskedImage : `lsst.afw.image.MaskedImage`
593  Image on which to estimate the background.
594  backgrounds : `lsst.afw.math.BackgroundList`
595  List of backgrounds; modified.
596 
597  Returns
598  -------
599  bg : `lsst.afw.math.backgroundMI`
600  Empirical background model.
601  """
602  bg = self.background.fitBackground(maskedImage)
603  if self.config.adjustBackground:
604  self.log.warning("Fiddling the background by %g", self.config.adjustBackground)
605  bg += self.config.adjustBackground
606  self.log.info("Resubtracting the background after object detection")
607  maskedImage -= bg.getImageF(self.background.config.algorithm,
608  self.background.config.undersampleStyle)
609 
610  actrl = bg.getBackgroundControl().getApproximateControl()
611  backgrounds.append((bg, getattr(afwMath.Interpolate, self.background.config.algorithm),
612  bg.getAsUsedUndersampleStyle(), actrl.getStyle(), actrl.getOrderX(),
613  actrl.getOrderY(), actrl.getWeighting()))
614  return bg
615 

◆ run()

def lsst.meas.algorithms.detection.SourceDetectionTask.run (   self,
  table,
  exposure,
  doSmooth = True,
  sigma = None,
  clearMask = True,
  expId = None 
)
inherited
Run source detection and create a SourceCatalog of detections.

Parameters
----------
table : `lsst.afw.table.SourceTable`
    Table object that will be used to create the SourceCatalog.
exposure : `lsst.afw.image.Exposure`
    Exposure to process; DETECTED mask plane will be set in-place.
doSmooth : `bool`
    If True, smooth the image before detection using a Gaussian of width
    ``sigma``, or the measured PSF width. Set to False when running on
    e.g. a pre-convolved image, or a mask plane.
sigma : `float`
    Sigma of PSF (pixels); used for smoothing and to grow detections;
    if None then measure the sigma of the PSF of the exposure
clearMask : `bool`
    Clear DETECTED{,_NEGATIVE} planes before running detection.
expId : `int`
    Exposure identifier; unused by this implementation, but used for
    RNG seed by subclasses.

Returns
-------
result : `lsst.pipe.base.Struct`
  ``sources``
      The detected sources (`lsst.afw.table.SourceCatalog`)
  ``fpSets``
      The result resturned by `detectFootprints`
      (`lsst.pipe.base.Struct`).

Raises
------
ValueError
    If flags.negative is needed, but isn't in table's schema.
lsst.pipe.base.TaskError
    If sigma=None, doSmooth=True and the exposure has no PSF.

Notes
-----
If you want to avoid dealing with Sources and Tables, you can use
detectFootprints() to just get the `lsst.afw.detection.FootprintSet`s.

Definition at line 205 of file detection.py.

205  def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
206  """Run source detection and create a SourceCatalog of detections.
207 
208  Parameters
209  ----------
210  table : `lsst.afw.table.SourceTable`
211  Table object that will be used to create the SourceCatalog.
212  exposure : `lsst.afw.image.Exposure`
213  Exposure to process; DETECTED mask plane will be set in-place.
214  doSmooth : `bool`
215  If True, smooth the image before detection using a Gaussian of width
216  ``sigma``, or the measured PSF width. Set to False when running on
217  e.g. a pre-convolved image, or a mask plane.
218  sigma : `float`
219  Sigma of PSF (pixels); used for smoothing and to grow detections;
220  if None then measure the sigma of the PSF of the exposure
221  clearMask : `bool`
222  Clear DETECTED{,_NEGATIVE} planes before running detection.
223  expId : `int`
224  Exposure identifier; unused by this implementation, but used for
225  RNG seed by subclasses.
226 
227  Returns
228  -------
229  result : `lsst.pipe.base.Struct`
230  ``sources``
231  The detected sources (`lsst.afw.table.SourceCatalog`)
232  ``fpSets``
233  The result resturned by `detectFootprints`
234  (`lsst.pipe.base.Struct`).
235 
236  Raises
237  ------
238  ValueError
239  If flags.negative is needed, but isn't in table's schema.
240  lsst.pipe.base.TaskError
241  If sigma=None, doSmooth=True and the exposure has no PSF.
242 
243  Notes
244  -----
245  If you want to avoid dealing with Sources and Tables, you can use
246  detectFootprints() to just get the `lsst.afw.detection.FootprintSet`s.
247  """
248  if self.negativeFlagKey is not None and self.negativeFlagKey not in table.getSchema():
249  raise ValueError("Table has incorrect Schema")
250  results = self.detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
251  clearMask=clearMask, expId=expId)
252  sources = afwTable.SourceCatalog(table)
253  sources.reserve(results.numPos + results.numNeg)
254  if results.negative:
255  results.negative.makeSources(sources)
256  if self.negativeFlagKey:
257  for record in sources:
258  record.set(self.negativeFlagKey, True)
259  if results.positive:
260  results.positive.makeSources(sources)
261  results.fpSets = results.copy() # Backward compatibility
262  results.sources = sources
263  return results
264 

◆ setEdgeBits()

def lsst.meas.algorithms.detection.SourceDetectionTask.setEdgeBits (   maskedImage,
  goodBBox,
  edgeBitmask 
)
staticinherited
Set the edgeBitmask bits for all of maskedImage outside goodBBox

Parameters
----------
maskedImage : `lsst.afw.image.MaskedImage`
    Image on which to set edge bits in the mask.
goodBBox : `lsst.geom.Box2I`
    Bounding box of good pixels, in ``LOCAL`` coordinates.
edgeBitmask : `lsst.afw.image.MaskPixel`
    Bit mask to OR with the existing mask bits in the region
    outside ``goodBBox``.

Definition at line 786 of file detection.py.

786  def setEdgeBits(maskedImage, goodBBox, edgeBitmask):
787  """Set the edgeBitmask bits for all of maskedImage outside goodBBox
788 
789  Parameters
790  ----------
791  maskedImage : `lsst.afw.image.MaskedImage`
792  Image on which to set edge bits in the mask.
793  goodBBox : `lsst.geom.Box2I`
794  Bounding box of good pixels, in ``LOCAL`` coordinates.
795  edgeBitmask : `lsst.afw.image.MaskPixel`
796  Bit mask to OR with the existing mask bits in the region
797  outside ``goodBBox``.
798  """
799  msk = maskedImage.getMask()
800 
801  mx0, my0 = maskedImage.getXY0()
802  for x0, y0, w, h in ([0, 0,
803  msk.getWidth(), goodBBox.getBeginY() - my0],
804  [0, goodBBox.getEndY() - my0, msk.getWidth(),
805  maskedImage.getHeight() - (goodBBox.getEndY() - my0)],
806  [0, 0,
807  goodBBox.getBeginX() - mx0, msk.getHeight()],
808  [goodBBox.getEndX() - mx0, 0,
809  maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
810  ):
811  edgeMask = msk.Factory(msk, lsst.geom.BoxI(lsst.geom.PointI(x0, y0),
812  lsst.geom.ExtentI(w, h)), afwImage.LOCAL)
813  edgeMask |= edgeBitmask
814 
An integer coordinate rectangle.
Definition: Box.h:55

◆ tempWideBackgroundContext()

def lsst.meas.algorithms.detection.SourceDetectionTask.tempWideBackgroundContext (   self,
  exposure 
)
inherited
Context manager for removing wide (large-scale) background

Removing a wide (large-scale) background helps to suppress the
detection of large footprints that may overwhelm the deblender.
It does, however, set a limit on the maximum scale of objects.

The background that we remove will be restored upon exit from
the context manager.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure on which to remove large-scale background.

Returns
-------
context : context manager
    Context manager that will ensure the temporary wide background
    is restored.

Definition at line 816 of file detection.py.

816  def tempWideBackgroundContext(self, exposure):
817  """Context manager for removing wide (large-scale) background
818 
819  Removing a wide (large-scale) background helps to suppress the
820  detection of large footprints that may overwhelm the deblender.
821  It does, however, set a limit on the maximum scale of objects.
822 
823  The background that we remove will be restored upon exit from
824  the context manager.
825 
826  Parameters
827  ----------
828  exposure : `lsst.afw.image.Exposure`
829  Exposure on which to remove large-scale background.
830 
831  Returns
832  -------
833  context : context manager
834  Context manager that will ensure the temporary wide background
835  is restored.
836  """
837  doTempWideBackground = self.config.doTempWideBackground
838  if doTempWideBackground:
839  self.log.info("Applying temporary wide background subtraction")
840  original = exposure.maskedImage.image.array[:].copy()
841  self.tempWideBackground.run(exposure).background
842  # Remove NO_DATA regions (e.g., edge of the field-of-view); these can cause detections after
843  # subtraction because of extrapolation of the background model into areas with no constraints.
844  image = exposure.maskedImage.image
845  mask = exposure.maskedImage.mask
846  noData = mask.array & mask.getPlaneBitMask("NO_DATA") > 0
847  isGood = mask.array & mask.getPlaneBitMask(self.config.statsMask) == 0
848  image.array[noData] = np.median(image.array[~noData & isGood])
849  try:
850  yield
851  finally:
852  if doTempWideBackground:
853  exposure.maskedImage.image.array[:] = original
854 
855 

◆ tweakBackground()

def lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.tweakBackground (   self,
  exposure,
  bgLevel,
  bgList = None 
)
Modify the background by a constant value

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure for which to tweak background.
bgLevel : `float`
    Background level to remove
bgList : `lsst.afw.math.BackgroundList`, optional
    List of backgrounds to append to.

Returns
-------
bg : `lsst.afw.math.BackgroundMI`
    Constant background model.

Definition at line 254 of file dynamicDetection.py.

254  def tweakBackground(self, exposure, bgLevel, bgList=None):
255  """Modify the background by a constant value
256 
257  Parameters
258  ----------
259  exposure : `lsst.afw.image.Exposure`
260  Exposure for which to tweak background.
261  bgLevel : `float`
262  Background level to remove
263  bgList : `lsst.afw.math.BackgroundList`, optional
264  List of backgrounds to append to.
265 
266  Returns
267  -------
268  bg : `lsst.afw.math.BackgroundMI`
269  Constant background model.
270  """
271  self.log.info("Tweaking background by %f to match sky photometry", bgLevel)
272  exposure.image -= bgLevel
273  bgStats = lsst.afw.image.MaskedImageF(1, 1)
274  bgStats.set(bgLevel, 0, bgLevel)
275  bg = lsst.afw.math.BackgroundMI(exposure.getBBox(), bgStats)
276  bgData = (bg, lsst.afw.math.Interpolate.LINEAR, lsst.afw.math.REDUCE_INTERP_ORDER,
277  lsst.afw.math.ApproximateControl.UNKNOWN, 0, 0, False)
278  if bgList is not None:
279  bgList.append(bgData)
280  return bg
A class to evaluate image background levels.
Definition: Background.h:434

◆ updatePeaks()

def lsst.meas.algorithms.detection.SourceDetectionTask.updatePeaks (   self,
  fpSet,
  image,
  threshold 
)
inherited
Update the Peaks in a FootprintSet by detecting new Footprints and
Peaks in an image and using the new Peaks instead of the old ones.

Parameters
----------
fpSet : `afw.detection.FootprintSet`
    Set of Footprints whose Peaks should be updated.
image : `afw.image.MaskedImage`
    Image to detect new Footprints and Peak in.
threshold : `afw.detection.Threshold`
    Threshold object for detection.

Input Footprints with fewer Peaks than self.config.nPeaksMaxSimple
are not modified, and if no new Peaks are detected in an input
Footprint, the brightest original Peak in that Footprint is kept.

Definition at line 743 of file detection.py.

743  def updatePeaks(self, fpSet, image, threshold):
744  """Update the Peaks in a FootprintSet by detecting new Footprints and
745  Peaks in an image and using the new Peaks instead of the old ones.
746 
747  Parameters
748  ----------
749  fpSet : `afw.detection.FootprintSet`
750  Set of Footprints whose Peaks should be updated.
751  image : `afw.image.MaskedImage`
752  Image to detect new Footprints and Peak in.
753  threshold : `afw.detection.Threshold`
754  Threshold object for detection.
755 
756  Input Footprints with fewer Peaks than self.config.nPeaksMaxSimple
757  are not modified, and if no new Peaks are detected in an input
758  Footprint, the brightest original Peak in that Footprint is kept.
759  """
760  for footprint in fpSet.getFootprints():
761  oldPeaks = footprint.getPeaks()
762  if len(oldPeaks) <= self.config.nPeaksMaxSimple:
763  continue
764  # We detect a new FootprintSet within each non-simple Footprint's
765  # bbox to avoid a big O(N^2) comparison between the two sets of
766  # Footprints.
767  sub = image.Factory(image, footprint.getBBox())
768  fpSetForPeaks = afwDet.FootprintSet(
769  sub,
770  threshold,
771  "", # don't set a mask plane
772  self.config.minPixels
773  )
774  newPeaks = afwDet.PeakCatalog(oldPeaks.getTable())
775  for fpForPeaks in fpSetForPeaks.getFootprints():
776  for peak in fpForPeaks.getPeaks():
777  if footprint.contains(peak.getI()):
778  newPeaks.append(peak)
779  if len(newPeaks) > 0:
780  del oldPeaks[:]
781  oldPeaks.extend(newPeaks)
782  else:
783  del oldPeaks[1:]
784 

Member Data Documentation

◆ ConfigClass

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.ConfigClass = DynamicDetectionConfig
static

Definition at line 52 of file dynamicDetection.py.

◆ negativeFlagKey

lsst.meas.algorithms.detection.SourceDetectionTask.negativeFlagKey
inherited

Definition at line 188 of file detection.py.

◆ skyMeasurement

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.skyMeasurement

Definition at line 68 of file dynamicDetection.py.

◆ skySchema

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.skySchema

Definition at line 67 of file dynamicDetection.py.


The documentation for this class was generated from the following file: