284 def deblend(self, exposure, srcs, psf):
289 exposure : `lsst.afw.image.Exposure`
290 Exposure to be processed
291 srcs : `lsst.afw.table.SourceCatalog`
292 SourceCatalog containing sources detected on this exposure
293 psf : `lsst.afw.detection.Psf`
294 Point source function
301 if self.config.useCiLimits:
302 self.log.
info(f
"Using CI catalog limits, "
303 f
"the original number of sources to deblend was {len(srcs)}.")
306 minChildren, maxChildren = self.config.ciDeblendChildRange
307 nPeaks = np.array([len(src.getFootprint().peaks)
for src
in srcs])
308 childrenInRange = np.where((nPeaks >= minChildren) & (nPeaks <= maxChildren))[0]
309 if len(childrenInRange) < self.config.ciNumParentsToDeblend:
310 raise ValueError(
"Fewer than ciNumParentsToDeblend children were contained in the range "
311 "indicated by ciDeblendChildRange. Adjust this range to include more "
315 parents = nPeaks == 1
316 children = np.zeros((len(srcs),), dtype=bool)
317 children[childrenInRange[:self.config.ciNumParentsToDeblend]] =
True
318 srcs = srcs[parents | children]
321 idFactory = srcs.getIdFactory()
322 maxId = np.max(srcs[
"id"])
323 idFactory.notify(maxId)
325 self.log.
info(
"Deblending %d sources", len(srcs))
330 mi = exposure.getMaskedImage()
332 statsCtrl.setAndMask(mi.getMask().getPlaneBitMask(self.config.maskPlanes))
334 sigma1 = math.sqrt(stats.getValue(afwMath.MEDIAN))
335 self.log.
trace(
'sigma1: %g', sigma1)
339 for i, src
in enumerate(srcs):
342 fp = src.getFootprint()
347 src.assign(pks[0], self.peakSchemaMapper)
352 if self.isLargeFootprint(fp):
353 src.set(self.tooBigKey,
True)
354 self.skipParent(src, mi.getMask())
355 self.log.
warning(
'Parent %i: skipping large footprint (area: %i)',
356 int(src.getId()), int(fp.getArea()))
358 if self.isMasked(fp, exposure.getMaskedImage().getMask()):
359 src.set(self.maskedKey,
True)
360 self.skipParent(src, mi.getMask())
361 self.log.
warning(
'Parent %i: skipping masked footprint (area: %i)',
362 int(src.getId()), int(fp.getArea()))
367 psf_fwhm = self._getPsfFwhm(psf, bb)
369 self.log.
trace(
'Parent %i: deblending %i peaks', int(src.getId()), len(pks))
371 self.preSingleDeblendHook(exposure, srcs, i, fp, psf, psf_fwhm, sigma1)
375 src.set(self.tooManyPeaksKey, len(fp.getPeaks()) > self.config.maxNumberOfPeaks)
379 fp, mi, psf, psf_fwhm, sigma1=sigma1,
380 psfChisqCut1=self.config.psfChisq1,
381 psfChisqCut2=self.config.psfChisq2,
382 psfChisqCut2b=self.config.psfChisq2b,
383 maxNumberOfPeaks=self.config.maxNumberOfPeaks,
384 strayFluxToPointSources=self.config.strayFluxToPointSources,
385 assignStrayFlux=self.config.assignStrayFlux,
386 strayFluxAssignment=self.config.strayFluxRule,
387 rampFluxAtEdge=(self.config.edgeHandling ==
'ramp'),
388 patchEdges=(self.config.edgeHandling ==
'noclip'),
389 tinyFootprintSize=self.config.tinyFootprintSize,
390 clipStrayFluxFraction=self.config.clipStrayFluxFraction,
391 weightTemplates=self.config.weightTemplates,
392 removeDegenerateTemplates=self.config.removeDegenerateTemplates,
393 maxTempDotProd=self.config.maxTempDotProd,
394 medianSmoothTemplate=self.config.medianSmoothTemplate
396 if self.config.catchFailures:
397 src.set(self.deblendFailedKey,
False)
398 except Exception
as e:
399 if self.config.catchFailures:
400 self.log.
warning(
"Unable to deblend source %d: %s", src.getId(), e)
401 src.set(self.deblendFailedKey,
True)
403 traceback.print_exc()
410 for j, peak
in enumerate(res.deblendedParents[0].peaks):
411 heavy = peak.getFluxPortion()
412 if heavy
is None or peak.skip:
413 src.set(self.deblendSkippedKey,
True)
414 if not self.config.propagateAllPeaks:
419 self.log.
trace(
"Peak at (%i,%i) failed. Using minimal default info for child.",
420 pks[j].getIx(), pks[j].getIy())
424 peakList = foot.getPeaks()
426 peakList.append(peak.peak)
427 zeroMimg = afwImage.MaskedImageF(foot.getBBox())
429 if peak.deblendedAsPsf:
430 if peak.psfFitFlux
is None:
431 peak.psfFitFlux = 0.0
432 if peak.psfFitCenter
is None:
433 peak.psfFitCenter = (peak.peak.getIx(), peak.peak.getIy())
435 assert(len(heavy.getPeaks()) == 1)
437 src.set(self.deblendSkippedKey,
False)
438 child = srcs.addNew()
440 for key
in self.toCopyFromParent:
441 child.set(key, src.get(key))
442 child.assign(heavy.getPeaks()[0], self.peakSchemaMapper)
443 child.setParent(src.getId())
444 child.setFootprint(heavy)
445 child.set(self.psfKey, peak.deblendedAsPsf)
446 child.set(self.hasStrayFluxKey, peak.strayFlux
is not None)
447 if peak.deblendedAsPsf:
448 (cx, cy) = peak.psfFitCenter
450 child.set(self.psfFluxKey, peak.psfFitFlux)
451 child.set(self.deblendRampedTemplateKey, peak.hasRampedTemplate)
452 child.set(self.deblendPatchedTemplateKey, peak.patched)
459 child.set(self.peakCenter,
geom.Point2I(pks[j].getIx(), pks[j].getIy()))
460 child.set(self.peakIdKey, pks[j].getId())
463 child.set(self.nPeaksKey, 1)
465 child.set(self.parentNPeaksKey, len(pks))
474 spans = src.getFootprint().spans
476 spans = spans.union(child.getFootprint().spans)
477 src.getFootprint().setSpans(spans)
479 src.set(self.nChildKey, nchild)
481 self.postSingleDeblendHook(exposure, srcs, i, npre, kids, fp, psf, psf_fwhm, sigma1, res)
485 self.log.
info(
'Deblended: of %i sources, %i were deblended, creating %i children, total %i sources',
486 n0, nparents, n1-n0, n1)
Pass parameters to a Statistics object.
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=nullptr)
Create a HeavyFootprint with footprint defined by the given Footprint and pixel values from the given...
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)
def deblend(footprint, maskedImage, psf, psffwhm, psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, fitPsfs=True, medianSmoothTemplate=True, medianFilterHalfsize=2, monotonicTemplate=True, weightTemplates=False, log=None, verbose=False, sigma1=None, maxNumberOfPeaks=0, assignStrayFlux=True, strayFluxToPointSources='necessary', strayFluxAssignment='r-to-peak', rampFluxAtEdge=False, patchEdges=False, tinyFootprintSize=2, getTemplateSum=False, clipStrayFluxFraction=0.001, clipFootprintToNonzero=True, removeDegenerateTemplates=False, maxTempDotProd=0.5)