24__all__ = (
"SourceDetectionConfig",
"SourceDetectionTask",
"addExposures")
26from contextlib
import contextmanager
39from lsst.utils.timer
import timeMethod
40from .subtractBackground
import SubtractBackgroundTask
44 """Configuration parameters for the SourceDetectionTask
46 minPixels = pexConfig.RangeField(
47 doc="detected sources with fewer than the specified number of pixels will be ignored",
48 dtype=int, optional=
False, default=1, min=0,
50 isotropicGrow = pexConfig.Field(
51 doc=
"Pixels should be grown as isotropically as possible (slower)",
52 dtype=bool, optional=
False, default=
False,
54 combinedGrow = pexConfig.Field(
55 doc=
"Grow all footprints at the same time? This allows disconnected footprints to merge.",
56 dtype=bool, default=
True,
58 nSigmaToGrow = pexConfig.Field(
59 doc=
"Grow detections by nSigmaToGrow * [PSF RMS width]; if 0 then do not grow",
60 dtype=float, default=2.4,
62 returnOriginalFootprints = pexConfig.Field(
63 doc=
"Grow detections to set the image mask bits, but return the original (not-grown) footprints",
64 dtype=bool, optional=
False, default=
False,
66 thresholdValue = pexConfig.RangeField(
67 doc=
"Threshold for footprints; exact meaning and units depend on thresholdType.",
68 dtype=float, optional=
False, default=5.0, min=0.0,
70 includeThresholdMultiplier = pexConfig.RangeField(
71 doc=
"Include threshold relative to thresholdValue",
72 dtype=float, default=1.0, min=0.0,
74 thresholdType = pexConfig.ChoiceField(
75 doc=
"specifies the desired flavor of Threshold",
76 dtype=str, optional=
False, default=
"stdev",
78 "variance":
"threshold applied to image variance",
79 "stdev":
"threshold applied to image std deviation",
80 "value":
"threshold applied to image value",
81 "pixel_stdev":
"threshold applied to per-pixel std deviation",
84 thresholdPolarity = pexConfig.ChoiceField(
85 doc=
"specifies whether to detect positive, or negative sources, or both",
86 dtype=str, optional=
False, default=
"positive",
88 "positive":
"detect only positive sources",
89 "negative":
"detect only negative sources",
90 "both":
"detect both positive and negative sources",
93 adjustBackground = pexConfig.Field(
95 doc=
"Fiddle factor to add to the background; debugging only",
98 reEstimateBackground = pexConfig.Field(
100 doc=
"Estimate the background again after final source detection?",
101 default=
True, optional=
False,
103 background = pexConfig.ConfigurableField(
104 doc=
"Background re-estimation; ignored if reEstimateBackground false",
105 target=SubtractBackgroundTask,
107 tempLocalBackground = pexConfig.ConfigurableField(
108 doc=(
"A local (small-scale), temporary background estimation step run between "
109 "detecting above-threshold regions and detecting the peaks within "
110 "them; used to avoid detecting spuerious peaks in the wings."),
111 target=SubtractBackgroundTask,
113 doTempLocalBackground = pexConfig.Field(
115 doc=
"Enable temporary local background subtraction? (see tempLocalBackground)",
118 tempWideBackground = pexConfig.ConfigurableField(
119 doc=(
"A wide (large-scale) background estimation and removal before footprint and peak detection. "
120 "It is added back into the image after detection. The purpose is to suppress very large "
121 "footprints (e.g., from large artifacts) that the deblender may choke on."),
122 target=SubtractBackgroundTask,
124 doTempWideBackground = pexConfig.Field(
126 doc=
"Do temporary wide (large-scale) background subtraction before footprint detection?",
129 nPeaksMaxSimple = pexConfig.Field(
131 doc=(
"The maximum number of peaks in a Footprint before trying to "
132 "replace its peaks using the temporary local background"),
135 nSigmaForKernel = pexConfig.Field(
137 doc=(
"Multiple of PSF RMS size to use for convolution kernel bounding box size; "
138 "note that this is not a half-size. The size will be rounded up to the nearest odd integer"),
141 statsMask = pexConfig.ListField(
143 doc=
"Mask planes to ignore when calculating statistics of image (for thresholdType=stdev)",
144 default=[
'BAD',
'SAT',
'EDGE',
'NO_DATA'],
149 doc=
"Mask planes to exclude when detecting sources."
162 for maskPlane
in (
"DETECTED",
"DETECTED_NEGATIVE"):
168 """Detect peaks and footprints of sources in an image.
170 This task convolves the image with a Gaussian approximation to the PSF,
171 matched to the sigma of the input exposure, because this
is separable
and
172 fast. The PSF would have to be very non-Gaussian
or non-circular
for this
173 approximation to have a significant impact on the signal-to-noise of the
181 Keyword arguments passed to `lsst.pipe.base.Task.__init__`
183 If schema
is not None and configured
for 'both' detections,
184 a
'flags.negative' field will be added to label detections made
with a
189 This task can add fields to the schema, so any code calling this task must
190 ensure that these columns are indeed present
in the input match list.
192 ConfigClass = SourceDetectionConfig
193 _DefaultName = "sourceDetection"
196 pipeBase.Task.__init__(self, **kwds)
197 if schema
is not None and self.config.thresholdPolarity ==
"both":
199 "flags_negative", type=
"Flag",
200 doc=
"set if source was detected as significantly negative"
203 if self.config.thresholdPolarity ==
"both":
204 self.log.warning(
"Detection polarity set to 'both', but no flag will be "
205 "set to distinguish between positive and negative detections")
207 if self.config.reEstimateBackground:
208 self.makeSubtask(
"background")
209 if self.config.doTempLocalBackground:
210 self.makeSubtask(
"tempLocalBackground")
211 if self.config.doTempWideBackground:
212 self.makeSubtask(
"tempWideBackground")
215 def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None,
217 r"""Detect sources and return catalog(s) of detections.
222 Table object that will be used to create the SourceCatalog.
224 Exposure to process; DETECTED mask plane will be set in-place.
225 doSmooth : `bool`, optional
226 If
True, smooth the image before detection using a Gaussian of width
227 ``sigma``,
or the measured PSF width. Set to
False when running on
228 e.g. a pre-convolved image,
or a mask plane.
229 sigma : `float`, optional
230 Sigma of PSF (pixels); used
for smoothing
and to grow detections;
231 if None then measure the sigma of the PSF of the exposure
232 clearMask : `bool`, optional
233 Clear DETECTED{,_NEGATIVE} planes before running detection.
234 expId : `int`, optional
235 Exposure identifier; unused by this implementation, but used
for
236 RNG seed by subclasses.
238 Background that was already subtracted
from the exposure; will be
239 modified
in-place
if ``reEstimateBackground=
True``.
243 result : `lsst.pipe.base.Struct`
244 The `~lsst.pipe.base.Struct` contains:
247 Detected sources on the exposure.
250 Positive polarity footprints.
253 Negative polarity footprints.
256 Number of footprints
in positive
or 0
if detection polarity was
259 Number of footprints
in negative
or 0
if detection polarity was
262 Re-estimated background. `
None`
if
263 ``reEstimateBackground==
False``.
266 Multiplication factor applied to the configured detection
272 Raised
if flags.negative
is needed, but isn
't in table's schema.
273 lsst.pipe.base.TaskError
274 Raised
if sigma=
None, doSmooth=
True and the exposure has no PSF.
278 If you want to avoid dealing
with Sources
and Tables, you can use
283 raise ValueError(
"Table has incorrect Schema")
284 results = self.
detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
285 clearMask=clearMask, expId=expId, background=background)
287 sources.reserve(results.numPos + results.numNeg)
289 results.negative.makeSources(sources)
291 for record
in sources:
294 results.positive.makeSources(sources)
295 results.sources = sources
298 def display(self, exposure, results, convolvedImage=None):
299 """Display detections if so configured
301 Displays the ``exposure`` in frame 0, overlays the detection peaks.
303 Requires that ``lsstDebug`` has been set up correctly, so that
304 ``
lsstDebug.Info(
"lsst.meas.algorithms.detection")`` evaluates `
True`.
306 If the ``convolvedImage``
is non-`
None`
and
308 ``convolvedImage`` will be displayed
in frame 1.
313 Exposure to display, on which will be plotted the detections.
314 results : `lsst.pipe.base.Struct`
315 Results of the
'detectFootprints' method, containing positive
and
316 negative footprints (which contain the peak positions that we will
317 plot). This
is a `Struct`
with ``positive``
and ``negative``
320 Convolved image used
for thresholding.
333 afwDisplay.setDefaultMaskTransparency(75)
335 disp0 = afwDisplay.Display(frame=0)
336 disp0.mtv(exposure, title=
"detection")
338 def plotPeaks(fps, ctype):
341 with disp0.Buffering():
342 for fp
in fps.getFootprints():
343 for pp
in fp.getPeaks():
344 disp0.dot(
"+", pp.getFx(), pp.getFy(), ctype=ctype)
345 plotPeaks(results.positive,
"yellow")
346 plotPeaks(results.negative,
"red")
348 if convolvedImage
and display > 1:
349 disp1 = afwDisplay.Display(frame=1)
350 disp1.mtv(convolvedImage, title=
"PSF smoothed")
352 disp2 = afwDisplay.Display(frame=2)
353 disp2.mtv(afwImage.ImageF(np.sqrt(exposure.variance.array)), title=
"stddev")
356 """Apply a temporary local background subtraction
358 This temporary local background serves to suppress noise fluctuations
359 in the wings of bright objects.
361 Peaks
in the footprints will be updated.
366 Exposure
for which to fit local background.
368 Convolved image on which detection will be performed
369 (typically smaller than ``exposure`` because the
370 half-kernel has been removed around the edges).
371 results : `lsst.pipe.base.Struct`
372 Results of the
'detectFootprints' method, containing positive
and
373 negative footprints (which contain the peak positions that we will
374 plot). This
is a `Struct`
with ``positive``
and ``negative``
380 bg = self.tempLocalBackground.fitBackground(exposure.getMaskedImage())
381 bgImage = bg.getImageF(self.tempLocalBackground.config.algorithm,
382 self.tempLocalBackground.config.undersampleStyle)
383 middle -= bgImage.Factory(bgImage, middle.getBBox())
384 if self.config.thresholdPolarity !=
"negative":
385 results.positiveThreshold = self.
makeThreshold(middle,
"positive")
386 self.
updatePeaks(results.positive, middle, results.positiveThreshold)
387 if self.config.thresholdPolarity !=
"positive":
388 results.negativeThreshold = self.
makeThreshold(middle,
"negative")
389 self.
updatePeaks(results.negative, middle, results.negativeThreshold)
392 """Clear the DETECTED and DETECTED_NEGATIVE mask planes.
394 Removes any previous detection mask in preparation
for a new
402 mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask(
"DETECTED_NEGATIVE"))
405 """Calculate the size of the smoothing kernel.
407 Uses the ``nSigmaForKernel`` configuration parameter. Note
408 that that is the full width of the kernel bounding box
409 (so a value of 7 means 3.5 sigma on either side of center).
410 The value will be rounded up to the nearest odd integer.
415 Gaussian sigma of smoothing kernel.
420 Size of the smoothing kernel.
422 return (int(sigma * self.config.nSigmaForKernel + 0.5)//2)*2 + 1
425 """Create a single Gaussian PSF for an exposure.
428 with that, otherwise use the sigma
from the psf of the ``exposure`` to
434 Exposure
from which to retrieve the PSF.
435 sigma : `float`, optional
436 Gaussian sigma to use
if provided.
441 PSF to use
for detection.
446 Raised
if ``sigma``
is not provided
and ``exposure`` does
not
447 contain a ``Psf`` object.
450 psf = exposure.getPsf()
452 raise RuntimeError(
"Unable to determine PSF to use for detection: no sigma provided")
453 sigma = psf.computeShape(psf.getAveragePosition()).getDeterminantRadius()
459 """Convolve the image with the PSF.
461 We convolve the image with a Gaussian approximation to the PSF,
462 because this
is separable
and therefore fast. It
's technically a
463 correlation rather than a convolution, but since we use a symmetric
464 Gaussian there's no difference.
466 The convolution can be disabled with ``doSmooth=
False``. If we do
467 convolve, we mask the edges
as ``EDGE``
and return the convolved image
468 with the edges removed. This
is because we can
't convolve the edges
469 because the kernel would extend off the image.
476 PSF to convolve with (actually
with a Gaussian approximation
479 Actually do the convolution? Set to
False when running on
480 e.g. a pre-convolved image,
or a mask plane.
484 results : `lsst.pipe.base.Struct`
485 The `~lsst.pipe.base.Struct` contains:
490 Gaussian sigma used
for the convolution. (`float`)
492 self.metadata["doSmooth"] = doSmooth
493 sigma = psf.computeShape(psf.getAveragePosition()).getDeterminantRadius()
494 self.metadata[
"sigma"] = sigma
497 middle = maskedImage.Factory(maskedImage, deep=
True)
498 return pipeBase.Struct(middle=middle, sigma=sigma)
503 self.metadata[
"smoothingKernelWidth"] = kWidth
504 gaussFunc = afwMath.GaussianFunction1D(sigma)
507 convolvedImage = maskedImage.Factory(maskedImage.getBBox())
512 goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
513 middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT,
False)
516 self.
setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask(
"EDGE"))
518 return pipeBase.Struct(middle=middle, sigma=sigma)
521 r"""Apply thresholds to the convolved image
524 The threshold can be modified by the provided multiplication
530 Convolved image to threshold.
532 Bounding box of unconvolved image.
534 Multiplier
for the configured threshold.
535 factorNeg : `float`
or `
None`
536 Multiplier
for the configured threshold
for negative detection polarity.
537 If `
None`, will be set equal to ``factor`` (i.e. equal to the factor used
538 for positive detection polarity).
542 results : `lsst.pipe.base.Struct`
543 The `~lsst.pipe.base.Struct` contains:
546 Positive detection footprints,
if configured.
549 Negative detection footprints,
if configured.
552 Multiplier
for the configured threshold.
555 Multiplier
for the configured threshold
for negative detection polarity.
558 if factorNeg
is None:
560 self.log.info(
"Setting factor for negative detections equal to that for positive "
561 "detections: %f", factor)
562 results = pipeBase.Struct(positive=
None, negative=
None, factor=factor, factorNeg=factorNeg,
563 positiveThreshold=
None, negativeThreshold=
None)
565 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"negative":
566 results.positiveThreshold = self.
makeThreshold(middle,
"positive", factor=factor)
569 results.positiveThreshold,
571 self.config.minPixels
573 results.positive.setRegion(bbox)
574 if self.config.reEstimateBackground
or self.config.thresholdPolarity !=
"positive":
575 results.negativeThreshold = self.
makeThreshold(middle,
"negative", factor=factorNeg)
578 results.negativeThreshold,
580 self.config.minPixels
582 results.negative.setRegion(bbox)
587 """Finalize the detected footprints.
589 Grow the footprints, set the ``DETECTED`` and ``DETECTED_NEGATIVE``
590 mask planes,
and log the results.
592 ``numPos`` (number of positive footprints), ``numPosPeaks`` (number
593 of positive peaks), ``numNeg`` (number of negative footprints),
594 ``numNegPeaks`` (number of negative peaks) entries are added to the
600 Mask image on which to flag detected pixels.
601 results : `lsst.pipe.base.Struct`
602 Struct of detection results, including ``positive``
and
603 ``negative`` entries; modified.
605 Gaussian sigma of PSF.
607 Multiplier
for the configured threshold. Note that this
is only
608 used here
for logging purposes.
609 factorNeg : `float`
or `
None`
610 Multiplier used
for the negative detection polarity threshold.
611 If `
None`, a factor equal to ``factor`` (i.e. equal to the one used
612 for positive detection polarity)
is assumed. Note that this
is only
613 used here
for logging purposes.
615 factorNeg = factor if factorNeg
is None else factorNeg
616 for polarity, maskName
in ((
"positive",
"DETECTED"), (
"negative",
"DETECTED_NEGATIVE")):
617 fpSet = getattr(results, polarity)
620 if self.config.nSigmaToGrow > 0:
621 nGrow = int((self.config.nSigmaToGrow * sigma) + 0.5)
622 self.metadata[
"nGrow"] = nGrow
623 if self.config.combinedGrow:
626 stencil = (afwGeom.Stencil.CIRCLE
if self.config.isotropicGrow
else
627 afwGeom.Stencil.MANHATTAN)
629 fp.dilate(nGrow, stencil)
630 fpSet.setMask(mask, maskName)
631 if not self.config.returnOriginalFootprints:
632 setattr(results, polarity, fpSet)
635 results.numPosPeaks = 0
637 results.numNegPeaks = 0
641 if results.positive
is not None:
642 results.numPos = len(results.positive.getFootprints())
643 results.numPosPeaks = sum(len(fp.getPeaks())
for fp
in results.positive.getFootprints())
644 positive =
" %d positive peaks in %d footprints" % (results.numPosPeaks, results.numPos)
645 if results.negative
is not None:
646 results.numNeg = len(results.negative.getFootprints())
647 results.numNegPeaks = sum(len(fp.getPeaks())
for fp
in results.negative.getFootprints())
648 negative =
" %d negative peaks in %d footprints" % (results.numNegPeaks, results.numNeg)
650 self.log.info(
"Detected%s%s%s to %g +ve and %g -ve %s",
651 positive,
" and" if positive
and negative
else "", negative,
652 self.config.thresholdValue*self.config.includeThresholdMultiplier*factor,
653 self.config.thresholdValue*self.config.includeThresholdMultiplier*factorNeg,
654 "DN" if self.config.thresholdType ==
"value" else "sigma")
657 """Estimate the background after detection
662 Image on which to estimate the background.
664 List of backgrounds; modified.
668 bg : `lsst.afw.math.backgroundMI`
669 Empirical background model.
671 bg = self.background.fitBackground(maskedImage)
672 if self.config.adjustBackground:
673 self.log.warning(
"Fiddling the background by %g", self.config.adjustBackground)
674 bg += self.config.adjustBackground
675 self.log.info(
"Resubtracting the background after object detection")
676 maskedImage -= bg.getImageF(self.background.config.algorithm,
677 self.background.config.undersampleStyle)
679 actrl = bg.getBackgroundControl().getApproximateControl()
681 bg.getAsUsedUndersampleStyle(), actrl.getStyle(), actrl.getOrderX(),
682 actrl.getOrderY(), actrl.getWeighting()))
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.
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,
711 """Detect footprints on an exposure.
716 Exposure to process; DETECTED{,_NEGATIVE} mask plane will be
718 doSmooth : `bool`, optional
719 If
True, smooth the image before detection using a Gaussian
720 of width ``sigma``,
or the measured PSF width of ``exposure``.
721 Set to
False when running on e.g. a pre-convolved image,
or a mask
723 sigma : `float`, optional
724 Gaussian Sigma of PSF (pixels); used
for smoothing
and to grow
725 detections;
if `
None` then measure the sigma of the PSF of the
727 clearMask : `bool`, optional
728 Clear both DETECTED
and DETECTED_NEGATIVE planes before running
730 expId : `dict`, optional
731 Exposure identifier; unused by this implementation, but used
for
732 RNG seed by subclasses.
734 Background that was already subtracted
from the exposure; will be
735 modified
in-place
if ``reEstimateBackground=
True``.
739 results : `lsst.pipe.base.Struct`
740 A `~lsst.pipe.base.Struct` containing:
743 Positive polarity footprints.
746 Negative polarity footprints.
749 Number of footprints
in positive
or 0
if detection polarity was
752 Number of footprints
in negative
or 0
if detection polarity was
755 Re-estimated background. `
None`
or the input ``background``
756 if ``reEstimateBackground==
False``.
759 Multiplication factor applied to the configured detection
762 maskedImage = exposure.maskedImage
767 psf = self.
getPsf(exposure, sigma=sigma)
769 convolveResults = self.
convolveImage(maskedImage, psf, doSmooth=doSmooth)
770 middle = convolveResults.middle
771 sigma = convolveResults.sigma
777 if self.config.doTempLocalBackground:
784 results.positive = self.
setPeakSignificance(middle, results.positive, results.positiveThreshold)
785 results.negative = self.
setPeakSignificance(middle, results.negative, results.negativeThreshold,
788 if self.config.reEstimateBackground:
793 self.
display(exposure, results, middle)
798 """Set the significance of flagged pixels to zero.
802 middle : `lsst.afw.image.ExposureF`
803 Score or maximum likelihood difference image.
804 The image plane will be modified
in place.
807 badPixels = middle.mask.array & badPixelMask > 0
808 middle.image.array[badPixels] = 0
811 """Set the significance of each detected peak to the pixel value divided
812 by the appropriate standard-deviation for ``config.thresholdType``.
814 Only sets significance
for "stdev" and "pixel_stdev" thresholdTypes;
815 we leave it undefined
for "value" and "variance" as it does
not have a
816 well-defined meaning
in those cases.
821 Exposure that footprints were detected on, likely the convolved,
822 local background-subtracted image.
824 Footprints detected on the image.
826 Threshold used to find footprints.
827 negative : `bool`, optional
828 Are we calculating
for negative sources?
830 if footprints
is None or footprints.getFootprints() == []:
832 polarity = -1
if negative
else 1
836 mapper.addMinimalSchema(footprints.getFootprints()[0].peaks.schema)
837 mapper.addOutputField(
"significance", type=float,
838 doc=
"Ratio of peak value to configured standard deviation.")
844 for old, new
in zip(footprints.getFootprints(), newFootprints.getFootprints()):
846 newPeaks.extend(old.peaks, mapper=mapper)
847 new.getPeaks().clear()
848 new.setPeakCatalog(newPeaks)
851 if self.config.thresholdType ==
"pixel_stdev":
852 for footprint
in newFootprints.getFootprints():
853 footprint.updatePeakSignificance(exposure.variance, polarity)
854 elif self.config.thresholdType ==
"stdev":
855 sigma = threshold.getValue() / self.config.thresholdValue
856 for footprint
in newFootprints.getFootprints():
857 footprint.updatePeakSignificance(polarity*sigma)
859 for footprint
in newFootprints.getFootprints():
860 for peak
in footprint.peaks:
861 peak[
"significance"] = 0
866 """Make an afw.detection.Threshold object corresponding to the task's
867 configuration and the statistics of the given image.
872 Image to measure noise statistics
from if needed.
873 thresholdParity: `str`
874 One of
"positive" or "negative", to set the kind of fluctuations
875 the Threshold will detect.
877 Factor by which to multiply the configured detection threshold.
878 This
is useful
for tweaking the detection threshold slightly.
885 parity = False if thresholdParity ==
"negative" else True
886 thresholdValue = self.config.thresholdValue
887 thresholdType = self.config.thresholdType
888 if self.config.thresholdType ==
'stdev':
889 bad = image.getMask().getPlaneBitMask(self.config.statsMask)
891 sctrl.setAndMask(bad)
893 thresholdValue *= stats.getValue(afwMath.STDEVCLIP)
894 thresholdType =
'value'
897 threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
898 self.log.debug(
"Detection threshold: %s", threshold)
902 """Update the Peaks in a FootprintSet by detecting new Footprints and
903 Peaks in an image
and using the new Peaks instead of the old ones.
908 Set of Footprints whose Peaks should be updated.
910 Image to detect new Footprints
and Peak
in.
912 Threshold object
for detection.
914 Input Footprints
with fewer Peaks than self.config.nPeaksMaxSimple
915 are
not modified,
and if no new Peaks are detected
in an input
916 Footprint, the brightest original Peak
in that Footprint
is kept.
918 for footprint
in fpSet.getFootprints():
919 oldPeaks = footprint.getPeaks()
920 if len(oldPeaks) <= self.config.nPeaksMaxSimple:
925 sub = image.Factory(image, footprint.getBBox())
930 self.config.minPixels
933 for fpForPeaks
in fpSetForPeaks.getFootprints():
934 for peak
in fpForPeaks.getPeaks():
935 if footprint.contains(peak.getI()):
936 newPeaks.append(peak)
937 if len(newPeaks) > 0:
939 oldPeaks.extend(newPeaks)
945 """Set the edgeBitmask bits for all of maskedImage outside goodBBox
950 Image on which to set edge bits in the mask.
952 Bounding box of good pixels,
in ``LOCAL`` coordinates.
954 Bit mask to OR
with the existing mask bits
in the region
955 outside ``goodBBox``.
957 msk = maskedImage.getMask()
959 mx0, my0 = maskedImage.getXY0()
960 for x0, y0, w, h
in ([0, 0,
961 msk.getWidth(), goodBBox.getBeginY() - my0],
962 [0, goodBBox.getEndY() - my0, msk.getWidth(),
963 maskedImage.getHeight() - (goodBBox.getEndY() - my0)],
965 goodBBox.getBeginX() - mx0, msk.getHeight()],
966 [goodBBox.getEndX() - mx0, 0,
967 maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
971 edgeMask |= edgeBitmask
975 """Context manager for removing wide (large-scale) background
977 Removing a wide (large-scale) background helps to suppress the
978 detection of large footprints that may overwhelm the deblender.
979 It does, however, set a limit on the maximum scale of objects.
981 The background that we remove will be restored upon exit from
987 Exposure on which to remove large-scale background.
991 context : context manager
992 Context manager that will ensure the temporary wide background
995 doTempWideBackground = self.config.doTempWideBackground
996 if doTempWideBackground:
997 self.log.info(
"Applying temporary wide background subtraction")
998 original = exposure.maskedImage.image.array[:].copy()
999 self.tempWideBackground.run(exposure).background
1002 image = exposure.maskedImage.image
1003 mask = exposure.maskedImage.mask
1004 noData = mask.array & mask.getPlaneBitMask(
"NO_DATA") > 0
1005 isGood = mask.array & mask.getPlaneBitMask(self.config.statsMask) == 0
1006 image.array[noData] = np.median(image.array[~noData & isGood])
1010 if doTempWideBackground:
1011 exposure.maskedImage.image.array[:] = original
1015 """Add a set of exposures together.
1020 Sequence of exposures to add.
1025 An exposure of the same size as each exposure
in ``exposureList``,
1026 with the metadata
from ``exposureList[0]``
and a masked image equal
1027 to the sum of all the exposure
's masked images.
1029 exposure0 = exposureList[0]
1030 image0 = exposure0.getMaskedImage()
1032 addedImage = image0.Factory(image0, True)
1033 addedImage.setXY0(image0.getXY0())
1035 for exposure
in exposureList[1:]:
1036 image = exposure.getMaskedImage()
1039 addedExposure = exposure0.Factory(addedImage, exposure0.getWcs())
1040 return addedExposure
A circularly symmetric Gaussian Psf class with no spatial variation, intended mostly for testing purp...
A polymorphic base class for representing an image's Point Spread Function.
A Threshold is used to pass a threshold value to detection algorithms.
A class to contain the data, WCS, and other information needed to describe an image of the sky.
A class to represent a 2-dimensional array of pixels.
Represent a 2-dimensional array of bitmask pixels.
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR'd together.
A class to manipulate images, masks, and variance as a single object.
Parameters to control convolution.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
Pass parameters to a Statistics object.
Defines the fields and offsets for a table.
A mapping between the keys of two Schemas, used to copy data between them.
Table class that contains measurements made on a single exposure.
An integer coordinate rectangle.
makeThreshold(self, image, thresholdParity, factor=1.0)
applyTempLocalBackground(self, exposure, middle, results)
calculateKernelSize(self, sigma)
setEdgeBits(maskedImage, goodBBox, edgeBitmask)
tempWideBackgroundContext(self, exposure)
setPeakSignificance(self, exposure, footprints, threshold, negative=False)
clearUnwantedResults(self, mask, results)
detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True, expId=None, background=None)
updatePeaks(self, fpSet, image, threshold)
getPsf(self, exposure, sigma=None)
applyThreshold(self, middle, bbox, factor=1.0, factorNeg=None)
convolveImage(self, maskedImage, psf, doSmooth=True)
display(self, exposure, results, convolvedImage=None)
finalizeFootprints(self, mask, results, sigma, factor=1.0, factorNeg=None)
removeBadPixels(self, middle)
__init__(self, schema=None, **kwds)
reEstimateBackground(self, maskedImage, backgrounds)
Threshold createThreshold(const double value, const std::string type="value", const bool polarity=true)
Factory method for creating Threshold objects.
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image.
addExposures(exposureList)