LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
lsst.meas.algorithms.detection.SourceDetectionTask Class Reference
Inheritance diagram for lsst.meas.algorithms.detection.SourceDetectionTask:
lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask

Public Member Functions

def __init__ (self, schema=None, **kwds)
 
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 detectFootprints (self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None)
 
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

 negativeFlagKey
 

Static Public Attributes

 ConfigClass = SourceDetectionConfig
 

Detailed Description

Create the detection task.  Most arguments are simply passed onto pipe.base.Task.

Parameters
----------
schema : `lsst.afw.table.Schema`
    Schema object used to create the output `lsst.afw.table.SourceCatalog`
**kwds
    Keyword arguments passed to `lsst.pipe.base.task.Task.__init__`

If schema is not None and configured for 'both' detections,
a 'flags.negative' field will be added to label detections made with a
negative threshold.

Notes
-----
This task can add fields to the schema, so any code calling this task must ensure that
these columns are indeed present in the input match list.

Definition at line 161 of file detection.py.

Constructor & Destructor Documentation

◆ __init__()

def lsst.meas.algorithms.detection.SourceDetectionTask.__init__ (   self,
  schema = None,
**  kwds 
)

Definition at line 184 of file detection.py.

184  def __init__(self, schema=None, **kwds):
185  pipeBase.Task.__init__(self, **kwds)
186  if schema is not None and self.config.thresholdPolarity == "both":
187  self.negativeFlagKey = schema.addField(
188  "flags_negative", type="Flag",
189  doc="set if source was detected as significantly negative"
190  )
191  else:
192  if self.config.thresholdPolarity == "both":
193  self.log.warn("Detection polarity set to 'both', but no flag will be "
194  "set to distinguish between positive and negative detections")
195  self.negativeFlagKey = None
196  if self.config.reEstimateBackground:
197  self.makeSubtask("background")
198  if self.config.doTempLocalBackground:
199  self.makeSubtask("tempLocalBackground")
200  if self.config.doTempWideBackground:
201  self.makeSubtask("tempWideBackground")
202 

Member Function Documentation

◆ applyTempLocalBackground()

def lsst.meas.algorithms.detection.SourceDetectionTask.applyTempLocalBackground (   self,
  exposure,
  middle,
  results 
)
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 318 of file detection.py.

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

◆ applyThreshold()

def lsst.meas.algorithms.detection.SourceDetectionTask.applyThreshold (   self,
  middle,
  bbox,
  factor = 1.0 
)
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 475 of file detection.py.

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

◆ calculateKernelSize()

def lsst.meas.algorithms.detection.SourceDetectionTask.calculateKernelSize (   self,
  sigma 
)
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 367 of file detection.py.

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

◆ clearMask()

def lsst.meas.algorithms.detection.SourceDetectionTask.clearMask (   self,
  mask 
)
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 354 of file detection.py.

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

◆ clearUnwantedResults()

def lsst.meas.algorithms.detection.SourceDetectionTask.clearUnwantedResults (   self,
  mask,
  results 
)
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 615 of file detection.py.

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

◆ convolveImage()

def lsst.meas.algorithms.detection.SourceDetectionTask.convolveImage (   self,
  maskedImage,
  psf,
  doSmooth = True 
)
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 414 of file detection.py.

414  def convolveImage(self, maskedImage, psf, doSmooth=True):
415  """Convolve the image with the PSF
416 
417  We convolve the image with a Gaussian approximation to the PSF,
418  because this is separable and therefore fast. It's technically a
419  correlation rather than a convolution, but since we use a symmetric
420  Gaussian there's no difference.
421 
422  The convolution can be disabled with ``doSmooth=False``. If we do
423  convolve, we mask the edges as ``EDGE`` and return the convolved image
424  with the edges removed. This is because we can't convolve the edges
425  because the kernel would extend off the image.
426 
427  Parameters
428  ----------
429  maskedImage : `lsst.afw.image.MaskedImage`
430  Image to convolve.
431  psf : `lsst.afw.detection.Psf`
432  PSF to convolve with (actually with a Gaussian approximation
433  to it).
434  doSmooth : `bool`
435  Actually do the convolution? Set to False when running on
436  e.g. a pre-convolved image, or a mask plane.
437 
438  Return Struct contents
439  ----------------------
440  middle : `lsst.afw.image.MaskedImage`
441  Convolved image, without the edges.
442  sigma : `float`
443  Gaussian sigma used for the convolution.
444  """
445  self.metadata.set("doSmooth", doSmooth)
446  sigma = psf.computeShape().getDeterminantRadius()
447  self.metadata.set("sigma", sigma)
448 
449  if not doSmooth:
450  middle = maskedImage.Factory(maskedImage, deep=True)
451  return pipeBase.Struct(middle=middle, sigma=sigma)
452 
453  # Smooth using a Gaussian (which is separable, hence fast) of width sigma
454  # Make a SingleGaussian (separable) kernel with the 'sigma'
455  kWidth = self.calculateKernelSize(sigma)
456  self.metadata.set("smoothingKernelWidth", kWidth)
457  gaussFunc = afwMath.GaussianFunction1D(sigma)
458  gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)
459 
460  convolvedImage = maskedImage.Factory(maskedImage.getBBox())
461 
462  afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
463  #
464  # Only search psf-smoothed part of frame
465  #
466  goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
467  middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
468  #
469  # Mark the parts of the image outside goodBBox as EDGE
470  #
471  self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))
472 
473  return pipeBase.Struct(middle=middle, sigma=sigma)
474 
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:861
daf::base::PropertySet * set
Definition: fits.cc:912
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.detection.SourceDetectionTask.detectFootprints (   self,
  exposure,
  doSmooth = True,
  sigma = None,
  clearMask = True,
  expId = None 
)
Detect footprints on an exposure.

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``, or the measured PSF width of ``exposure``.
    Set to False when running on e.g. a pre-convolved image, or a mask
    plane.
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 : `dict`, optional
    Exposure identifier; unused by this implementation, but used for
    RNG seed by subclasses.

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.

Reimplemented in lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.

Definition at line 639 of file detection.py.

639  def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
640  """Detect footprints on an exposure.
641 
642  Parameters
643  ----------
644  exposure : `lsst.afw.image.Exposure`
645  Exposure to process; DETECTED{,_NEGATIVE} mask plane will be
646  set in-place.
647  doSmooth : `bool`, optional
648  If True, smooth the image before detection using a Gaussian
649  of width ``sigma``, or the measured PSF width of ``exposure``.
650  Set to False when running on e.g. a pre-convolved image, or a mask
651  plane.
652  sigma : `float`, optional
653  Gaussian Sigma of PSF (pixels); used for smoothing and to grow
654  detections; if `None` then measure the sigma of the PSF of the
655  ``exposure``.
656  clearMask : `bool`, optional
657  Clear both DETECTED and DETECTED_NEGATIVE planes before running
658  detection.
659  expId : `dict`, optional
660  Exposure identifier; unused by this implementation, but used for
661  RNG seed by subclasses.
662 
663  Return Struct contents
664  ----------------------
665  positive : `lsst.afw.detection.FootprintSet`
666  Positive polarity footprints (may be `None`)
667  negative : `lsst.afw.detection.FootprintSet`
668  Negative polarity footprints (may be `None`)
669  numPos : `int`
670  Number of footprints in positive or 0 if detection polarity was
671  negative.
672  numNeg : `int`
673  Number of footprints in negative or 0 if detection polarity was
674  positive.
675  background : `lsst.afw.math.BackgroundList`
676  Re-estimated background. `None` if
677  ``reEstimateBackground==False``.
678  factor : `float`
679  Multiplication factor applied to the configured detection
680  threshold.
681  """
682  maskedImage = exposure.maskedImage
683 
684  if clearMask:
685  self.clearMask(maskedImage.getMask())
686 
687  psf = self.getPsf(exposure, sigma=sigma)
688  with self.tempWideBackgroundContext(exposure):
689  convolveResults = self.convolveImage(maskedImage, psf, doSmooth=doSmooth)
690  middle = convolveResults.middle
691  sigma = convolveResults.sigma
692 
693  results = self.applyThreshold(middle, maskedImage.getBBox())
694  results.background = afwMath.BackgroundList()
695  if self.config.doTempLocalBackground:
696  self.applyTempLocalBackground(exposure, middle, results)
697  self.finalizeFootprints(maskedImage.mask, results, sigma)
698 
699  if self.config.reEstimateBackground:
700  self.reEstimateBackground(maskedImage, results.background)
701 
702  self.clearUnwantedResults(maskedImage.getMask(), results)
703  self.display(exposure, results, middle)
704 
705  return results
706 

◆ display()

def lsst.meas.algorithms.detection.SourceDetectionTask.display (   self,
  exposure,
  results,
  convolvedImage = None 
)
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 264 of file detection.py.

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

◆ finalizeFootprints()

def lsst.meas.algorithms.detection.SourceDetectionTask.finalizeFootprints (   self,
  mask,
  results,
  sigma,
  factor = 1.0 
)
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 524 of file detection.py.

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

◆ getPsf()

def lsst.meas.algorithms.detection.SourceDetectionTask.getPsf (   self,
  exposure,
  sigma = None 
)
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 387 of file detection.py.

387  def getPsf(self, exposure, sigma=None):
388  """Retrieve the PSF for an exposure
389 
390  If ``sigma`` is provided, we make a ``GaussianPsf`` with that,
391  otherwise use the one from the ``exposure``.
392 
393  Parameters
394  ----------
395  exposure : `lsst.afw.image.Exposure`
396  Exposure from which to retrieve the PSF.
397  sigma : `float`, optional
398  Gaussian sigma to use if provided.
399 
400  Returns
401  -------
402  psf : `lsst.afw.detection.Psf`
403  PSF to use for detection.
404  """
405  if sigma is None:
406  psf = exposure.getPsf()
407  if psf is None:
408  raise RuntimeError("Unable to determine PSF to use for detection: no sigma provided")
409  sigma = psf.computeShape().getDeterminantRadius()
410  size = self.calculateKernelSize(sigma)
411  psf = afwDet.GaussianPsf(size, size, sigma)
412  return psf
413 
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 
)
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 707 of file detection.py.

707  def makeThreshold(self, image, thresholdParity, factor=1.0):
708  """Make an afw.detection.Threshold object corresponding to the task's
709  configuration and the statistics of the given image.
710 
711  Parameters
712  ----------
713  image : `afw.image.MaskedImage`
714  Image to measure noise statistics from if needed.
715  thresholdParity: `str`
716  One of "positive" or "negative", to set the kind of fluctuations
717  the Threshold will detect.
718  factor : `float`
719  Factor by which to multiply the configured detection threshold.
720  This is useful for tweaking the detection threshold slightly.
721 
722  Returns
723  -------
724  threshold : `lsst.afw.detection.Threshold`
725  Detection threshold.
726  """
727  parity = False if thresholdParity == "negative" else True
728  thresholdValue = self.config.thresholdValue
729  thresholdType = self.config.thresholdType
730  if self.config.thresholdType == 'stdev':
731  bad = image.getMask().getPlaneBitMask(self.config.statsMask)
732  sctrl = afwMath.StatisticsControl()
733  sctrl.setAndMask(bad)
734  stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl)
735  thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
736  thresholdType = 'value'
737 
738  threshold = afwDet.createThreshold(thresholdValue*factor, thresholdType, parity)
739  threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
740  return threshold
741 
Pass parameters to a Statistics object.
Definition: Statistics.h:93
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:354

◆ reEstimateBackground()

def lsst.meas.algorithms.detection.SourceDetectionTask.reEstimateBackground (   self,
  maskedImage,
  backgrounds 
)
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 586 of file detection.py.

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

◆ run()

def lsst.meas.algorithms.detection.SourceDetectionTask.run (   self,
  table,
  exposure,
  doSmooth = True,
  sigma = None,
  clearMask = True,
  expId = None 
)
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 204 of file detection.py.

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

◆ setEdgeBits()

def lsst.meas.algorithms.detection.SourceDetectionTask.setEdgeBits (   maskedImage,
  goodBBox,
  edgeBitmask 
)
static
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 785 of file detection.py.

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

◆ tempWideBackgroundContext()

def lsst.meas.algorithms.detection.SourceDetectionTask.tempWideBackgroundContext (   self,
  exposure 
)
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 815 of file detection.py.

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

◆ updatePeaks()

def lsst.meas.algorithms.detection.SourceDetectionTask.updatePeaks (   self,
  fpSet,
  image,
  threshold 
)
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 742 of file detection.py.

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

Member Data Documentation

◆ ConfigClass

lsst.meas.algorithms.detection.SourceDetectionTask.ConfigClass = SourceDetectionConfig
static

Definition at line 181 of file detection.py.

◆ negativeFlagKey

lsst.meas.algorithms.detection.SourceDetectionTask.negativeFlagKey

Definition at line 187 of file detection.py.


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