24 __all__ = (
"SourceDetectionConfig",
"SourceDetectionTask",
"addExposures")
26 from contextlib
import contextmanager
39 from .subtractBackground
import SubtractBackgroundTask
43 """!Configuration parameters for the SourceDetectionTask 45 minPixels = pexConfig.RangeField(
46 doc=
"detected sources with fewer than the specified number of pixels will be ignored",
47 dtype=int, optional=
False, default=1, min=0,
49 isotropicGrow = pexConfig.Field(
50 doc=
"Pixels should be grown as isotropically as possible (slower)",
51 dtype=bool, optional=
False, default=
False,
53 combinedGrow = pexConfig.Field(
54 doc=
"Grow all footprints at the same time? This allows disconnected footprints to merge.",
55 dtype=bool, default=
True,
57 nSigmaToGrow = pexConfig.Field(
58 doc=
"Grow detections by nSigmaToGrow * [PSF RMS width]; if 0 then do not grow",
59 dtype=float, default=2.4,
61 returnOriginalFootprints = pexConfig.Field(
62 doc=
"Grow detections to set the image mask bits, but return the original (not-grown) footprints",
63 dtype=bool, optional=
False, default=
False,
65 thresholdValue = pexConfig.RangeField(
66 doc=
"Threshold for footprints",
67 dtype=float, optional=
False, default=5.0, min=0.0,
69 includeThresholdMultiplier = pexConfig.RangeField(
70 doc=
"Include threshold relative to thresholdValue",
71 dtype=float, default=1.0, min=0.0,
73 thresholdType = pexConfig.ChoiceField(
74 doc=
"specifies the desired flavor of Threshold",
75 dtype=str, optional=
False, default=
"stdev",
77 "variance":
"threshold applied to image variance",
78 "stdev":
"threshold applied to image std deviation",
79 "value":
"threshold applied to image value",
80 "pixel_stdev":
"threshold applied to per-pixel std deviation",
83 thresholdPolarity = pexConfig.ChoiceField(
84 doc=
"specifies whether to detect positive, or negative sources, or both",
85 dtype=str, optional=
False, default=
"positive",
87 "positive":
"detect only positive sources",
88 "negative":
"detect only negative sources",
89 "both":
"detect both positive and negative sources",
92 adjustBackground = pexConfig.Field(
94 doc=
"Fiddle factor to add to the background; debugging only",
97 reEstimateBackground = pexConfig.Field(
99 doc=
"Estimate the background again after final source detection?",
100 default=
True, optional=
False,
102 background = pexConfig.ConfigurableField(
103 doc=
"Background re-estimation; ignored if reEstimateBackground false",
104 target=SubtractBackgroundTask,
106 tempLocalBackground = pexConfig.ConfigurableField(
107 doc=(
"A local (small-scale), temporary background estimation step run between " 108 "detecting above-threshold regions and detecting the peaks within " 109 "them; used to avoid detecting spuerious peaks in the wings."),
110 target=SubtractBackgroundTask,
112 doTempLocalBackground = pexConfig.Field(
114 doc=
"Enable temporary local background subtraction? (see tempLocalBackground)",
117 tempWideBackground = pexConfig.ConfigurableField(
118 doc=(
"A wide (large-scale) background estimation and removal before footprint and peak detection. " 119 "It is added back into the image after detection. The purpose is to suppress very large " 120 "footprints (e.g., from large artifacts) that the deblender may choke on."),
121 target=SubtractBackgroundTask,
123 doTempWideBackground = pexConfig.Field(
125 doc=
"Do temporary wide (large-scale) background subtraction before footprint detection?",
128 nPeaksMaxSimple = pexConfig.Field(
130 doc=(
"The maximum number of peaks in a Footprint before trying to " 131 "replace its peaks using the temporary local background"),
134 nSigmaForKernel = pexConfig.Field(
136 doc=(
"Multiple of PSF RMS size to use for convolution kernel bounding box size; " 137 "note that this is not a half-size. The size will be rounded up to the nearest odd integer"),
140 statsMask = pexConfig.ListField(
142 doc=
"Mask planes to ignore when calculating statistics of image (for thresholdType=stdev)",
143 default=[
'BAD',
'SAT',
'EDGE',
'NO_DATA'],
156 for maskPlane
in (
"DETECTED",
"DETECTED_NEGATIVE"):
170 @anchor SourceDetectionTask_ 172 @brief Detect positive and negative sources on an exposure and return a new @link table.SourceCatalog@endlink. 174 @section meas_algorithms_detection_Contents Contents 176 - @ref meas_algorithms_detection_Purpose 177 - @ref meas_algorithms_detection_Initialize 178 - @ref meas_algorithms_detection_Invoke 179 - @ref meas_algorithms_detection_Config 180 - @ref meas_algorithms_detection_Debug 181 - @ref meas_algorithms_detection_Example 183 @section meas_algorithms_detection_Purpose Description 185 @copybrief SourceDetectionTask 187 @section meas_algorithms_detection_Initialize Task initialisation 189 @copydoc \_\_init\_\_ 191 @section meas_algorithms_detection_Invoke Invoking the Task 195 @section meas_algorithms_detection_Config Configuration parameters 197 See @ref SourceDetectionConfig 199 @section meas_algorithms_detection_Debug Debug variables 201 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 202 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about @b debug.py files. 204 The available variables in SourceDetectionTask are: 208 - If True, display the exposure on afwDisplay.Display's frame 0. 209 +ve detections in blue, -ve detections in cyan 210 - If display > 1, display the convolved exposure on frame 1 213 @section meas_algorithms_detection_Example A complete example of using SourceDetectionTask 215 This code is in @link measAlgTasks.py@endlink in the examples directory, and can be run as @em e.g. 217 examples/measAlgTasks.py --doDisplay 219 @dontinclude measAlgTasks.py 220 The example also runs the SingleFrameMeasurementTask; see @ref meas_algorithms_measurement_Example for more 223 Import the task (there are some other standard imports; read the file if you're confused) 224 @skipline SourceDetectionTask 226 We need to create our task before processing any data as the task constructor 227 can add an extra column to the schema, but first we need an almost-empty Schema 228 @skipline makeMinimalSchema 229 after which we can call the constructor: 230 @skip SourceDetectionTask.ConfigClass 233 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same 234 task objects). First create the output table: 237 And process the image 239 (You may not be happy that the threshold was set in the config before creating the Task rather than being set 240 separately for each exposure. You @em can reset it just before calling the run method if you must, but we 241 should really implement a better solution). 243 We can then unpack and use the results: 248 To investigate the @ref meas_algorithms_detection_Debug, put something like 252 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 253 if name == "lsst.meas.algorithms.detection": 258 lsstDebug.Info = DebugInfo 260 into your debug.py file and run measAlgTasks.py with the @c --debug flag. 262 ConfigClass = SourceDetectionConfig
263 _DefaultName =
"sourceDetection" 266 """!Create the detection task. Most arguments are simply passed onto pipe.base.Task. 268 @param schema An lsst::afw::table::Schema used to create the output lsst.afw.table.SourceCatalog 269 @param **kwds Keyword arguments passed to lsst.pipe.base.task.Task.__init__. 271 If schema is not None and configured for 'both' detections, 272 a 'flags.negative' field will be added to label detections made with a 275 @note This task can add fields to the schema, so any code calling this task must ensure that 276 these columns are indeed present in the input match list; see @ref Example 278 pipeBase.Task.__init__(self, **kwds)
279 if schema
is not None and self.config.thresholdPolarity ==
"both":
281 "flags_negative", type=
"Flag",
282 doc=
"set if source was detected as significantly negative" 285 if self.config.thresholdPolarity ==
"both":
286 self.log.
warn(
"Detection polarity set to 'both', but no flag will be " 287 "set to distinguish between positive and negative detections")
289 if self.config.reEstimateBackground:
290 self.makeSubtask(
"background")
291 if self.config.doTempLocalBackground:
292 self.makeSubtask(
"tempLocalBackground")
293 if self.config.doTempWideBackground:
294 self.makeSubtask(
"tempWideBackground")
297 def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
298 """!Run source detection and create a SourceCatalog. 300 @param table lsst.afw.table.SourceTable object that will be used to create the SourceCatalog. 301 @param exposure Exposure to process; DETECTED mask plane will be set in-place. 302 @param doSmooth if True, smooth the image before detection using a Gaussian of width sigma 304 @param sigma sigma of PSF (pixels); used for smoothing and to grow detections; 305 if None then measure the sigma of the PSF of the exposure (default: None) 306 @param clearMask Clear DETECTED{,_NEGATIVE} planes before running detection (default: True) 307 @param expId Exposure identifier (integer); unused by this implementation, but used for 308 RNG seed by subclasses. 310 @return a lsst.pipe.base.Struct with: 311 - sources -- an lsst.afw.table.SourceCatalog object 312 - fpSets --- lsst.pipe.base.Struct returned by @link detectFootprints @endlink 314 @throws ValueError if flags.negative is needed, but isn't in table's schema 315 @throws lsst.pipe.base.TaskError if sigma=None, doSmooth=True and the exposure has no PSF 318 If you want to avoid dealing with Sources and Tables, you can use detectFootprints() 319 to just get the afw::detection::FootprintSet%s. 322 raise ValueError(
"Table has incorrect Schema")
323 results = self.
detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
324 clearMask=clearMask, expId=expId)
326 sources.reserve(results.numPos + results.numNeg)
328 results.negative.makeSources(sources)
330 for record
in sources:
333 results.positive.makeSources(sources)
334 results.fpSets = results.copy()
335 results.sources = sources
339 makeSourceCatalog = run
341 def display(self, exposure, results, convolvedImage=None):
342 """Display detections if so configured 344 Displays the ``exposure`` in frame 0, overlays the detection peaks. 346 Requires that ``lsstDebug`` has been set up correctly, so that 347 ``lsstDebug.Info("lsst.meas.algorithms.detection")`` evaluates `True`. 349 If the ``convolvedImage`` is non-`None` and 350 ``lsstDebug.Info("lsst.meas.algorithms.detection") > 1``, the 351 ``convolvedImage`` will be displayed in frame 1. 355 exposure : `lsst.afw.image.Exposure` 356 Exposure to display, on which will be plotted the detections. 357 results : `lsst.pipe.base.Struct` 358 Results of the 'detectFootprints' method, containing positive and 359 negative footprints (which contain the peak positions that we will 360 plot). This is a `Struct` with ``positive`` and ``negative`` 361 elements that are of type `lsst.afw.detection.FootprintSet`. 362 convolvedImage : `lsst.afw.image.Image`, optional 363 Convolved image used for thresholding. 376 afwDisplay.setDefaultMaskTransparency(75)
378 disp0 = afwDisplay.Display(frame=0)
379 disp0.mtv(exposure, title=
"detection")
381 def plotPeaks(fps, ctype):
384 with disp0.Buffering():
385 for fp
in fps.getFootprints():
386 for pp
in fp.getPeaks():
387 disp0.dot(
"+", pp.getFx(), pp.getFy(), ctype=ctype)
388 plotPeaks(results.positive,
"yellow")
389 plotPeaks(results.negative,
"red")
391 if convolvedImage
and display > 1:
392 disp1 = afwDisplay.Display(frame=1)
393 disp1.mtv(convolvedImage, title=
"PSF smoothed")
396 """Apply a temporary local background subtraction 398 This temporary local background serves to suppress noise fluctuations 399 in the wings of bright objects. 401 Peaks in the footprints will be updated. 405 exposure : `lsst.afw.image.Exposure` 406 Exposure for which to fit local background. 407 middle : `lsst.afw.image.MaskedImage` 408 Convolved image on which detection will be performed 409 (typically smaller than ``exposure`` because the 410 half-kernel has been removed around the edges). 411 results : `lsst.pipe.base.Struct` 412 Results of the 'detectFootprints' method, containing positive and 413 negative footprints (which contain the peak positions that we will 414 plot). This is a `Struct` with ``positive`` and ``negative`` 415 elements that are of type `lsst.afw.detection.FootprintSet`. 420 bg = self.tempLocalBackground.fitBackground(exposure.getMaskedImage())
421 bgImage = bg.getImageF()
422 middle -= bgImage.Factory(bgImage, middle.getBBox())
425 if self.config.thresholdPolarity !=
"negative":
426 self.
updatePeaks(results.positive, middle, thresholdPos)
427 if self.config.thresholdPolarity !=
"positive":
428 self.
updatePeaks(results.negative, middle, thresholdNeg)
431 """Clear the DETECTED and DETECTED_NEGATIVE mask planes 433 Removes any previous detection mask in preparation for a new 438 mask : `lsst.afw.image.Mask` 441 mask &= ~(mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE"))
444 """Calculate size of smoothing kernel 446 Uses the ``nSigmaForKernel`` configuration parameter. Note 447 that that is the full width of the kernel bounding box 448 (so a value of 7 means 3.5 sigma on either side of center). 449 The value will be rounded up to the nearest odd integer. 454 Gaussian sigma of smoothing kernel. 459 Size of the smoothing kernel. 461 return (
int(sigma * self.config.nSigmaForKernel + 0.5)//2)*2 + 1
464 """Retrieve the PSF for an exposure 466 If ``sigma`` is provided, we make a ``GaussianPsf`` with that, 467 otherwise use the one from the ``exposure``. 471 exposure : `lsst.afw.image.Exposure` 472 Exposure from which to retrieve the PSF. 473 sigma : `float`, optional 474 Gaussian sigma to use if provided. 478 psf : `lsst.afw.detection.Psf` 479 PSF to use for detection. 482 psf = exposure.getPsf()
484 raise RuntimeError(
"Unable to determine PSF to use for detection: no sigma provided")
485 sigma = psf.computeShape().getDeterminantRadius()
491 """Convolve the image with the PSF 493 We convolve the image with a Gaussian approximation to the PSF, 494 because this is separable and therefore fast. It's technically a 495 correlation rather than a convolution, but since we use a symmetric 496 Gaussian there's no difference. 498 The convolution can be disabled with ``doSmooth=False``. If we do 499 convolve, we mask the edges as ``EDGE`` and return the convolved image 500 with the edges removed. This is because we can't convolve the edges 501 because the kernel would extend off the image. 505 maskedImage : `lsst.afw.image.MaskedImage` 507 psf : `lsst.afw.detection.Psf` 508 PSF to convolve with (actually with a Gaussian approximation 511 Actually do the convolution? 513 Return Struct contents 514 ---------------------- 515 middle : `lsst.afw.image.MaskedImage` 516 Convolved image, without the edges. 518 Gaussian sigma used for the convolution. 520 self.metadata.
set(
"doSmooth", doSmooth)
521 sigma = psf.computeShape().getDeterminantRadius()
522 self.metadata.
set(
"sigma", sigma)
525 middle = maskedImage.Factory(maskedImage)
526 return pipeBase.Struct(middle=middle, sigma=sigma)
531 self.metadata.
set(
"smoothingKernelWidth", kWidth)
532 gaussFunc = afwMath.GaussianFunction1D(sigma)
535 convolvedImage = maskedImage.Factory(maskedImage.getBBox())
541 goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
542 middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT,
False)
546 self.
setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask(
"EDGE"))
548 return pipeBase.Struct(middle=middle, sigma=sigma)
551 """Apply thresholds to the convolved image 553 Identifies ``Footprint``s, both positive and negative. 555 The threshold can be modified by the provided multiplication 560 middle : `lsst.afw.image.MaskedImage` 561 Convolved image to threshold. 562 bbox : `lsst.geom.Box2I` 563 Bounding box of unconvolved image. 565 Multiplier for the configured threshold. 567 Return Struct contents 568 ---------------------- 569 positive : `lsst.afw.detection.FootprintSet` or `None` 570 Positive detection footprints, if configured. 571 negative : `lsst.afw.detection.FootprintSet` or `None` 572 Negative detection footprints, if configured. 574 Multiplier for the configured threshold. 576 results = pipeBase.Struct(positive=
None, negative=
None, factor=factor)
578 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"negative":
579 threshold = self.
makeThreshold(middle,
"positive", factor=factor)
584 self.config.minPixels
586 results.positive.setRegion(bbox)
587 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"positive":
588 threshold = self.
makeThreshold(middle,
"negative", factor=factor)
593 self.config.minPixels
595 results.negative.setRegion(bbox)
600 """Finalize the detected footprints 602 Grows the footprints, sets the ``DETECTED`` and ``DETECTED_NEGATIVE`` 603 mask planes, and logs the results. 605 ``numPos`` (number of positive footprints), ``numPosPeaks`` (number 606 of positive peaks), ``numNeg`` (number of negative footprints), 607 ``numNegPeaks`` (number of negative peaks) entries are added to the 612 mask : `lsst.afw.image.Mask` 613 Mask image on which to flag detected pixels. 614 results : `lsst.pipe.base.Struct` 615 Struct of detection results, including ``positive`` and 616 ``negative`` entries; modified. 618 Gaussian sigma of PSF. 620 Multiplier for the configured threshold. 622 for polarity, maskName
in ((
"positive",
"DETECTED"), (
"negative",
"DETECTED_NEGATIVE")):
623 fpSet = getattr(results, polarity)
626 if self.config.nSigmaToGrow > 0:
627 nGrow =
int((self.config.nSigmaToGrow * sigma) + 0.5)
628 self.metadata.
set(
"nGrow", nGrow)
629 if self.config.combinedGrow:
632 stencil = (afwGeom.Stencil.CIRCLE
if self.config.isotropicGrow
else 633 afwGeom.Stencil.MANHATTAN)
635 fp.dilate(nGrow, stencil)
636 fpSet.setMask(mask, maskName)
637 if not self.config.returnOriginalFootprints:
638 setattr(results, polarity, fpSet)
641 results.numPosPeaks = 0
643 results.numNegPeaks = 0
647 if results.positive
is not None:
648 results.numPos = len(results.positive.getFootprints())
649 results.numPosPeaks = sum(len(fp.getPeaks())
for fp
in results.positive.getFootprints())
650 positive =
" %d positive peaks in %d footprints" % (results.numPosPeaks, results.numPos)
651 if results.negative
is not None:
652 results.numNeg = len(results.negative.getFootprints())
653 results.numNegPeaks = sum(len(fp.getPeaks())
for fp
in results.negative.getFootprints())
654 negative =
" %d negative peaks in %d footprints" % (results.numNegPeaks, results.numNeg)
656 self.log.
info(
"Detected%s%s%s to %g %s" %
657 (positive,
" and" if positive
and negative
else "", negative,
658 self.config.thresholdValue*self.config.includeThresholdMultiplier*factor,
659 "DN" if self.config.thresholdType ==
"value" else "sigma"))
662 """Estimate the background after detection 666 maskedImage : `lsst.afw.image.MaskedImage` 667 Image on which to estimate the background. 668 backgrounds : `lsst.afw.math.BackgroundList` 669 List of backgrounds; modified. 673 bg : `lsst.afw.math.backgroundMI` 674 Empirical background model. 676 bg = self.background.fitBackground(maskedImage)
677 if self.config.adjustBackground:
678 self.log.
warn(
"Fiddling the background by %g", self.config.adjustBackground)
679 bg += self.config.adjustBackground
680 self.log.
info(
"Resubtracting the background after object detection")
681 maskedImage -= bg.getImageF()
682 backgrounds.append(bg)
686 """Clear unwanted results from the Struct of results 688 If we specifically want only positive or only negative detections, 689 drop the ones we don't want, and its associated mask plane. 693 mask : `lsst.afw.image.Mask` 695 results : `lsst.pipe.base.Struct` 696 Detection results, with ``positive`` and ``negative`` elements; 699 if self.config.thresholdPolarity ==
"positive":
700 if self.config.reEstimateBackground:
701 mask &= ~mask.getPlaneBitMask(
"DETECTED_NEGATIVE")
702 results.negative =
None 703 elif self.config.thresholdPolarity ==
"negative":
704 if self.config.reEstimateBackground:
705 mask &= ~mask.getPlaneBitMask(
"DETECTED")
706 results.positive =
None 709 def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
710 """Detect footprints. 714 exposure : `lsst.afw.image.Exposure` 715 Exposure to process; DETECTED{,_NEGATIVE} mask plane will be 717 doSmooth : `bool`, optional 718 If True, smooth the image before detection using a Gaussian 720 sigma : `float`, optional 721 Gaussian Sigma of PSF (pixels); used for smoothing and to grow 722 detections; if `None` then measure the sigma of the PSF of the 724 clearMask : `bool`, optional 725 Clear both DETECTED and DETECTED_NEGATIVE planes before running 727 expId : `dict`, optional 728 Exposure identifier; unused by this implementation, but used for 729 RNG seed by subclasses. 731 Return Struct contents 732 ---------------------- 733 positive : `lsst.afw.detection.FootprintSet` 734 Positive polarity footprints (may be `None`) 735 negative : `lsst.afw.detection.FootprintSet` 736 Negative polarity footprints (may be `None`) 738 Number of footprints in positive or 0 if detection polarity was 741 Number of footprints in negative or 0 if detection polarity was 743 background : `lsst.afw.math.BackgroundList` 744 Re-estimated background. `None` if 745 ``reEstimateBackground==False``. 747 Multiplication factor applied to the configured detection 750 maskedImage = exposure.maskedImage
755 psf = self.
getPsf(exposure, sigma=sigma)
757 convolveResults = self.
convolveImage(maskedImage, psf, doSmooth=doSmooth)
758 middle = convolveResults.middle
759 sigma = convolveResults.sigma
763 if self.config.doTempLocalBackground:
767 if self.config.reEstimateBackground:
771 self.
display(exposure, results, middle)
776 """Make an afw.detection.Threshold object corresponding to the task's 777 configuration and the statistics of the given image. 781 image : `afw.image.MaskedImage` 782 Image to measure noise statistics from if needed. 783 thresholdParity: `str` 784 One of "positive" or "negative", to set the kind of fluctuations 785 the Threshold will detect. 787 Factor by which to multiply the configured detection threshold. 788 This is useful for tweaking the detection threshold slightly. 792 threshold : `lsst.afw.detection.Threshold` 795 parity =
False if thresholdParity ==
"negative" else True 796 thresholdValue = self.config.thresholdValue
797 thresholdType = self.config.thresholdType
798 if self.config.thresholdType ==
'stdev':
799 bad = image.getMask().getPlaneBitMask(self.config.statsMask)
801 sctrl.setAndMask(bad)
803 thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
804 thresholdType =
'value' 807 threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
811 """Update the Peaks in a FootprintSet by detecting new Footprints and 812 Peaks in an image and using the new Peaks instead of the old ones. 816 fpSet : `afw.detection.FootprintSet` 817 Set of Footprints whose Peaks should be updated. 818 image : `afw.image.MaskedImage` 819 Image to detect new Footprints and Peak in. 820 threshold : `afw.detection.Threshold` 821 Threshold object for detection. 823 Input Footprints with fewer Peaks than self.config.nPeaksMaxSimple 824 are not modified, and if no new Peaks are detected in an input 825 Footprint, the brightest original Peak in that Footprint is kept. 827 for footprint
in fpSet.getFootprints():
828 oldPeaks = footprint.getPeaks()
829 if len(oldPeaks) <= self.config.nPeaksMaxSimple:
834 sub = image.Factory(image, footprint.getBBox())
839 self.config.minPixels
842 for fpForPeaks
in fpSetForPeaks.getFootprints():
843 for peak
in fpForPeaks.getPeaks():
844 if footprint.contains(peak.getI()):
845 newPeaks.append(peak)
846 if len(newPeaks) > 0:
848 oldPeaks.extend(newPeaks)
854 """Set the edgeBitmask bits for all of maskedImage outside goodBBox 858 maskedImage : `lsst.afw.image.MaskedImage` 859 Image on which to set edge bits in the mask. 860 goodBBox : `lsst.geom.Box2I` 861 Bounding box of good pixels, in ``LOCAL`` coordinates. 862 edgeBitmask : `lsst.afw.image.MaskPixel` 863 Bit mask to OR with the existing mask bits in the region 864 outside ``goodBBox``. 866 msk = maskedImage.getMask()
868 mx0, my0 = maskedImage.getXY0()
869 for x0, y0, w, h
in ([0, 0,
870 msk.getWidth(), goodBBox.getBeginY() - my0],
871 [0, goodBBox.getEndY() - my0, msk.getWidth(),
872 maskedImage.getHeight() - (goodBBox.getEndY() - my0)],
874 goodBBox.getBeginX() - mx0, msk.getHeight()],
875 [goodBBox.getEndX() - mx0, 0,
876 maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
880 edgeMask |= edgeBitmask
884 """Context manager for removing wide (large-scale) background 886 Removing a wide (large-scale) background helps to suppress the 887 detection of large footprints that may overwhelm the deblender. 888 It does, however, set a limit on the maximum scale of objects. 890 The background that we remove will be restored upon exit from 895 exposure : `lsst.afw.image.Exposure` 896 Exposure on which to remove large-scale background. 900 context : context manager 901 Context manager that will ensure the temporary wide background 904 doTempWideBackground = self.config.doTempWideBackground
905 if doTempWideBackground:
906 self.log.
info(
"Applying temporary wide background subtraction")
907 original = exposure.maskedImage.image.array[:].copy()
908 self.tempWideBackground.
run(exposure).background
911 image = exposure.maskedImage.image
912 mask = exposure.maskedImage.mask
913 noData = mask.array & mask.getPlaneBitMask(
"NO_DATA") > 0
914 isGood = mask.array & mask.getPlaneBitMask(self.config.statsMask) == 0
915 image.array[noData] = np.median(image.array[~noData & isGood])
919 if doTempWideBackground:
920 exposure.maskedImage.image.array[:] = original
924 """Add a set of exposures together. 928 exposureList : `list` of `lsst.afw.image.Exposure` 929 Sequence of exposures to add. 933 addedExposure : `lsst.afw.image.Exposure` 934 An exposure of the same size as each exposure in ``exposureList``, 935 with the metadata from ``exposureList[0]`` and a masked image equal 936 to the sum of all the exposure's masked images. 938 exposure0 = exposureList[0]
939 image0 = exposure0.getMaskedImage()
941 addedImage = image0.Factory(image0,
True)
942 addedImage.setXY0(image0.getXY0())
944 for exposure
in exposureList[1:]:
945 image = exposure.getMaskedImage()
948 addedExposure = exposure0.Factory(addedImage, exposure0.getWcs())
def updatePeaks(self, fpSet, image, threshold)
def applyThreshold(self, middle, bbox, factor=1.0)
def addExposures(exposureList)
Parameters to control convolution.
def tempWideBackgroundContext(self, exposure)
def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None)
def convolveImage(self, maskedImage, psf, doSmooth=True)
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
def applyTempLocalBackground(self, exposure, middle, results)
def calculateKernelSize(self, sigma)
daf::base::PropertySet * set
def display(self, exposure, results, convolvedImage=None)
Detect positive and negative sources on an exposure and return a new table.SourceCatalog.
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<>
def makeThreshold(self, image, thresholdParity, factor=1.0)
Pass parameters to a Statistics object.
Configuration parameters for the SourceDetectionTask.
def clearUnwantedResults(self, mask, results)
def getPsf(self, exposure, sigma=None)
Threshold createThreshold(const double value, const std::string type="value", const bool polarity=true)
Factory method for creating Threshold objects.
def finalizeFootprints(self, mask, results, sigma, factor=1.0)
def __init__(self, schema=None, kwds)
Create the detection task.
def reEstimateBackground(self, maskedImage, backgrounds)
def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None)
Run source detection and create a SourceCatalog.
def clearMask(self, mask)
def setEdgeBits(maskedImage, goodBBox, edgeBitmask)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)
Old, deprecated version of convolve.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
An integer coordinate rectangle.
A circularly symmetric Gaussian Psf class with no spatial variation, intended mostly for testing purp...