286 def deblend(self, exposure, srcs, psf):
291 exposure : `lsst.afw.image.Exposure`
292 Exposure to be processed
293 srcs : `lsst.afw.table.SourceCatalog`
294 SourceCatalog containing sources detected on this exposure
295 psf : `lsst.afw.detection.Psf`
296 Point source function
303 if self.config.useCiLimits:
304 self.log.
info(f
"Using CI catalog limits, "
305 f
"the original number of sources to deblend was {len(srcs)}.")
308 minChildren, maxChildren = self.config.ciDeblendChildRange
309 nPeaks = np.array([len(src.getFootprint().peaks)
for src
in srcs])
310 childrenInRange = np.where((nPeaks >= minChildren) & (nPeaks <= maxChildren))[0]
311 if len(childrenInRange) < self.config.ciNumParentsToDeblend:
312 raise ValueError(
"Fewer than ciNumParentsToDeblend children were contained in the range "
313 "indicated by ciDeblendChildRange. Adjust this range to include more "
317 parents = nPeaks == 1
318 children = np.zeros((len(srcs),), dtype=bool)
319 children[childrenInRange[:self.config.ciNumParentsToDeblend]] =
True
320 srcs = srcs[parents | children]
323 idFactory = srcs.getIdFactory()
324 maxId = np.max(srcs[
"id"])
325 idFactory.notify(maxId)
327 self.log.
info(
"Deblending %d sources" % len(srcs))
332 mi = exposure.getMaskedImage()
334 statsCtrl.setAndMask(mi.getMask().getPlaneBitMask(self.config.maskPlanes))
336 sigma1 = math.sqrt(stats.getValue(afwMath.MEDIAN))
337 self.log.
trace(
'sigma1: %g', sigma1)
341 for i, src
in enumerate(srcs):
344 fp = src.getFootprint()
349 src.assign(pks[0], self.peakSchemaMapper)
354 if self.isLargeFootprint(fp):
355 src.set(self.tooBigKey,
True)
356 self.skipParent(src, mi.getMask())
357 self.log.
warn(
'Parent %i: skipping large footprint (area: %i)',
358 int(src.getId()), int(fp.getArea()))
360 if self.isMasked(fp, exposure.getMaskedImage().getMask()):
361 src.set(self.maskedKey,
True)
362 self.skipParent(src, mi.getMask())
363 self.log.
warn(
'Parent %i: skipping masked footprint (area: %i)',
364 int(src.getId()), int(fp.getArea()))
369 psf_fwhm = self._getPsfFwhm(psf, bb)
371 self.log.
trace(
'Parent %i: deblending %i peaks', int(src.getId()), len(pks))
373 self.preSingleDeblendHook(exposure, srcs, i, fp, psf, psf_fwhm, sigma1)
377 src.set(self.tooManyPeaksKey, len(fp.getPeaks()) > self.config.maxNumberOfPeaks)
381 fp, mi, psf, psf_fwhm, sigma1=sigma1,
382 psfChisqCut1=self.config.psfChisq1,
383 psfChisqCut2=self.config.psfChisq2,
384 psfChisqCut2b=self.config.psfChisq2b,
385 maxNumberOfPeaks=self.config.maxNumberOfPeaks,
386 strayFluxToPointSources=self.config.strayFluxToPointSources,
387 assignStrayFlux=self.config.assignStrayFlux,
388 strayFluxAssignment=self.config.strayFluxRule,
389 rampFluxAtEdge=(self.config.edgeHandling ==
'ramp'),
390 patchEdges=(self.config.edgeHandling ==
'noclip'),
391 tinyFootprintSize=self.config.tinyFootprintSize,
392 clipStrayFluxFraction=self.config.clipStrayFluxFraction,
393 weightTemplates=self.config.weightTemplates,
394 removeDegenerateTemplates=self.config.removeDegenerateTemplates,
395 maxTempDotProd=self.config.maxTempDotProd,
396 medianSmoothTemplate=self.config.medianSmoothTemplate
398 if self.config.catchFailures:
399 src.set(self.deblendFailedKey,
False)
400 except Exception
as e:
401 if self.config.catchFailures:
402 self.log.
warn(
"Unable to deblend source %d: %s" % (src.getId(), e))
403 src.set(self.deblendFailedKey,
True)
405 traceback.print_exc()
412 for j, peak
in enumerate(res.deblendedParents[0].peaks):
413 heavy = peak.getFluxPortion()
414 if heavy
is None or peak.skip:
415 src.set(self.deblendSkippedKey,
True)
416 if not self.config.propagateAllPeaks:
421 self.log.
trace(
"Peak at (%i,%i) failed. Using minimal default info for child.",
422 pks[j].getIx(), pks[j].getIy())
426 peakList = foot.getPeaks()
428 peakList.append(peak.peak)
429 zeroMimg = afwImage.MaskedImageF(foot.getBBox())
431 if peak.deblendedAsPsf:
432 if peak.psfFitFlux
is None:
433 peak.psfFitFlux = 0.0
434 if peak.psfFitCenter
is None:
435 peak.psfFitCenter = (peak.peak.getIx(), peak.peak.getIy())
437 assert(len(heavy.getPeaks()) == 1)
439 src.set(self.deblendSkippedKey,
False)
440 child = srcs.addNew()
442 for key
in self.toCopyFromParent:
443 child.set(key, src.get(key))
444 child.assign(heavy.getPeaks()[0], self.peakSchemaMapper)
445 child.setParent(src.getId())
446 child.setFootprint(heavy)
447 child.set(self.psfKey, peak.deblendedAsPsf)
448 child.set(self.hasStrayFluxKey, peak.strayFlux
is not None)
449 if peak.deblendedAsPsf:
450 (cx, cy) = peak.psfFitCenter
452 child.set(self.psfFluxKey, peak.psfFitFlux)
453 child.set(self.deblendRampedTemplateKey, peak.hasRampedTemplate)
454 child.set(self.deblendPatchedTemplateKey, peak.patched)
461 child.set(self.peakCenter,
geom.Point2I(pks[j].getIx(), pks[j].getIy()))
462 child.set(self.peakIdKey, pks[j].getId())
465 child.set(self.nPeaksKey, 1)
467 child.set(self.parentNPeaksKey, len(pks))
476 spans = src.getFootprint().spans
478 spans = spans.union(child.getFootprint().spans)
479 src.getFootprint().setSpans(spans)
481 src.set(self.nChildKey, nchild)
483 self.postSingleDeblendHook(exposure, srcs, i, npre, kids, fp, psf, psf_fwhm, sigma1, res)
487 self.log.
info(
'Deblended: of %i sources, %i were deblended, creating %i children, total %i sources'
488 % (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)