24 __all__ = (
"SourceDetectionConfig",
"SourceDetectionTask",
"addExposures")
26 from contextlib
import contextmanager
37 import lsst.pex.config
as pexConfig
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; exact meaning and units depend on thresholdType.",
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 of detections. 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. 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. 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 314 Clear DETECTED{,_NEGATIVE} planes before running detection. 316 Exposure identifier; unused by this implementation, but used for 317 RNG seed by subclasses. 321 result : `lsst.pipe.base.Struct` 323 The detected sources (`lsst.afw.table.SourceCatalog`) 325 The result resturned by `detectFootprints` 326 (`lsst.pipe.base.Struct`). 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. 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. 341 raise ValueError(
"Table has incorrect Schema")
342 results = self.
detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
343 clearMask=clearMask, expId=expId)
345 sources.reserve(results.numPos + results.numNeg)
347 results.negative.makeSources(sources)
349 for record
in sources:
352 results.positive.makeSources(sources)
353 results.fpSets = results.copy()
354 results.sources = sources
358 makeSourceCatalog = run
360 def display(self, exposure, results, convolvedImage=None):
361 """Display detections if so configured 363 Displays the ``exposure`` in frame 0, overlays the detection peaks. 365 Requires that ``lsstDebug`` has been set up correctly, so that 366 ``lsstDebug.Info("lsst.meas.algorithms.detection")`` evaluates `True`. 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. 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. 395 afwDisplay.setDefaultMaskTransparency(75)
397 disp0 = afwDisplay.Display(frame=0)
398 disp0.mtv(exposure, title=
"detection")
400 def plotPeaks(fps, ctype):
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")
410 if convolvedImage
and display > 1:
411 disp1 = afwDisplay.Display(frame=1)
412 disp1.mtv(convolvedImage, title=
"PSF smoothed")
415 """Apply a temporary local background subtraction 417 This temporary local background serves to suppress noise fluctuations 418 in the wings of bright objects. 420 Peaks in the footprints will be updated. 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`. 439 bg = self.tempLocalBackground.fitBackground(exposure.getMaskedImage())
440 bgImage = bg.getImageF()
441 middle -= bgImage.Factory(bgImage, middle.getBBox())
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)
450 """Clear the DETECTED and DETECTED_NEGATIVE mask planes 452 Removes any previous detection mask in preparation for a new 457 mask : `lsst.afw.image.Mask` 460 mask &= ~(mask.getPlaneBitMask(
"DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE"))
463 """Calculate size of smoothing kernel 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. 473 Gaussian sigma of smoothing kernel. 478 Size of the smoothing kernel. 480 return (int(sigma * self.config.nSigmaForKernel + 0.5)//2)*2 + 1
483 """Retrieve the PSF for an exposure 485 If ``sigma`` is provided, we make a ``GaussianPsf`` with that, 486 otherwise use the one from the ``exposure``. 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. 497 psf : `lsst.afw.detection.Psf` 498 PSF to use for detection. 501 psf = exposure.getPsf()
503 raise RuntimeError(
"Unable to determine PSF to use for detection: no sigma provided")
504 sigma = psf.computeShape().getDeterminantRadius()
510 """Convolve the image with the PSF 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. 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. 524 maskedImage : `lsst.afw.image.MaskedImage` 526 psf : `lsst.afw.detection.Psf` 527 PSF to convolve with (actually with a Gaussian approximation 530 Actually do the convolution? Set to False when running on 531 e.g. a pre-convolved image, or a mask plane. 533 Return Struct contents 534 ---------------------- 535 middle : `lsst.afw.image.MaskedImage` 536 Convolved image, without the edges. 538 Gaussian sigma used for the convolution. 540 self.metadata.
set(
"doSmooth", doSmooth)
541 sigma = psf.computeShape().getDeterminantRadius()
542 self.metadata.
set(
"sigma", sigma)
545 middle = maskedImage.Factory(maskedImage)
546 return pipeBase.Struct(middle=middle, sigma=sigma)
551 self.metadata.
set(
"smoothingKernelWidth", kWidth)
552 gaussFunc = afwMath.GaussianFunction1D(sigma)
555 convolvedImage = maskedImage.Factory(maskedImage.getBBox())
561 goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
562 middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT,
False)
566 self.
setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask(
"EDGE"))
568 return pipeBase.Struct(middle=middle, sigma=sigma)
571 """Apply thresholds to the convolved image 573 Identifies ``Footprint``s, both positive and negative. 575 The threshold can be modified by the provided multiplication 580 middle : `lsst.afw.image.MaskedImage` 581 Convolved image to threshold. 582 bbox : `lsst.geom.Box2I` 583 Bounding box of unconvolved image. 585 Multiplier for the configured threshold. 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. 594 Multiplier for the configured threshold. 596 results = pipeBase.Struct(positive=
None, negative=
None, factor=factor)
598 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"negative":
599 threshold = self.
makeThreshold(middle,
"positive", factor=factor)
604 self.config.minPixels
606 results.positive.setRegion(bbox)
607 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"positive":
608 threshold = self.
makeThreshold(middle,
"negative", factor=factor)
613 self.config.minPixels
615 results.negative.setRegion(bbox)
620 """Finalize the detected footprints 622 Grows the footprints, sets the ``DETECTED`` and ``DETECTED_NEGATIVE`` 623 mask planes, and logs the results. 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 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. 638 Gaussian sigma of PSF. 640 Multiplier for the configured threshold. 642 for polarity, maskName
in ((
"positive",
"DETECTED"), (
"negative",
"DETECTED_NEGATIVE")):
643 fpSet = getattr(results, polarity)
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:
652 stencil = (afwGeom.Stencil.CIRCLE
if self.config.isotropicGrow
else 653 afwGeom.Stencil.MANHATTAN)
655 fp.dilate(nGrow, stencil)
656 fpSet.setMask(mask, maskName)
657 if not self.config.returnOriginalFootprints:
658 setattr(results, polarity, fpSet)
661 results.numPosPeaks = 0
663 results.numNegPeaks = 0
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)
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"))
682 """Estimate the background after detection 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. 693 bg : `lsst.afw.math.backgroundMI` 694 Empirical background model. 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)
706 """Clear unwanted results from the Struct of results 708 If we specifically want only positive or only negative detections, 709 drop the ones we don't want, and its associated mask plane. 713 mask : `lsst.afw.image.Mask` 715 results : `lsst.pipe.base.Struct` 716 Detection results, with ``positive`` and ``negative`` elements; 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 729 def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None):
730 """Detect footprints on an exposure. 734 exposure : `lsst.afw.image.Exposure` 735 Exposure to process; DETECTED{,_NEGATIVE} mask plane will be 737 doSmooth : `bool`, optional 738 If True, smooth the image before detection using a Gaussian 739 of width ``sigma``, or the measured PSF width of ``exposure``. 740 Set to False when running on e.g. a pre-convolved image, or a mask 742 sigma : `float`, optional 743 Gaussian Sigma of PSF (pixels); used for smoothing and to grow 744 detections; if `None` then measure the sigma of the PSF of the 746 clearMask : `bool`, optional 747 Clear both DETECTED and DETECTED_NEGATIVE planes before running 749 expId : `dict`, optional 750 Exposure identifier; unused by this implementation, but used for 751 RNG seed by subclasses. 753 Return Struct contents 754 ---------------------- 755 positive : `lsst.afw.detection.FootprintSet` 756 Positive polarity footprints (may be `None`) 757 negative : `lsst.afw.detection.FootprintSet` 758 Negative polarity footprints (may be `None`) 760 Number of footprints in positive or 0 if detection polarity was 763 Number of footprints in negative or 0 if detection polarity was 765 background : `lsst.afw.math.BackgroundList` 766 Re-estimated background. `None` if 767 ``reEstimateBackground==False``. 769 Multiplication factor applied to the configured detection 772 maskedImage = exposure.maskedImage
777 psf = self.
getPsf(exposure, sigma=sigma)
779 convolveResults = self.
convolveImage(maskedImage, psf, doSmooth=doSmooth)
780 middle = convolveResults.middle
781 sigma = convolveResults.sigma
785 if self.config.doTempLocalBackground:
789 if self.config.reEstimateBackground:
793 self.
display(exposure, results, middle)
798 """Make an afw.detection.Threshold object corresponding to the task's 799 configuration and the statistics of the given image. 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. 809 Factor by which to multiply the configured detection threshold. 810 This is useful for tweaking the detection threshold slightly. 814 threshold : `lsst.afw.detection.Threshold` 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)
823 sctrl.setAndMask(bad)
825 thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
826 thresholdType =
'value' 829 threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
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. 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. 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. 849 for footprint
in fpSet.getFootprints():
850 oldPeaks = footprint.getPeaks()
851 if len(oldPeaks) <= self.config.nPeaksMaxSimple:
856 sub = image.Factory(image, footprint.getBBox())
861 self.config.minPixels
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:
870 oldPeaks.extend(newPeaks)
876 """Set the edgeBitmask bits for all of maskedImage outside goodBBox 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``. 888 msk = maskedImage.getMask()
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)],
896 goodBBox.getBeginX() - mx0, msk.getHeight()],
897 [goodBBox.getEndX() - mx0, 0,
898 maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
902 edgeMask |= edgeBitmask
906 """Context manager for removing wide (large-scale) background 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. 912 The background that we remove will be restored upon exit from 917 exposure : `lsst.afw.image.Exposure` 918 Exposure on which to remove large-scale background. 922 context : context manager 923 Context manager that will ensure the temporary wide background 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
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])
941 if doTempWideBackground:
942 exposure.maskedImage.image.array[:] = original
946 """Add a set of exposures together. 950 exposureList : `list` of `lsst.afw.image.Exposure` 951 Sequence of exposures to add. 955 addedExposure : `lsst.afw.image.Exposure` 956 An exposure of the same size as each exposure in ``exposureList``, 957 with the metadata from ``exposureList[0]`` and a masked image equal 958 to the sum of all the exposure's masked images. 960 exposure0 = exposureList[0]
961 image0 = exposure0.getMaskedImage()
963 addedImage = image0.Factory(image0,
True)
964 addedImage.setXY0(image0.getXY0())
966 for exposure
in exposureList[1:]:
967 image = exposure.getMaskedImage()
970 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)
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...