LSSTApplications  17.0+124,17.0+14,17.0+73,18.0.0+37,18.0.0+80,18.0.0-4-g68ffd23+4,18.1.0-1-g0001055+12,18.1.0-1-g03d53ef+5,18.1.0-1-g1349e88+55,18.1.0-1-g2505f39+44,18.1.0-1-g5315e5e+4,18.1.0-1-g5e4b7ea+14,18.1.0-1-g7e8fceb+4,18.1.0-1-g85f8cd4+48,18.1.0-1-g8ff0b9f+4,18.1.0-1-ga2c679d+1,18.1.0-1-gd55f500+35,18.1.0-10-gb58edde+2,18.1.0-11-g0997b02+4,18.1.0-13-gfe4edf0b+12,18.1.0-14-g259bd21+21,18.1.0-19-gdb69f3f+2,18.1.0-2-g5f9922c+24,18.1.0-2-gd3b74e5+11,18.1.0-2-gfbf3545+32,18.1.0-26-g728bddb4+5,18.1.0-27-g6ff7ca9+2,18.1.0-3-g52aa583+25,18.1.0-3-g8ea57af+9,18.1.0-3-gb69f684+42,18.1.0-3-gfcaddf3+6,18.1.0-32-gd8786685a,18.1.0-4-gf3f9b77+6,18.1.0-5-g1dd662b+2,18.1.0-5-g6dbcb01+41,18.1.0-6-gae77429+3,18.1.0-7-g9d75d83+9,18.1.0-7-gae09a6d+30,18.1.0-9-gc381ef5+4,w.2019.45
LSSTDataManagementBasePackage
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
 
def makeSourceCatalog = run
 An alias for run. More...
 

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.

Definition at line 36 of file dynamicDetection.py.

Constructor & Destructor Documentation

◆ __init__()

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

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 49 of file dynamicDetection.py.

49  def __init__(self, *args, **kwargs):
50  """Constructor
51 
52  Besides the usual initialisation of configurables, we also set up
53  the forced measurement which is deliberately not represented in
54  this Task's configuration parameters because we're using it as part
55  of the algorithm and we don't want to allow it to be modified.
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 
def __init__(self, minimum, dataRange, Q)

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 414 of file detection.py.

414  def applyTempLocalBackground(self, exposure, middle, results):
415  """Apply a temporary local background subtraction
416 
417  This temporary local background serves to suppress noise fluctuations
418  in the wings of bright objects.
419 
420  Peaks in the footprints will be updated.
421 
422  Parameters
423  ----------
424  exposure : `lsst.afw.image.Exposure`
425  Exposure for which to fit local background.
426  middle : `lsst.afw.image.MaskedImage`
427  Convolved image on which detection will be performed
428  (typically smaller than ``exposure`` because the
429  half-kernel has been removed around the edges).
430  results : `lsst.pipe.base.Struct`
431  Results of the 'detectFootprints' method, containing positive and
432  negative footprints (which contain the peak positions that we will
433  plot). This is a `Struct` with ``positive`` and ``negative``
434  elements that are of type `lsst.afw.detection.FootprintSet`.
435  """
436  # Subtract the local background from the smoothed image. Since we
437  # never use the smoothed again we don't need to worry about adding
438  # it back in.
439  bg = self.tempLocalBackground.fitBackground(exposure.getMaskedImage())
440  bgImage = bg.getImageF()
441  middle -= bgImage.Factory(bgImage, middle.getBBox())
442  thresholdPos = self.makeThreshold(middle, "positive")
443  thresholdNeg = self.makeThreshold(middle, "negative")
444  if self.config.thresholdPolarity != "negative":
445  self.updatePeaks(results.positive, middle, thresholdPos)
446  if self.config.thresholdPolarity != "positive":
447  self.updatePeaks(results.negative, middle, thresholdNeg)
448 

◆ 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 570 of file detection.py.

570  def applyThreshold(self, middle, bbox, factor=1.0):
571  """Apply thresholds to the convolved image
572 
573  Identifies ``Footprint``s, both positive and negative.
574 
575  The threshold can be modified by the provided multiplication
576  ``factor``.
577 
578  Parameters
579  ----------
580  middle : `lsst.afw.image.MaskedImage`
581  Convolved image to threshold.
582  bbox : `lsst.geom.Box2I`
583  Bounding box of unconvolved image.
584  factor : `float`
585  Multiplier for the configured threshold.
586 
587  Return Struct contents
588  ----------------------
589  positive : `lsst.afw.detection.FootprintSet` or `None`
590  Positive detection footprints, if configured.
591  negative : `lsst.afw.detection.FootprintSet` or `None`
592  Negative detection footprints, if configured.
593  factor : `float`
594  Multiplier for the configured threshold.
595  """
596  results = pipeBase.Struct(positive=None, negative=None, factor=factor)
597  # Detect the Footprints (peaks may be replaced if doTempLocalBackground)
598  if self.config.reEstimateBackground or self.config.thresholdPolarity != "negative":
599  threshold = self.makeThreshold(middle, "positive", factor=factor)
600  results.positive = afwDet.FootprintSet(
601  middle,
602  threshold,
603  "DETECTED",
604  self.config.minPixels
605  )
606  results.positive.setRegion(bbox)
607  if self.config.reEstimateBackground or self.config.thresholdPolarity != "positive":
608  threshold = self.makeThreshold(middle, "negative", factor=factor)
609  results.negative = afwDet.FootprintSet(
610  middle,
611  threshold,
612  "DETECTED_NEGATIVE",
613  self.config.minPixels
614  )
615  results.negative.setRegion(bbox)
616 
617  return results
618 
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 462 of file detection.py.

462  def calculateKernelSize(self, sigma):
463  """Calculate size of smoothing kernel
464 
465  Uses the ``nSigmaForKernel`` configuration parameter. Note
466  that that is the full width of the kernel bounding box
467  (so a value of 7 means 3.5 sigma on either side of center).
468  The value will be rounded up to the nearest odd integer.
469 
470  Parameters
471  ----------
472  sigma : `float`
473  Gaussian sigma of smoothing kernel.
474 
475  Returns
476  -------
477  size : `int`
478  Size of the smoothing kernel.
479  """
480  return (int(sigma * self.config.nSigmaForKernel + 0.5)//2)*2 + 1 # make sure it is odd
481 

◆ 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.getCentroidKey()
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.warn("Insufficient good flux measurements (%d < %d) for dynamic threshold calculation",
130  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 
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
SortedCatalogT< SourceRecord > SourceCatalog
Definition: fwd.h:85

◆ 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 449 of file detection.py.

449  def clearMask(self, mask):
450  """Clear the DETECTED and DETECTED_NEGATIVE mask planes
451 
452  Removes any previous detection mask in preparation for a new
453  detection pass.
454 
455  Parameters
456  ----------
457  mask : `lsst.afw.image.Mask`
458  Mask to be cleared.
459  """
460  mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE"))
461 

◆ 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 705 of file detection.py.

705  def clearUnwantedResults(self, mask, results):
706  """Clear unwanted results from the Struct of results
707 
708  If we specifically want only positive or only negative detections,
709  drop the ones we don't want, and its associated mask plane.
710 
711  Parameters
712  ----------
713  mask : `lsst.afw.image.Mask`
714  Mask image.
715  results : `lsst.pipe.base.Struct`
716  Detection results, with ``positive`` and ``negative`` elements;
717  modified.
718  """
719  if self.config.thresholdPolarity == "positive":
720  if self.config.reEstimateBackground:
721  mask &= ~mask.getPlaneBitMask("DETECTED_NEGATIVE")
722  results.negative = None
723  elif self.config.thresholdPolarity == "negative":
724  if self.config.reEstimateBackground:
725  mask &= ~mask.getPlaneBitMask("DETECTED")
726  results.positive = None
727 

◆ 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 509 of file detection.py.

509  def convolveImage(self, maskedImage, psf, doSmooth=True):
510  """Convolve the image with the PSF
511 
512  We convolve the image with a Gaussian approximation to the PSF,
513  because this is separable and therefore fast. It's technically a
514  correlation rather than a convolution, but since we use a symmetric
515  Gaussian there's no difference.
516 
517  The convolution can be disabled with ``doSmooth=False``. If we do
518  convolve, we mask the edges as ``EDGE`` and return the convolved image
519  with the edges removed. This is because we can't convolve the edges
520  because the kernel would extend off the image.
521 
522  Parameters
523  ----------
524  maskedImage : `lsst.afw.image.MaskedImage`
525  Image to convolve.
526  psf : `lsst.afw.detection.Psf`
527  PSF to convolve with (actually with a Gaussian approximation
528  to it).
529  doSmooth : `bool`
530  Actually do the convolution? Set to False when running on
531  e.g. a pre-convolved image, or a mask plane.
532 
533  Return Struct contents
534  ----------------------
535  middle : `lsst.afw.image.MaskedImage`
536  Convolved image, without the edges.
537  sigma : `float`
538  Gaussian sigma used for the convolution.
539  """
540  self.metadata.set("doSmooth", doSmooth)
541  sigma = psf.computeShape().getDeterminantRadius()
542  self.metadata.set("sigma", sigma)
543 
544  if not doSmooth:
545  middle = maskedImage.Factory(maskedImage)
546  return pipeBase.Struct(middle=middle, sigma=sigma)
547 
548  # Smooth using a Gaussian (which is separable, hence fast) of width sigma
549  # Make a SingleGaussian (separable) kernel with the 'sigma'
550  kWidth = self.calculateKernelSize(sigma)
551  self.metadata.set("smoothingKernelWidth", kWidth)
552  gaussFunc = afwMath.GaussianFunction1D(sigma)
553  gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)
554 
555  convolvedImage = maskedImage.Factory(maskedImage.getBBox())
556 
557  afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
558  #
559  # Only search psf-smoothed part of frame
560  #
561  goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
562  middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
563  #
564  # Mark the parts of the image outside goodBBox as EDGE
565  #
566  self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))
567 
568  return pipeBase.Struct(middle=middle, sigma=sigma)
569 
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:895
daf::base::PropertySet * set
Definition: fits.cc:902
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)
Old, deprecated version of convolve.

◆ 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.

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 360 of file detection.py.

360  def display(self, exposure, results, convolvedImage=None):
361  """Display detections if so configured
362 
363  Displays the ``exposure`` in frame 0, overlays the detection peaks.
364 
365  Requires that ``lsstDebug`` has been set up correctly, so that
366  ``lsstDebug.Info("lsst.meas.algorithms.detection")`` evaluates `True`.
367 
368  If the ``convolvedImage`` is non-`None` and
369  ``lsstDebug.Info("lsst.meas.algorithms.detection") > 1``, the
370  ``convolvedImage`` will be displayed in frame 1.
371 
372  Parameters
373  ----------
374  exposure : `lsst.afw.image.Exposure`
375  Exposure to display, on which will be plotted the detections.
376  results : `lsst.pipe.base.Struct`
377  Results of the 'detectFootprints' method, containing positive and
378  negative footprints (which contain the peak positions that we will
379  plot). This is a `Struct` with ``positive`` and ``negative``
380  elements that are of type `lsst.afw.detection.FootprintSet`.
381  convolvedImage : `lsst.afw.image.Image`, optional
382  Convolved image used for thresholding.
383  """
384  try:
385  import lsstDebug
386  display = lsstDebug.Info(__name__).display
387  except ImportError:
388  try:
389  display
390  except NameError:
391  display = False
392  if not display:
393  return
394 
395  afwDisplay.setDefaultMaskTransparency(75)
396 
397  disp0 = afwDisplay.Display(frame=0)
398  disp0.mtv(exposure, title="detection")
399 
400  def plotPeaks(fps, ctype):
401  if fps is None:
402  return
403  with disp0.Buffering():
404  for fp in fps.getFootprints():
405  for pp in fp.getPeaks():
406  disp0.dot("+", pp.getFx(), pp.getFy(), ctype=ctype)
407  plotPeaks(results.positive, "yellow")
408  plotPeaks(results.negative, "red")
409 
410  if convolvedImage and display > 1:
411  disp1 = afwDisplay.Display(frame=1)
412  disp1.mtv(convolvedImage, title="PSF smoothed")
413 

◆ 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 619 of file detection.py.

619  def finalizeFootprints(self, mask, results, sigma, factor=1.0):
620  """Finalize the detected footprints
621 
622  Grows the footprints, sets the ``DETECTED`` and ``DETECTED_NEGATIVE``
623  mask planes, and logs the results.
624 
625  ``numPos`` (number of positive footprints), ``numPosPeaks`` (number
626  of positive peaks), ``numNeg`` (number of negative footprints),
627  ``numNegPeaks`` (number of negative peaks) entries are added to the
628  detection results.
629 
630  Parameters
631  ----------
632  mask : `lsst.afw.image.Mask`
633  Mask image on which to flag detected pixels.
634  results : `lsst.pipe.base.Struct`
635  Struct of detection results, including ``positive`` and
636  ``negative`` entries; modified.
637  sigma : `float`
638  Gaussian sigma of PSF.
639  factor : `float`
640  Multiplier for the configured threshold.
641  """
642  for polarity, maskName in (("positive", "DETECTED"), ("negative", "DETECTED_NEGATIVE")):
643  fpSet = getattr(results, polarity)
644  if fpSet is None:
645  continue
646  if self.config.nSigmaToGrow > 0:
647  nGrow = int((self.config.nSigmaToGrow * sigma) + 0.5)
648  self.metadata.set("nGrow", nGrow)
649  if self.config.combinedGrow:
650  fpSet = afwDet.FootprintSet(fpSet, nGrow, self.config.isotropicGrow)
651  else:
652  stencil = (afwGeom.Stencil.CIRCLE if self.config.isotropicGrow else
653  afwGeom.Stencil.MANHATTAN)
654  for fp in fpSet:
655  fp.dilate(nGrow, stencil)
656  fpSet.setMask(mask, maskName)
657  if not self.config.returnOriginalFootprints:
658  setattr(results, polarity, fpSet)
659 
660  results.numPos = 0
661  results.numPosPeaks = 0
662  results.numNeg = 0
663  results.numNegPeaks = 0
664  positive = ""
665  negative = ""
666 
667  if results.positive is not None:
668  results.numPos = len(results.positive.getFootprints())
669  results.numPosPeaks = sum(len(fp.getPeaks()) for fp in results.positive.getFootprints())
670  positive = " %d positive peaks in %d footprints" % (results.numPosPeaks, results.numPos)
671  if results.negative is not None:
672  results.numNeg = len(results.negative.getFootprints())
673  results.numNegPeaks = sum(len(fp.getPeaks()) for fp in results.negative.getFootprints())
674  negative = " %d negative peaks in %d footprints" % (results.numNegPeaks, results.numNeg)
675 
676  self.log.info("Detected%s%s%s to %g %s" %
677  (positive, " and" if positive and negative else "", negative,
678  self.config.thresholdValue*self.config.includeThresholdMultiplier*factor,
679  "DN" if self.config.thresholdType == "value" else "sigma"))
680 
daf::base::PropertySet * set
Definition: fits.cc:902
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53

◆ 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 482 of file detection.py.

482  def getPsf(self, exposure, sigma=None):
483  """Retrieve the PSF for an exposure
484 
485  If ``sigma`` is provided, we make a ``GaussianPsf`` with that,
486  otherwise use the one from the ``exposure``.
487 
488  Parameters
489  ----------
490  exposure : `lsst.afw.image.Exposure`
491  Exposure from which to retrieve the PSF.
492  sigma : `float`, optional
493  Gaussian sigma to use if provided.
494 
495  Returns
496  -------
497  psf : `lsst.afw.detection.Psf`
498  PSF to use for detection.
499  """
500  if sigma is None:
501  psf = exposure.getPsf()
502  if psf is None:
503  raise RuntimeError("Unable to determine PSF to use for detection: no sigma provided")
504  sigma = psf.computeShape().getDeterminantRadius()
505  size = self.calculateKernelSize(sigma)
506  psf = afwDet.GaussianPsf(size, size, sigma)
507  return psf
508 
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 797 of file detection.py.

797  def makeThreshold(self, image, thresholdParity, factor=1.0):
798  """Make an afw.detection.Threshold object corresponding to the task's
799  configuration and the statistics of the given image.
800 
801  Parameters
802  ----------
803  image : `afw.image.MaskedImage`
804  Image to measure noise statistics from if needed.
805  thresholdParity: `str`
806  One of "positive" or "negative", to set the kind of fluctuations
807  the Threshold will detect.
808  factor : `float`
809  Factor by which to multiply the configured detection threshold.
810  This is useful for tweaking the detection threshold slightly.
811 
812  Returns
813  -------
814  threshold : `lsst.afw.detection.Threshold`
815  Detection threshold.
816  """
817  parity = False if thresholdParity == "negative" else True
818  thresholdValue = self.config.thresholdValue
819  thresholdType = self.config.thresholdType
820  if self.config.thresholdType == 'stdev':
821  bad = image.getMask().getPlaneBitMask(self.config.statsMask)
822  sctrl = afwMath.StatisticsControl()
823  sctrl.setAndMask(bad)
824  stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl)
825  thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
826  thresholdType = 'value'
827 
828  threshold = afwDet.createThreshold(thresholdValue*factor, thresholdType, parity)
829  threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
830  return threshold
831 
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
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

◆ 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 681 of file detection.py.

681  def reEstimateBackground(self, maskedImage, backgrounds):
682  """Estimate the background after detection
683 
684  Parameters
685  ----------
686  maskedImage : `lsst.afw.image.MaskedImage`
687  Image on which to estimate the background.
688  backgrounds : `lsst.afw.math.BackgroundList`
689  List of backgrounds; modified.
690 
691  Returns
692  -------
693  bg : `lsst.afw.math.backgroundMI`
694  Empirical background model.
695  """
696  bg = self.background.fitBackground(maskedImage)
697  if self.config.adjustBackground:
698  self.log.warn("Fiddling the background by %g", self.config.adjustBackground)
699  bg += self.config.adjustBackground
700  self.log.info("Resubtracting the background after object detection")
701  maskedImage -= bg.getImageF()
702  backgrounds.append(bg)
703  return bg
704 

◆ 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 297 of file detection.py.

297  def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
298  """Run source detection and create a SourceCatalog of detections.
299 
300  Parameters
301  ----------
302  table : `lsst.afw.table.SourceTable`
303  Table object that will be used to create the SourceCatalog.
304  exposure : `lsst.afw.image.Exposure`
305  Exposure to process; DETECTED mask plane will be set in-place.
306  doSmooth : `bool`
307  If True, smooth the image before detection using a Gaussian of width
308  ``sigma``, or the measured PSF width. Set to False when running on
309  e.g. a pre-convolved image, or a mask plane.
310  sigma : `float`
311  Sigma of PSF (pixels); used for smoothing and to grow detections;
312  if None then measure the sigma of the PSF of the exposure
313  clearMask : `bool`
314  Clear DETECTED{,_NEGATIVE} planes before running detection.
315  expId : `int`
316  Exposure identifier; unused by this implementation, but used for
317  RNG seed by subclasses.
318 
319  Returns
320  -------
321  result : `lsst.pipe.base.Struct`
322  ``sources``
323  The detected sources (`lsst.afw.table.SourceCatalog`)
324  ``fpSets``
325  The result resturned by `detectFootprints`
326  (`lsst.pipe.base.Struct`).
327 
328  Raises
329  ------
330  ValueError
331  If flags.negative is needed, but isn't in table's schema.
332  lsst.pipe.base.TaskError
333  If sigma=None, doSmooth=True and the exposure has no PSF.
334 
335  Notes
336  -----
337  If you want to avoid dealing with Sources and Tables, you can use
338  detectFootprints() to just get the `lsst.afw.detection.FootprintSet`s.
339  """
340  if self.negativeFlagKey is not None and self.negativeFlagKey not in table.getSchema():
341  raise ValueError("Table has incorrect Schema")
342  results = self.detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
343  clearMask=clearMask, expId=expId)
344  sources = afwTable.SourceCatalog(table)
345  sources.reserve(results.numPos + results.numNeg)
346  if results.negative:
347  results.negative.makeSources(sources)
348  if self.negativeFlagKey:
349  for record in sources:
350  record.set(self.negativeFlagKey, True)
351  if results.positive:
352  results.positive.makeSources(sources)
353  results.fpSets = results.copy() # Backward compatibility
354  results.sources = sources
355  return results
356 
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)

◆ 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 875 of file detection.py.

875  def setEdgeBits(maskedImage, goodBBox, edgeBitmask):
876  """Set the edgeBitmask bits for all of maskedImage outside goodBBox
877 
878  Parameters
879  ----------
880  maskedImage : `lsst.afw.image.MaskedImage`
881  Image on which to set edge bits in the mask.
882  goodBBox : `lsst.geom.Box2I`
883  Bounding box of good pixels, in ``LOCAL`` coordinates.
884  edgeBitmask : `lsst.afw.image.MaskPixel`
885  Bit mask to OR with the existing mask bits in the region
886  outside ``goodBBox``.
887  """
888  msk = maskedImage.getMask()
889 
890  mx0, my0 = maskedImage.getXY0()
891  for x0, y0, w, h in ([0, 0,
892  msk.getWidth(), goodBBox.getBeginY() - my0],
893  [0, goodBBox.getEndY() - my0, msk.getWidth(),
894  maskedImage.getHeight() - (goodBBox.getEndY() - my0)],
895  [0, 0,
896  goodBBox.getBeginX() - mx0, msk.getHeight()],
897  [goodBBox.getEndX() - mx0, 0,
898  maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
899  ):
900  edgeMask = msk.Factory(msk, lsst.geom.BoxI(lsst.geom.PointI(x0, y0),
901  lsst.geom.ExtentI(w, h)), afwImage.LOCAL)
902  edgeMask |= edgeBitmask
903 
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 905 of file detection.py.

905  def tempWideBackgroundContext(self, exposure):
906  """Context manager for removing wide (large-scale) background
907 
908  Removing a wide (large-scale) background helps to suppress the
909  detection of large footprints that may overwhelm the deblender.
910  It does, however, set a limit on the maximum scale of objects.
911 
912  The background that we remove will be restored upon exit from
913  the context manager.
914 
915  Parameters
916  ----------
917  exposure : `lsst.afw.image.Exposure`
918  Exposure on which to remove large-scale background.
919 
920  Returns
921  -------
922  context : context manager
923  Context manager that will ensure the temporary wide background
924  is restored.
925  """
926  doTempWideBackground = self.config.doTempWideBackground
927  if doTempWideBackground:
928  self.log.info("Applying temporary wide background subtraction")
929  original = exposure.maskedImage.image.array[:].copy()
930  self.tempWideBackground.run(exposure).background
931  # Remove NO_DATA regions (e.g., edge of the field-of-view); these can cause detections after
932  # subtraction because of extrapolation of the background model into areas with no constraints.
933  image = exposure.maskedImage.image
934  mask = exposure.maskedImage.mask
935  noData = mask.array & mask.getPlaneBitMask("NO_DATA") > 0
936  isGood = mask.array & mask.getPlaneBitMask(self.config.statsMask) == 0
937  image.array[noData] = np.median(image.array[~noData & isGood])
938  try:
939  yield
940  finally:
941  if doTempWideBackground:
942  exposure.maskedImage.image.array[:] = original
943 
944 
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)

◆ 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
281 
A class to evaluate image background levels.
Definition: Background.h:443

◆ 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 832 of file detection.py.

832  def updatePeaks(self, fpSet, image, threshold):
833  """Update the Peaks in a FootprintSet by detecting new Footprints and
834  Peaks in an image and using the new Peaks instead of the old ones.
835 
836  Parameters
837  ----------
838  fpSet : `afw.detection.FootprintSet`
839  Set of Footprints whose Peaks should be updated.
840  image : `afw.image.MaskedImage`
841  Image to detect new Footprints and Peak in.
842  threshold : `afw.detection.Threshold`
843  Threshold object for detection.
844 
845  Input Footprints with fewer Peaks than self.config.nPeaksMaxSimple
846  are not modified, and if no new Peaks are detected in an input
847  Footprint, the brightest original Peak in that Footprint is kept.
848  """
849  for footprint in fpSet.getFootprints():
850  oldPeaks = footprint.getPeaks()
851  if len(oldPeaks) <= self.config.nPeaksMaxSimple:
852  continue
853  # We detect a new FootprintSet within each non-simple Footprint's
854  # bbox to avoid a big O(N^2) comparison between the two sets of
855  # Footprints.
856  sub = image.Factory(image, footprint.getBBox())
857  fpSetForPeaks = afwDet.FootprintSet(
858  sub,
859  threshold,
860  "", # don't set a mask plane
861  self.config.minPixels
862  )
863  newPeaks = afwDet.PeakCatalog(oldPeaks.getTable())
864  for fpForPeaks in fpSetForPeaks.getFootprints():
865  for peak in fpForPeaks.getPeaks():
866  if footprint.contains(peak.getI()):
867  newPeaks.append(peak)
868  if len(newPeaks) > 0:
869  del oldPeaks[:]
870  oldPeaks.extend(newPeaks)
871  else:
872  del oldPeaks[1:]
873 
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53

Member Data Documentation

◆ ConfigClass

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

Definition at line 46 of file dynamicDetection.py.

◆ makeSourceCatalog

def lsst.meas.algorithms.detection.SourceDetectionTask.makeSourceCatalog = run
staticinherited

An alias for run.

Deprecated:
Remove this alias after checking for where it's used

Definition at line 358 of file detection.py.

◆ negativeFlagKey

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

Definition at line 280 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: