@@ -105,6 +105,15 @@ class DynamicDetectionConfig(SourceDetectionConfig):
105105 "suitable locations to lay down sky objects. To allow for best effort "
106106 "sky source placement, if True, this allows for a slight erosion of "
107107 "the detection masks." )
108+ maxPeakToFootRatio = Field (dtype = float , default = 150.0 ,
109+ doc = "Maximum ratio of peak per footprint in the detection mask. "
110+ "This is to help prevent single contiguous footprints that nothing "
111+ "can be done with (i.e. deblending will be skipped). If the current "
112+ "detection plane does not satisfy this constraint, the detection "
113+ "threshold is increased iteratively until it is. This behaviour is "
114+ "intended to be an effective no-op for most \" typical\" scenes/standard "
115+ "quality observations, but can avoid total meltdown in, e.g. very "
116+ "crowded regions." )
108117
109118 def setDefaults (self ):
110119 SourceDetectionConfig .setDefaults (self )
@@ -424,22 +433,59 @@ def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True,
424433 # seed needs to fit in a C++ 'int' so pybind doesn't choke on it
425434 seed = (expId if expId is not None else int (maskedImage .image .array .sum ())) % (2 ** 31 - 1 )
426435 threshResults = self .calculateThreshold (exposure , seed , sigma = sigma )
427- factor = threshResults .multiplicative
436+ minMultiplicative = 0.5
437+ if threshResults .multiplicative < minMultiplicative :
438+ self .log .warning ("threshResults.multiplicative = %.2f is less than minimum value (%.2f). "
439+ "Setting to %.2f." , threshResults .multiplicative , minMultiplicative ,
440+ minMultiplicative )
441+ factor = max (minMultiplicative , threshResults .multiplicative )
428442 self .log .info ("Modifying configured detection threshold by factor %.2f to %.2f" ,
429443 factor , factor * self .config .thresholdValue )
430444
431- # Blow away preliminary (low threshold) detection mask
432- self .clearMask (maskedImage .mask )
433- if not clearMask :
434- maskedImage .mask .array |= oldDetected
435-
436- # Rinse and repeat thresholding with new calculated threshold
437- results = self .applyThreshold (middle , maskedImage .getBBox (), factor )
438- results .prelim = prelim
439- results .background = background if background is not None else lsst .afw .math .BackgroundList ()
440- if self .config .doTempLocalBackground :
441- self .applyTempLocalBackground (exposure , middle , results )
442- self .finalizeFootprints (maskedImage .mask , results , sigma , factor = factor )
445+ growOverride = None
446+ inFinalize = True
447+ while inFinalize :
448+ inFinalize = False
449+ # Blow away preliminary (low threshold) detection mask
450+ self .clearMask (maskedImage .mask )
451+ if not clearMask :
452+ maskedImage .mask .array |= oldDetected
453+
454+ # Rinse and repeat thresholding with new calculated threshold
455+ results = self .applyThreshold (middle , maskedImage .getBBox (), factor )
456+ results .prelim = prelim
457+ results .background = background if background is not None else lsst .afw .math .BackgroundList ()
458+ if self .config .doTempLocalBackground :
459+ self .applyTempLocalBackground (exposure , middle , results )
460+ self .finalizeFootprints (maskedImage .mask , results , sigma , factor = factor ,
461+ growOverride = growOverride )
462+ self .log .warning ("nPeaks/nFootprint = %.2f (max is %.1f)" ,
463+ results .numPosPeaks / results .numPos ,
464+ self .config .maxPeakToFootRatio )
465+ if results .numPosPeaks / results .numPos > self .config .maxPeakToFootRatio :
466+ if results .numPosPeaks / results .numPos > 3 * self .config .maxPeakToFootRatio :
467+ factor *= 1.4
468+ else :
469+ factor *= 1.2
470+ if factor > 2.0 :
471+ if growOverride is None :
472+ growOverride = 0.75 * self .config .nSigmaToGrow
473+ else :
474+ growOverride *= 0.75
475+ self .log .warning ("Decreasing nSigmaToGrow to %.2f" , growOverride )
476+ if factor >= 5 :
477+ self .log .warning ("New theshold value would be > 5 times the initially requested "
478+ "one (%.2f > %.2f). Leaving inFinalize iteration without "
479+ "getting the number of peaks per footprint below %.1f" ,
480+ factor * self .config .thresholdValue , self .config .thresholdValue ,
481+ self .config .maxPeakToFootRatio )
482+ inFinalize = False
483+ else :
484+ inFinalize = True
485+ self .log .warning ("numPosPeaks/numPos (%d) > maxPeakPerFootprint (%.1f). "
486+ "Increasing threshold factor to %.2f and re-running," ,
487+ results .numPosPeaks / results .numPos , self .config .maxPeakToFootRatio ,
488+ factor )
443489
444490 self .clearUnwantedResults (maskedImage .mask , results )
445491
0 commit comments