LSST Applications g0265f82a02+0e5473021a,g02d81e74bb+0dd8ce4237,g1470d8bcf6+3ea6592b6f,g2079a07aa2+86d27d4dc4,g2305ad1205+5ca4c0b359,g295015adf3+d10818ec9d,g2a9a014e59+6f9be1b9cd,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g3ddfee87b4+703ba97ebf,g487adcacf7+4fa16da234,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+ffa42b374e,g5a732f18d5+53520f316c,g64a986408d+0dd8ce4237,g858d7b2824+0dd8ce4237,g8a8a8dda67+585e252eca,g99cad8db69+d39438377f,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+f1d96605c8,gb0e22166c9+60f28cb32d,gb6a65358fc+0e5473021a,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e5339d463f,gc120e1dc64+da31e9920e,gc28159a63d+0e5473021a,gcf0d15dbbd+703ba97ebf,gdaeeff99f8+f9a426f77a,ge6526c86ff+889fc9d533,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gf18bd8381d+7268b93478,gff1a9f87cc+0dd8ce4237,w.2024.16
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected 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

 __init__ (self, *args, **kwargs)
 
 calculateThreshold (self, exposure, seed, sigma=None, minFractionSourcesFactor=1.0, isBgTweak=False)
 
 detectFootprints (self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None, background=None)
 
 tweakBackground (self, exposure, bgLevel, bgList=None)
 

Public Attributes

 skySchema
 
 skyMeasurement
 

Static Public Attributes

 ConfigClass = DynamicDetectionConfig
 

Protected Member Functions

 _computeBrightDetectionMask (self, maskedImage, convolveResults)
 

Static Protected Attributes

str _DefaultName = "dynamicDetection"
 

Detailed Description

Detection of sources on an image with a dynamic threshold

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

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

Definition at line 72 of file dynamicDetection.py.

Constructor & Destructor Documentation

◆ __init__()

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

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

Definition at line 90 of file dynamicDetection.py.

90 def __init__(self, *args, **kwargs):
91
92 SourceDetectionTask.__init__(self, *args, **kwargs)
93 self.makeSubtask("skyObjects")
94
95 # Set up forced measurement.
96 config = ForcedMeasurementTask.ConfigClass()
97 config.plugins.names = ['base_TransformedCentroid', 'base_PsfFlux', 'base_LocalBackground']
98 # We'll need the "centroid" and "psfFlux" slots
99 for slot in ("shape", "psfShape", "apFlux", "modelFlux", "gaussianFlux", "calibFlux"):
100 setattr(config.slots, slot, None)
101 config.copyColumns = {}
102 self.skySchema = SourceTable.makeMinimalSchema()
103 self.skyMeasurement = ForcedMeasurementTask(config=config, name="skyMeasurement", parentTask=self,
104 refSchema=self.skySchema)
105

Member Function Documentation

◆ _computeBrightDetectionMask()

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask._computeBrightDetectionMask ( self,
maskedImage,
convolveResults )
protected
Perform an initial bright source detection pass.

Perform an initial bright object detection pass using a high detection
threshold. The footprints in this pass are grown significantly more
than is typical to account for wings around bright sources.  The
negative polarity detections in this pass help in masking severely
over-subtracted regions.

A maximum fraction of masked pixel from this pass is ensured via
the config ``brightMaskFractionMax``.  If the masked pixel fraction is
above this value, the detection thresholds here are increased by
``bisectFactor`` in a while loop until the detected masked fraction
falls below this value.

Parameters
----------
maskedImage : `lsst.afw.image.MaskedImage`
    Masked image on which to run the detection.
convolveResults :  `lsst.pipe.base.Struct`
    The results of the self.convolveImage function with attributes:

    ``middle``
        Convolved image, without the edges
       (`lsst.afw.image.MaskedImage`).
    ``sigma``
        Gaussian sigma used for the convolution (`float`).

Returns
-------
brightDetectedMask : `numpy.ndarray`
    Boolean array representing the union of the bright detection pass
    DETECTED and DETECTED_NEGATIVE masks.

Definition at line 411 of file dynamicDetection.py.

411 def _computeBrightDetectionMask(self, maskedImage, convolveResults):
412 """Perform an initial bright source detection pass.
413
414 Perform an initial bright object detection pass using a high detection
415 threshold. The footprints in this pass are grown significantly more
416 than is typical to account for wings around bright sources. The
417 negative polarity detections in this pass help in masking severely
418 over-subtracted regions.
419
420 A maximum fraction of masked pixel from this pass is ensured via
421 the config ``brightMaskFractionMax``. If the masked pixel fraction is
422 above this value, the detection thresholds here are increased by
423 ``bisectFactor`` in a while loop until the detected masked fraction
424 falls below this value.
425
426 Parameters
427 ----------
428 maskedImage : `lsst.afw.image.MaskedImage`
429 Masked image on which to run the detection.
430 convolveResults : `lsst.pipe.base.Struct`
431 The results of the self.convolveImage function with attributes:
432
433 ``middle``
434 Convolved image, without the edges
435 (`lsst.afw.image.MaskedImage`).
436 ``sigma``
437 Gaussian sigma used for the convolution (`float`).
438
439 Returns
440 -------
441 brightDetectedMask : `numpy.ndarray`
442 Boolean array representing the union of the bright detection pass
443 DETECTED and DETECTED_NEGATIVE masks.
444 """
445 # Initialize some parameters.
446 brightPosFactor = (
447 self.config.prelimThresholdFactor*self.config.brightMultiplier/self.config.bisectFactor
448 )
449 brightNegFactor = self.config.brightNegFactor/self.config.bisectFactor
450 nPix = 1
451 nPixDet = 1
452 nPixDetNeg = 1
453 brightMaskFractionMax = self.config.brightMaskFractionMax
454
455 # Loop until masked fraction is smaller than
456 # brightMaskFractionMax, increasing the thresholds by
457 # config.bisectFactor on each iteration (rarely necessary
458 # for current defaults).
459 while nPixDetNeg/nPix > brightMaskFractionMax or nPixDet/nPix > brightMaskFractionMax:
460 self.clearMask(maskedImage.mask)
461 brightPosFactor *= self.config.bisectFactor
462 brightNegFactor *= self.config.bisectFactor
463 prelimBright = self.applyThreshold(convolveResults.middle, maskedImage.getBBox(),
464 factor=brightPosFactor, factorNeg=brightNegFactor)
465 self.finalizeFootprints(
466 maskedImage.mask, prelimBright, convolveResults.sigma*self.config.brightGrowFactor,
467 factor=brightPosFactor, factorNeg=brightNegFactor
468 )
469 # Check that not too many pixels got masked.
470 nPix = maskedImage.mask.array.size
471 nPixDet = countMaskedPixels(maskedImage, "DETECTED")
472 self.log.info("Number (%) of bright DETECTED pix: {} ({:.1f}%)".
473 format(nPixDet, 100*nPixDet/nPix))
474 nPixDetNeg = countMaskedPixels(maskedImage, "DETECTED_NEGATIVE")
475 self.log.info("Number (%) of bright DETECTED_NEGATIVE pix: {} ({:.1f}%)".
476 format(nPixDetNeg, 100*nPixDetNeg/nPix))
477 if nPixDetNeg/nPix > brightMaskFractionMax or nPixDet/nPix > brightMaskFractionMax:
478 self.log.warn("Too high a fraction (%.1f > %.1f) of pixels were masked with current "
479 "\"bright\" detection round thresholds. Increasing by a factor of %f "
480 "and trying again.", max(nPixDetNeg, nPixDet)/nPix,
481 brightMaskFractionMax, self.config.bisectFactor)
482
483 # Save the mask planes from the "bright" detection round, then
484 # clear them before moving on to the "prelim" detection phase.
485 brightDetectedMask = (maskedImage.mask.array
486 & maskedImage.mask.getPlaneBitMask(["DETECTED", "DETECTED_NEGATIVE"]))
487 self.clearMask(maskedImage.mask)
488 return brightDetectedMask
489
490
int max

◆ calculateThreshold()

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.calculateThreshold ( self,
exposure,
seed,
sigma = None,
minFractionSourcesFactor = 1.0,
isBgTweak = False )
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.
minFractionSourcesFactor : `float`
    Change the fraction of required sky sources from that set in
    ``self.config.minFractionSources`` by this factor.  NOTE: this
    is intended for use in the background tweak pass (the detection
    threshold is much lower there, so many more pixels end up marked
    as DETECTED or DETECTED_NEGATIVE, leaving less room for sky
    object placement).
isBgTweak : `bool`
   Set to ``True`` for the background tweak pass (for more helpful
   log messages).

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`).

Raises
------
NoWorkFound
    Raised if the number of good sky sources found is less than the
    minimum fraction
    (``self.config.minFractionSources``*``minFractionSourcesFactor``)
    of the number requested (``self.skyObjects.config.nSources``).

Definition at line 106 of file dynamicDetection.py.

106 def calculateThreshold(self, exposure, seed, sigma=None, minFractionSourcesFactor=1.0, isBgTweak=False):
107 """Calculate new threshold
108
109 This is the main functional addition to the vanilla
110 `SourceDetectionTask`.
111
112 We identify sky objects and perform forced PSF photometry on
113 them. Using those PSF flux measurements and estimated errors,
114 we set the threshold so that the stdev of the measurements
115 matches the median estimated error.
116
117 Parameters
118 ----------
119 exposure : `lsst.afw.image.Exposure`
120 Exposure on which we're detecting sources.
121 seed : `int`
122 RNG seed to use for finding sky objects.
123 sigma : `float`, optional
124 Gaussian sigma of smoothing kernel; if not provided,
125 will be deduced from the exposure's PSF.
126 minFractionSourcesFactor : `float`
127 Change the fraction of required sky sources from that set in
128 ``self.config.minFractionSources`` by this factor. NOTE: this
129 is intended for use in the background tweak pass (the detection
130 threshold is much lower there, so many more pixels end up marked
131 as DETECTED or DETECTED_NEGATIVE, leaving less room for sky
132 object placement).
133 isBgTweak : `bool`
134 Set to ``True`` for the background tweak pass (for more helpful
135 log messages).
136
137 Returns
138 -------
139 result : `lsst.pipe.base.Struct`
140 Result struct with components:
141
142 ``multiplicative``
143 Multiplicative factor to be applied to the
144 configured detection threshold (`float`).
145 ``additive``
146 Additive factor to be applied to the background
147 level (`float`).
148
149 Raises
150 ------
151 NoWorkFound
152 Raised if the number of good sky sources found is less than the
153 minimum fraction
154 (``self.config.minFractionSources``*``minFractionSourcesFactor``)
155 of the number requested (``self.skyObjects.config.nSources``).
156 """
157 wcsIsNone = exposure.getWcs() is None
158 if wcsIsNone: # create a dummy WCS as needed by ForcedMeasurementTask
159 self.log.info("WCS for exposure is None. Setting a dummy WCS for dynamic detection.")
160 exposure.setWcs(makeSkyWcs(crpix=geom.Point2D(0, 0),
161 crval=geom.SpherePoint(0, 0, geom.degrees),
162 cdMatrix=makeCdMatrix(scale=1e-5*geom.degrees)))
163 fp = self.skyObjects.run(exposure.maskedImage.mask, seed)
164 skyFootprints = FootprintSet(exposure.getBBox())
165 skyFootprints.setFootprints(fp)
166 table = SourceTable.make(self.skyMeasurement.schema)
167 catalog = SourceCatalog(table)
168 catalog.reserve(len(skyFootprints.getFootprints()))
169 skyFootprints.makeSources(catalog)
170 key = catalog.getCentroidSlot().getMeasKey()
171 for source in catalog:
172 peaks = source.getFootprint().getPeaks()
173 assert len(peaks) == 1
174 source.set(key, peaks[0].getF())
175 # Coordinate covariance is not used, so don't bother calulating it.
176 source.updateCoord(exposure.getWcs(), include_covariance=False)
177
178 # Forced photometry on sky objects
179 self.skyMeasurement.run(catalog, exposure, catalog, exposure.getWcs())
180
181 # Calculate new threshold
182 fluxes = catalog["base_PsfFlux_instFlux"]
183 area = catalog["base_PsfFlux_area"]
184 bg = catalog["base_LocalBackground_instFlux"]
185
186 good = (~catalog["base_PsfFlux_flag"] & ~catalog["base_LocalBackground_flag"]
187 & np.isfinite(fluxes) & np.isfinite(area) & np.isfinite(bg))
188
189 minNumSources = int(self.config.minFractionSources*self.skyObjects.config.nSources)
190 # Reduce the number of sky sources required if requested, but ensure
191 # a minumum of 3.
192 if minFractionSourcesFactor != 1.0:
193 minNumSources = max(3, int(minNumSources*minFractionSourcesFactor))
194 if good.sum() < minNumSources:
195 if not isBgTweak:
196 msg = (f"Insufficient good sky source flux measurements ({good.sum()} < "
197 f"{minNumSources}) for dynamic threshold calculation.")
198 else:
199 msg = (f"Insufficient good sky source flux measurements ({good.sum()} < "
200 f"{minNumSources}) for background tweak calculation.")
201
202 nPix = exposure.mask.array.size
203 badPixelMask = lsst.afw.image.Mask.getPlaneBitMask(["NO_DATA", "BAD"])
204 nGoodPix = np.sum(exposure.mask.array & badPixelMask == 0)
205 if nGoodPix/nPix > 0.2:
206 detectedPixelMask = lsst.afw.image.Mask.getPlaneBitMask(["DETECTED", "DETECTED_NEGATIVE"])
207 nDetectedPix = np.sum(exposure.mask.array & detectedPixelMask != 0)
208 msg += (f" However, {nGoodPix}/{nPix} pixels are not marked NO_DATA or BAD, "
209 "so there should be sufficient area to locate suitable sky sources. "
210 f"Note that {nDetectedPix} of {nGoodPix} \"good\" pixels were marked "
211 "as DETECTED or DETECTED_NEGATIVE.")
212 raise RuntimeError(msg)
213 raise NoWorkFound(msg)
214
215 if not isBgTweak:
216 self.log.info("Number of good sky sources used for dynamic detection: %d (of %d requested).",
217 good.sum(), self.skyObjects.config.nSources)
218 else:
219 self.log.info("Number of good sky sources used for dynamic detection background tweak:"
220 " %d (of %d requested).", good.sum(), self.skyObjects.config.nSources)
221 bgMedian = np.median((fluxes/area)[good])
222
223 lq, uq = np.percentile((fluxes - bg*area)[good], [25.0, 75.0])
224 stdevMeas = 0.741*(uq - lq)
225 medianError = np.median(catalog["base_PsfFlux_instFluxErr"][good])
226 if wcsIsNone:
227 exposure.setWcs(None)
228 return Struct(multiplicative=medianError/stdevMeas, additive=bgMedian)
229
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR'd together.
Definition Mask.cc:376
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57

◆ detectFootprints()

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

This varies from the vanilla ``detectFootprints`` method because we
do detection three times: first with a high threshold to detect
"bright" (both positive and negative, the latter to identify very
over-subtracted regions) sources for which we grow the DETECTED and
DETECTED_NEGATIVE masks significantly to account for wings.  Second,
with a low threshold to mask all non-empty regions of the image. These
two masks are combined and used to identify regions of sky
uncontaminated by objects.  A final round of detection is then done
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.
background : `lsst.afw.math.BackgroundList`, optional
    Background that was already subtracted from the exposure; will be
    modified in-place if ``reEstimateBackground=True``.

Returns
-------
resutls : `lsst.pipe.base.Struct`
    The results `~lsst.pipe.base.Struct` contains:

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

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

Definition at line 230 of file dynamicDetection.py.

231 background=None):
232 """Detect footprints with a dynamic threshold
233
234 This varies from the vanilla ``detectFootprints`` method because we
235 do detection three times: first with a high threshold to detect
236 "bright" (both positive and negative, the latter to identify very
237 over-subtracted regions) sources for which we grow the DETECTED and
238 DETECTED_NEGATIVE masks significantly to account for wings. Second,
239 with a low threshold to mask all non-empty regions of the image. These
240 two masks are combined and used to identify regions of sky
241 uncontaminated by objects. A final round of detection is then done
242 with the new calculated threshold.
243
244 Parameters
245 ----------
246 exposure : `lsst.afw.image.Exposure`
247 Exposure to process; DETECTED{,_NEGATIVE} mask plane will be
248 set in-place.
249 doSmooth : `bool`, optional
250 If True, smooth the image before detection using a Gaussian
251 of width ``sigma``.
252 sigma : `float`, optional
253 Gaussian Sigma of PSF (pixels); used for smoothing and to grow
254 detections; if `None` then measure the sigma of the PSF of the
255 ``exposure``.
256 clearMask : `bool`, optional
257 Clear both DETECTED and DETECTED_NEGATIVE planes before running
258 detection.
259 expId : `int`, optional
260 Exposure identifier, used as a seed for the random number
261 generator. If absent, the seed will be the sum of the image.
262 background : `lsst.afw.math.BackgroundList`, optional
263 Background that was already subtracted from the exposure; will be
264 modified in-place if ``reEstimateBackground=True``.
265
266 Returns
267 -------
268 resutls : `lsst.pipe.base.Struct`
269 The results `~lsst.pipe.base.Struct` contains:
270
271 ``positive``
272 Positive polarity footprints.
273 (`lsst.afw.detection.FootprintSet` or `None`)
274 ``negative``
275 Negative polarity footprints.
276 (`lsst.afw.detection.FootprintSet` or `None`)
277 ``numPos``
278 Number of footprints in positive or 0 if detection polarity was
279 negative. (`int`)
280 ``numNeg``
281 Number of footprints in negative or 0 if detection polarity was
282 positive. (`int`)
283 ``background``
284 Re-estimated background. `None` or the input ``background``
285 if ``reEstimateBackground==False``.
286 (`lsst.afw.math.BackgroundList`)
287 ``factor``
288 Multiplication factor applied to the configured detection
289 threshold. (`float`)
290 ``prelim``
291 Results from preliminary detection pass.
292 (`lsst.pipe.base.Struct`)
293 """
294 maskedImage = exposure.maskedImage
295
296 if clearMask:
297 self.clearMask(maskedImage.mask)
298 else:
299 oldDetected = maskedImage.mask.array & maskedImage.mask.getPlaneBitMask(["DETECTED",
300 "DETECTED_NEGATIVE"])
301 nPix = maskedImage.mask.array.size
302 badPixelMask = lsst.afw.image.Mask.getPlaneBitMask(["NO_DATA", "BAD"])
303 nGoodPix = np.sum(maskedImage.mask.array & badPixelMask == 0)
304 self.log.info("Number of good data pixels (i.e. not NO_DATA or BAD): {} ({:.1f}% of total)".
305 format(nGoodPix, 100*nGoodPix/nPix))
306
307 with self.tempWideBackgroundContext(exposure):
308 # Could potentially smooth with a wider kernel than the PSF in
309 # order to better pick up the wings of stars and galaxies, but for
310 # now sticking with the PSF as that's more simple.
311 psf = self.getPsf(exposure, sigma=sigma)
312 convolveResults = self.convolveImage(maskedImage, psf, doSmooth=doSmooth)
313
314 if self.config.doBrightPrelimDetection:
315 brightDetectedMask = self._computeBrightDetectionMask(maskedImage, convolveResults)
316
317 middle = convolveResults.middle
318 sigma = convolveResults.sigma
319 prelim = self.applyThreshold(
320 middle, maskedImage.getBBox(), factor=self.config.prelimThresholdFactor,
321 factorNeg=self.config.prelimNegMultiplier*self.config.prelimThresholdFactor
322 )
323 self.finalizeFootprints(
324 maskedImage.mask, prelim, sigma, factor=self.config.prelimThresholdFactor,
325 factorNeg=self.config.prelimNegMultiplier*self.config.prelimThresholdFactor
326 )
327 if self.config.doBrightPrelimDetection:
328 # Combine prelim and bright detection masks for multiplier
329 # determination.
330 maskedImage.mask.array |= brightDetectedMask
331
332 # Calculate the proper threshold
333 # seed needs to fit in a C++ 'int' so pybind doesn't choke on it
334 seed = (expId if expId is not None else int(maskedImage.image.array.sum())) % (2**31 - 1)
335 threshResults = self.calculateThreshold(exposure, seed, sigma=sigma)
336 factor = threshResults.multiplicative
337 self.log.info("Modifying configured detection threshold by factor %f to %f",
338 factor, factor*self.config.thresholdValue)
339
340 # Blow away preliminary (low threshold) detection mask
341 self.clearMask(maskedImage.mask)
342 if not clearMask:
343 maskedImage.mask.array |= oldDetected
344
345 # Rinse and repeat thresholding with new calculated threshold
346 results = self.applyThreshold(middle, maskedImage.getBBox(), factor)
347 results.prelim = prelim
348 results.background = background if background is not None else lsst.afw.math.BackgroundList()
349 if self.config.doTempLocalBackground:
350 self.applyTempLocalBackground(exposure, middle, results)
351 self.finalizeFootprints(maskedImage.mask, results, sigma, factor=factor)
352
353 self.clearUnwantedResults(maskedImage.mask, results)
354
355 if self.config.reEstimateBackground:
356 self.reEstimateBackground(maskedImage, results.background)
357
358 self.display(exposure, results, middle)
359
360 if self.config.doBackgroundTweak:
361 # Re-do the background tweak after any temporary backgrounds have
362 # been restored.
363 #
364 # But we want to keep any large-scale background (e.g., scattered
365 # light from bright stars) from being selected for sky objects in
366 # the calculation, so do another detection pass without either the
367 # local or wide temporary background subtraction; the DETECTED
368 # pixels will mark the area to ignore.
369 originalMask = maskedImage.mask.array.copy()
370 try:
371 self.clearMask(exposure.mask)
372 convolveResults = self.convolveImage(maskedImage, psf, doSmooth=doSmooth)
373 tweakDetResults = self.applyThreshold(convolveResults.middle, maskedImage.getBBox(), factor)
374 self.finalizeFootprints(maskedImage.mask, tweakDetResults, sigma, factor=factor)
375 bgLevel = self.calculateThreshold(exposure, seed, sigma=sigma, minFractionSourcesFactor=0.5,
376 isBgTweak=True).additive
377 finally:
378 maskedImage.mask.array[:] = originalMask
379 self.tweakBackground(exposure, bgLevel, results.background)
380
381 return results
382

◆ tweakBackground()

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

383 def tweakBackground(self, exposure, bgLevel, bgList=None):
384 """Modify the background by a constant value
385
386 Parameters
387 ----------
388 exposure : `lsst.afw.image.Exposure`
389 Exposure for which to tweak background.
390 bgLevel : `float`
391 Background level to remove
392 bgList : `lsst.afw.math.BackgroundList`, optional
393 List of backgrounds to append to.
394
395 Returns
396 -------
397 bg : `lsst.afw.math.BackgroundMI`
398 Constant background model.
399 """
400 self.log.info("Tweaking background by %f to match sky photometry", bgLevel)
401 exposure.image -= bgLevel
402 bgStats = lsst.afw.image.MaskedImageF(1, 1)
403 bgStats.set(bgLevel, 0, bgLevel)
404 bg = lsst.afw.math.BackgroundMI(exposure.getBBox(), bgStats)
405 bgData = (bg, lsst.afw.math.Interpolate.LINEAR, lsst.afw.math.REDUCE_INTERP_ORDER,
406 lsst.afw.math.ApproximateControl.UNKNOWN, 0, 0, False)
407 if bgList is not None:
408 bgList.append(bgData)
409 return bg
410
A class to evaluate image background levels.
Definition Background.h:434

Member Data Documentation

◆ _DefaultName

str lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask._DefaultName = "dynamicDetection"
staticprotected

Definition at line 88 of file dynamicDetection.py.

◆ ConfigClass

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

Definition at line 87 of file dynamicDetection.py.

◆ skyMeasurement

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.skyMeasurement

Definition at line 103 of file dynamicDetection.py.

◆ skySchema

lsst.meas.algorithms.dynamicDetection.DynamicDetectionTask.skySchema

Definition at line 102 of file dynamicDetection.py.


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