From 35dcd12eff286b73fcdb051a8672887c9dec1cc2 Mon Sep 17 00:00:00 2001 From: Ian Sullivan Date: Tue, 3 Dec 2024 16:24:06 -0800 Subject: [PATCH 1/4] Add optional config to limit streak mask width --- python/lsst/meas/algorithms/maskStreaks.py | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/python/lsst/meas/algorithms/maskStreaks.py b/python/lsst/meas/algorithms/maskStreaks.py index 2da63293..8528a8e2 100644 --- a/python/lsst/meas/algorithms/maskStreaks.py +++ b/python/lsst/meas/algorithms/maskStreaks.py @@ -145,7 +145,7 @@ def __init__(self, data, weights, line=None): self.mask = (weights != 0) self._initLine = line - self.setLineMask(line) + self.setLineMask(line, maxStreakWidth=0) def getLineXY(self, line): """Return the pixel coordinates of the ends of the line. @@ -191,7 +191,7 @@ def getLineXY(self, line): return boxIntersections - def setLineMask(self, line): + def setLineMask(self, line, maxStreakWidth, logger=None): """Set mask around the image region near the line. Parameters @@ -203,7 +203,14 @@ def setLineMask(self, line): # Only fit pixels within 5 sigma of the estimated line radtheta = np.deg2rad(line.theta) distance = (np.cos(radtheta) * self._xmesh + np.sin(radtheta) * self._ymesh - line.rho) - m = (abs(distance) < 5 * line.sigma) + + width = 2 * 5 * line.sigma + if (maxStreakWidth > 0) and (maxStreakWidth < width): + if logger is not None: + logger.info("Line with width %d exceeded maximum configured width of %d", + width, maxStreakWidth) + width = maxStreakWidth + m = (abs(distance) < width/2) self.lineMask = self.mask & m else: self.lineMask = np.copy(self.mask) @@ -490,6 +497,14 @@ class MaskStreaksConfig(pexConfig.Config): dtype=str, default=("NO_DATA", "INTRP", "BAD", "SAT", "EDGE"), ) + maxStreakWidth = pexConfig.Field( + doc="Maximum width in pixels to allow for masking a streak." + "The fit streak parameters will not be modified, and a warning will " + "be issued if the fitted width is larger than this value." + "Set to 0 to disable.", + dtype=float, + default=0., + ) class MaskStreaksTask(pipeBase.Task): @@ -757,7 +772,7 @@ def _fitProfile(self, lines, maskedImage): continue # Make mask - lineModel.setLineMask(fit) + lineModel.setLineMask(fit, self.config.maxStreakWidth, logger=self.log) finalModel = lineModel.makeProfile(fit) # Take absolute value, as streaks are allowed to be negative finalModelMax = abs(finalModel).max() From 1eb4baf0d067d8949896e6eb482c822db2689514 Mon Sep 17 00:00:00 2001 From: Ian Sullivan Date: Tue, 3 Dec 2024 18:19:58 -0800 Subject: [PATCH 2/4] Make nSigma of width of line to mask configurable. --- python/lsst/meas/algorithms/maskStreaks.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/python/lsst/meas/algorithms/maskStreaks.py b/python/lsst/meas/algorithms/maskStreaks.py index 8528a8e2..e8f9e2bb 100644 --- a/python/lsst/meas/algorithms/maskStreaks.py +++ b/python/lsst/meas/algorithms/maskStreaks.py @@ -145,7 +145,7 @@ def __init__(self, data, weights, line=None): self.mask = (weights != 0) self._initLine = line - self.setLineMask(line, maxStreakWidth=0) + self.setLineMask(line, maxStreakWidth=0, nSigmaMask=5) def getLineXY(self, line): """Return the pixel coordinates of the ends of the line. @@ -191,7 +191,7 @@ def getLineXY(self, line): return boxIntersections - def setLineMask(self, line, maxStreakWidth, logger=None): + def setLineMask(self, line, maxStreakWidth, nSigmaMask, logger=None): """Set mask around the image region near the line. Parameters @@ -200,11 +200,11 @@ def setLineMask(self, line, maxStreakWidth, logger=None): Parameters of line in the image. """ if line: - # Only fit pixels within 5 sigma of the estimated line + # Only fit pixels within nSigmaMask * sigma of the estimated line radtheta = np.deg2rad(line.theta) distance = (np.cos(radtheta) * self._xmesh + np.sin(radtheta) * self._ymesh - line.rho) - width = 2 * 5 * line.sigma + width = 2 * nSigmaMask * line.sigma if (maxStreakWidth > 0) and (maxStreakWidth < width): if logger is not None: logger.info("Line with width %d exceeded maximum configured width of %d", @@ -444,6 +444,11 @@ class MaskStreaksConfig(pexConfig.Config): dtype=float, default=2, ) + nSigmaMask = pexConfig.Field( + doc="Number of sigmas from center of kernel to mask", + dtype=float, + default=5, + ) rhoBinSize = pexConfig.Field( doc="Binsize in pixels for position parameter rho when finding " "clusters of detected lines", @@ -772,7 +777,7 @@ def _fitProfile(self, lines, maskedImage): continue # Make mask - lineModel.setLineMask(fit, self.config.maxStreakWidth, logger=self.log) + lineModel.setLineMask(fit, self.config.maxStreakWidth, self.config.nSigmaMask, logger=self.log) finalModel = lineModel.makeProfile(fit) # Take absolute value, as streaks are allowed to be negative finalModelMax = abs(finalModel).max() From 6c470209092a6954881708739076dd7a87734334 Mon Sep 17 00:00:00 2001 From: Ian Sullivan Date: Thu, 5 Dec 2024 19:22:52 -0800 Subject: [PATCH 3/4] Add configurable limit on the number of streak fitting iterations --- python/lsst/meas/algorithms/maskStreaks.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/lsst/meas/algorithms/maskStreaks.py b/python/lsst/meas/algorithms/maskStreaks.py index e8f9e2bb..329ca431 100644 --- a/python/lsst/meas/algorithms/maskStreaks.py +++ b/python/lsst/meas/algorithms/maskStreaks.py @@ -479,6 +479,12 @@ class MaskStreaksConfig(pexConfig.Config): dtype=float, default=0.1 ) + maxFitIter = pexConfig.Field( + doc="Maximum number of line profile fitting iterations that is " + "acceptable for convergence", + dtype=int, + default=100 + ) detectedMaskPlane = pexConfig.Field( doc="Name of mask with pixels above detection threshold, used for first" "estimate of streak locations", @@ -763,7 +769,8 @@ def _fitProfile(self, lines, maskedImage): if lineModel.lineMaskSize == 0: continue - fit, fitFailure = lineModel.fit(dChi2Tol=self.config.dChi2Tolerance, log=self.log) + fit, fitFailure = lineModel.fit(dChi2Tol=self.config.dChi2Tolerance, log=self.log, + maxIter=self.config.maxFitIter) # Initial estimate should be quite close: fit is deemed unsuccessful if rho or theta # change more than the allowed bin in rho or theta: From e217f3668abe8ea81d11b9761745811e8bc984fd Mon Sep 17 00:00:00 2001 From: Ian Sullivan Date: Wed, 11 Dec 2024 10:36:58 -0800 Subject: [PATCH 4/4] Update gitignore to actually exclude .coverage files --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f4c85d94..b249c02a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,4 @@ python/lsst/meas/algorithms/version.py .cache .pytest_cache pytest_session.txt -.coverage +.coverage*