23 Apply intra-CCD crosstalk corrections 32 __all__ = [
"CrosstalkConfig",
"CrosstalkTask",
"subtractCrosstalk"]
36 """Configuration for intra-CCD crosstalk removal""" 37 minPixelToMask = Field(dtype=float, default=45000,
38 doc=
"Set crosstalk mask plane for pixels over this value")
39 crosstalkMaskPlane = Field(dtype=str, default=
"CROSSTALK", doc=
"Name for crosstalk mask plane")
43 """Apply intra-CCD crosstalk correction""" 44 ConfigClass = CrosstalkConfig
47 """Placeholder for crosstalk preparation method, e.g., for inter-CCD crosstalk. 51 lsst.obs.decam.crosstalk.DecamCrosstalkTask.prepCrosstalk 55 def run(self, exposure, crosstalkSources=None):
56 """Apply intra-CCD crosstalk correction 60 exposure : `lsst.afw.image.Exposure` 61 Exposure for which to remove crosstalk. 62 crosstalkSources : `defaultdict`, optional 63 Image data and crosstalk coefficients from other CCDs/amps that are 64 sources of crosstalk in exposure. 65 The default for intra-CCD crosstalk here is None. 67 detector = exposure.getDetector()
68 if not detector.hasCrosstalk():
69 self.log.warn(
"Crosstalk correction skipped: no crosstalk coefficients for detector")
71 self.log.info(
"Applying crosstalk correction")
73 crosstalkStr=self.config.crosstalkMaskPlane)
78 X_FLIP = {lsst.afw.table.LL:
False, lsst.afw.table.LR:
True,
79 lsst.afw.table.UL:
False, lsst.afw.table.UR:
True}
80 Y_FLIP = {lsst.afw.table.LL:
False, lsst.afw.table.LR:
False,
81 lsst.afw.table.UL:
True, lsst.afw.table.UR:
True}
85 """Return an image of the amp 87 The returned image will have the amp's readout corner in the 92 image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 93 Image containing the amplifier of interest. 94 amp : `lsst.afw.table.AmpInfoRecord` 95 Amplifier information. 96 corner : `lsst.afw.table.ReadoutCorner` or `None` 97 Corner in which to put the amp's readout corner, or `None` for 102 output : `lsst.afw.image.Image` 103 Image of the amplifier in the standard configuration. 105 output = image.Factory(image, amp.getBBox())
106 ampCorner = amp.getReadoutCorner()
108 xFlip = X_FLIP[corner] ^ X_FLIP[ampCorner]
109 yFlip = Y_FLIP[corner] ^ Y_FLIP[ampCorner]
114 """Calculate median background in image 116 Getting a great background model isn't important for crosstalk correction, 117 since the crosstalk is at a low level. The median should be sufficient. 121 mi : `lsst.afw.image.MaskedImage` 122 MaskedImage for which to measure background. 123 badPixels : `list` of `str` 124 Mask planes to ignore. 129 Median background level. 133 stats.setAndMask(mask.getPlaneBitMask(badPixels))
137 def subtractCrosstalk(exposure, badPixels=["BAD"], minPixelToMask=45000, crosstalkStr="CROSSTALK"):
138 """Subtract the intra-CCD crosstalk from an exposure 140 We set the mask plane indicated by ``crosstalkStr`` in a target amplifier 141 for pixels in a source amplifier that exceed `minPixelToMask`. Note that 142 the correction is applied to all pixels in the amplifier, but only those 143 that have a substantial crosstalk are masked with ``crosstalkStr``. 145 The uncorrected image is used as a template for correction. This is good 146 enough if the crosstalk is small (e.g., coefficients < ~ 1e-3), but if it's 147 larger you may want to iterate. 151 exposure : `lsst.afw.image.Exposure` 152 Exposure for which to subtract crosstalk. 153 badPixels : `list` of `str` 154 Mask planes to ignore. 155 minPixelToMask : `float` 156 Minimum pixel value in source amplifier for which to set 157 ``crosstalkStr`` mask plane in target amplifier. 159 Mask plane name for pixels greatly modified by crosstalk. 161 mi = exposure.getMaskedImage()
164 ccd = exposure.getDetector()
166 coeffs = ccd.getCrosstalk()
167 assert coeffs.shape == (numAmps, numAmps)
170 crosstalkPlane = mask.addMaskPlane(crosstalkStr)
172 footprints.setMask(mask, crosstalkStr)
173 crosstalk = mask.getPlaneBitMask(crosstalkStr)
175 backgrounds = [
calculateBackground(mi.Factory(mi, amp.getBBox()), badPixels)
for amp
in ccd]
177 subtrahend = mi.Factory(mi.getBBox())
178 subtrahend.set((0, 0, 0))
179 for ii, iAmp
in enumerate(ccd):
180 iImage = subtrahend.Factory(subtrahend, iAmp.getBBox())
181 for jj, jAmp
in enumerate(ccd):
183 assert coeffs[ii, jj] == 0.0
184 if coeffs[ii, jj] == 0.0:
187 jImage =
extractAmp(mi, jAmp, iAmp.getReadoutCorner())
188 jImage.getMask().getArray()[:] &= crosstalk
189 jImage -= backgrounds[jj]
191 iImage.scaledPlus(coeffs[ii, jj], jImage)
195 mask.clearMaskPlane(crosstalkPlane)
def subtractCrosstalk(exposure, badPixels=["BAD"], minPixelToMask=45000, crosstalkStr="CROSSTALK")
def extractAmp(image, amp, corner)
std::shared_ptr< ImageT > flipImage(ImageT const &inImage, bool flipLR, bool flipTB)
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
def calculateBackground(mi, badPixels=["BAD"])
def run(self, exposure, crosstalkSources=None)
def prepCrosstalk(self, dataRef)