23 Apply intra-CCD crosstalk corrections 25 from __future__
import absolute_import, division, print_function
27 __all__ = [
"CrosstalkConfig",
"CrosstalkTask",
"subtractCrosstalk"]
29 from builtins
import zip
42 """Configuration for intra-CCD crosstalk removal""" 43 minPixelToMask = Field(dtype=float, default=45000,
44 doc=
"Set crosstalk mask plane for pixels over this value")
45 crosstalkMaskPlane = Field(dtype=str, default=
"CROSSTALK", doc=
"Name for crosstalk mask plane")
49 """Apply intra-CCD crosstalk correction""" 50 ConfigClass = CrosstalkConfig
52 def run(self, exposure):
53 """Apply intra-CCD crosstalk correction 57 exposure : `lsst.afw.image.Exposure` 58 Exposure for which to remove crosstalk. 60 detector = exposure.getDetector()
61 if not detector.hasCrosstalk():
62 self.log.warn(
"Crosstalk correction skipped: no crosstalk coefficients for detector")
64 self.log.info(
"Applying crosstalk correction")
65 numAmps = len(exposure.getDetector())
67 crosstalkStr=self.config.crosstalkMaskPlane)
72 X_FLIP = {lsst.afw.table.LL:
False, lsst.afw.table.LR:
True,
73 lsst.afw.table.UL:
False, lsst.afw.table.UR:
True}
74 Y_FLIP = {lsst.afw.table.LL:
False, lsst.afw.table.LR:
False,
75 lsst.afw.table.UL:
True, lsst.afw.table.UR:
True}
79 """Return an image of the amp 81 The returned image will have the amp's readout corner in the 86 image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 87 Image containing the amplifier of interest. 88 amp : `lsst.afw.table.AmpInfoRecord` 89 Amplifier information. 90 corner : `lsst.afw.table.ReadoutCorner` or `None` 91 Corner in which to put the amp's readout corner, or `None` for 96 output : `lsst.afw.image.Image` 97 Image of the amplifier in the standard configuration. 99 output = image.Factory(image, amp.getBBox())
100 ampCorner = amp.getReadoutCorner()
102 xFlip = X_FLIP[corner] ^ X_FLIP[ampCorner]
103 yFlip = Y_FLIP[corner] ^ Y_FLIP[ampCorner]
108 """Calculate median background in image 110 Getting a great background model isn't important for crosstalk correction, 111 since the crosstalk is at a low level. The median should be sufficient. 115 mi : `lsst.afw.image.MaskedImage` 116 MaskedImage for which to measure background. 117 badPixels : `list` of `str` 118 Mask planes to ignore. 123 Median background level. 127 stats.setAndMask(mask.getPlaneBitMask(badPixels))
131 def subtractCrosstalk(exposure, badPixels=["BAD"], minPixelToMask=45000, crosstalkStr="CROSSTALK"):
132 """Subtract the intra-CCD crosstalk from an exposure 134 We set the mask plane indicated by ``crosstalkStr`` in a target amplifier 135 for pixels in a source amplifier that exceed `minPixelToMask`. Note that 136 the correction is applied to all pixels in the amplifier, but only those 137 that have a substantial crosstalk are masked with ``crosstalkStr``. 139 The uncorrected image is used as a template for correction. This is good 140 enough if the crosstalk is small (e.g., coefficients < ~ 1e-3), but if it's 141 larger you may want to iterate. 145 exposure : `lsst.afw.image.Exposure` 146 Exposure for which to subtract crosstalk. 147 badPixels : `list` of `str` 148 Mask planes to ignore. 149 minPixelToMask : `float` 150 Minimum pixel value in source amplifier for which to set 151 ``crosstalkStr`` mask plane in target amplifier. 153 Mask plane name for pixels greatly modified by crosstalk. 155 mi = exposure.getMaskedImage()
158 ccd = exposure.getDetector()
160 coeffs = ccd.getCrosstalk()
161 assert coeffs.shape == (numAmps, numAmps)
164 crosstalkPlane = mask.addMaskPlane(crosstalkStr)
166 footprints.setMask(mask, crosstalkStr)
167 crosstalk = mask.getPlaneBitMask(crosstalkStr)
169 backgrounds = [
calculateBackground(mi.Factory(mi, amp.getBBox()), badPixels)
for amp
in ccd]
171 subtrahend = mi.Factory(mi.getBBox())
172 subtrahend.set((0, 0, 0))
173 for ii, iAmp
in enumerate(ccd):
174 iImage = subtrahend.Factory(subtrahend, iAmp.getBBox())
175 for jj, jAmp
in enumerate(ccd):
177 assert coeffs[ii, jj] == 0.0
178 if coeffs[ii, jj] == 0.0:
181 jImage =
extractAmp(mi, jAmp, iAmp.getReadoutCorner())
182 jImage.getMask().getArray()[:] &= crosstalk
183 jImage -= backgrounds[jj]
185 iImage.scaledPlus(coeffs[ii, jj], jImage)
189 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"])