Skip to content

Commit 3bed600

Browse files
estevesjhmfisherlevine
authored andcommitted
Use percentile instead of median for column bias subtraction
As suggested by Robert, use a low percentile (default 10th) instead of the median for column bias estimation. Stars and trails are very unlikely to live in the 10th percentile, which avoids the dark dip artifacts created by the median being pulled by bright sources. The percentile is slightly noisier but eliminates the dark bands. Added biasPercentile config option to GuiderReader.get() and processStamps() to allow tuning the percentile value.
1 parent dcea84d commit 3bed600

1 file changed

Lines changed: 23 additions & 10 deletions

File tree

‎python/lsst/summit/utils/guiders/reading.py‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ def get(
701701
seqNum: int,
702702
doSubtractMedian: bool = True,
703703
columnMaskK: float = 50.0,
704+
biasPercentile: float = 10.0,
704705
scienceDetNum: int = 94,
705706
) -> GuiderData:
706707
"""
@@ -713,9 +714,12 @@ def get(
713714
seqNum : `int`
714715
Sequence number.
715716
doSubtractMedian : `bool`, optional
716-
If True, subtract median row bias from each stamp.
717+
If True, subtract column bias from each stamp.
717718
columnMaskK : `float`, optional
718719
Threshold factor for column mask detection.
720+
biasPercentile : `float`, optional
721+
Percentile (0-100) for column bias estimation.
722+
Lower values avoid star/trail contamination.
719723
scienceDetNum : `int`, optional
720724
Science detector number for WCS reference.
721725
@@ -748,6 +752,7 @@ def get(
748752
rawStampsDict,
749753
doSubtractMedian,
750754
columnMaskK,
755+
biasPercentile,
751756
)
752757
guiderData = GuiderData(
753758
seqNum=seqNum,
@@ -797,19 +802,22 @@ def processStamps(
797802
rawStampsDict: dict[str, Stamps],
798803
doSubtractMedian: bool,
799804
columnMaskK: float,
805+
biasPercentile: float = 10.0,
800806
) -> dict[str, Stamps]:
801807
"""
802-
Apply median row bias subtraction and per-stamp column masking.
808+
Apply column bias subtraction and per-stamp column masking.
803809
804810
805811
Parameters
806812
----------
807813
rawStampsDict : `dict[str, Stamps]`
808814
ROI view of stamps from butler `guider_raw`.
809815
doSubtractMedian : `bool`, optional
810-
If True, subtract median row bias.
816+
If True, subtract column bias.
811817
columnMaskK : `float`, optional
812818
Threshold factor for column mask detection.
819+
biasPercentile : `float`, optional
820+
Percentile for column bias estimation.
813821
814822
Returns
815823
-------
@@ -829,23 +837,28 @@ def processStamps(
829837
# Work on a copy - never modify original
830838
data = stamps[i].stamp_im.image.array.copy()
831839

832-
# Compute median row bias
833-
medianRows = np.nanmedian(data, axis=0)
840+
# Compute column bias using low percentile to avoid
841+
# star contamination (median pulls dark dips at star cols).
842+
percRows = np.nanpercentile(data, biasPercentile, axis=0)
843+
rPerc = np.nanpercentile(data, biasPercentile)
834844
medianValue = np.nanmedian(data)
835-
# Replace NaN medians (fully masked columns) with global median
836-
medianRows = np.where(np.isnan(medianRows), medianValue, medianRows)
845+
# Replace NaN values (fully masked columns) with global median
846+
percRows = np.where(np.isnan(percRows), medianValue, percRows)
837847

838848
# Compute column mask on bias-subtracted data
839-
colMask = getColumnMask(data - medianRows[np.newaxis, :], k=columnMaskK)
849+
colMask = getColumnMask(
850+
data - percRows[np.newaxis, :] - (rPerc - medianValue),
851+
k=columnMaskK,
852+
)
840853

841854
# Create mask array for MaskedImageF (BAD=1 for masked cols)
842855
nRows, nCols = data.shape
843856
maskArray = np.zeros((nRows, nCols), dtype=np.uint32)
844857
maskArray[colMask] = 1 # Set BAD bit for masked columns
845858

846-
# Apply median row bias subtraction
859+
# Apply column bias subtraction
847860
if doSubtractMedian:
848-
data = data - medianRows[np.newaxis, :]
861+
data = data - percRows[np.newaxis, :] - (rPerc - medianValue)
849862

850863
# Fill masked columns with global median
851864
if colMask.any():

0 commit comments

Comments
 (0)