22 from contextlib
import contextmanager
31 __all__ = [
"InterpImageConfig",
"InterpImageTask"]
35 """Config for InterpImageTask 37 modelPsf = measAlg.GaussianPsfFactory.makeField(doc=
"Model Psf factory")
39 useFallbackValueAtEdge = pexConfig.Field(
41 doc=
"Smoothly taper to the fallback value at the edge of the image?",
44 fallbackValueType = pexConfig.ChoiceField(
46 doc=
"Type of statistic to calculate edge fallbackValue for interpolation",
50 "MEANCLIP":
"clipped mean",
51 "USER":
"user value set in fallbackUserValue config",
55 fallbackUserValue = pexConfig.Field(
57 doc=
"If fallbackValueType is 'USER' then use this as the fallbackValue; ignored otherwise",
60 negativeFallbackAllowed = pexConfig.Field(
62 doc=(
"Allow negative values for egde interpolation fallbackValue? If False, set " 63 "fallbackValue to max(fallbackValue, 0.0)"),
66 transpose = pexConfig.Field(dtype=int, default=
False,
67 doc=
"Transpose image before interpolating? " 68 "This allows the interpolation to act over columns instead of rows.")
71 pexConfig.Config.validate(self)
75 raise ValueError(
"User supplied fallbackValue is negative (%.2f) but " 80 """Interpolate over bad image pixels 82 ConfigClass = InterpImageConfig
83 _DefaultName =
"interpImage" 85 def _setFallbackValue(self, mi=None):
86 """Set the edge fallbackValue for interpolation 88 @param[in] mi input maksedImage on which to calculate the statistics 89 Must be provided if fallbackValueType != "USER". 91 @return fallbackValue The value set/computed based on the fallbackValueType 92 and negativeFallbackAllowed config parameters 94 if self.config.fallbackValueType !=
'USER':
95 assert mi,
"No maskedImage provided" 96 if self.config.fallbackValueType ==
'MEAN':
97 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEAN).getValue()
98 elif self.config.fallbackValueType ==
'MEDIAN':
99 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEDIAN).getValue()
100 elif self.config.fallbackValueType ==
'MEANCLIP':
101 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEANCLIP).getValue()
102 elif self.config.fallbackValueType ==
'USER':
103 fallbackValue = self.config.fallbackUserValue
105 raise NotImplementedError(
"%s : %s not implemented" %
106 (
"fallbackValueType", self.config.fallbackValueType))
108 if not self.config.negativeFallbackAllowed
and fallbackValue < 0.0:
109 self.log.warn(
"Negative interpolation edge fallback value computed but " 110 "negativeFallbackAllowed is False: setting fallbackValue to 0.0")
111 fallbackValue = max(fallbackValue, 0.0)
113 self.log.info(
"fallbackValueType %s has been set to %.4f" %
114 (self.config.fallbackValueType, fallbackValue))
119 def run(self, image, planeName=None, fwhmPixels=None, defects=None):
120 """!Interpolate in place over pixels in a maskedImage marked as bad 122 Pixels to be interpolated are set by either a mask planeName provided 123 by the caller OR a defects list of type measAlg.DefectListT. If both 124 are provided an exception is raised. 126 Note that the interpolation code in meas_algorithms currently doesn't 127 use the input PSF (though it's a required argument), so it's not 128 important to set the input PSF parameters exactly. This PSF is set 129 here as the psf attached to the "image" (i.e if the image passed in 130 is an Exposure). Otherwise, a psf model is created using 131 measAlg.GaussianPsfFactory with the value of fwhmPixels (the value 132 passed in by the caller, or the default defaultFwhm set in 133 measAlg.GaussianPsfFactory if None). 135 @param[in,out] image MaskedImage OR Exposure to be interpolated 136 @param[in] planeName name of mask plane over which to interpolate 137 If None, must provide a defects list. 138 @param[in] fwhmPixels FWHM of core star (pixels) 139 If None the default is used, where the default 140 is set to the exposure psf if available 141 @param[in] defects List of defects of type measAlg.DefectListT 142 over which to interpolate. 145 maskedImage = image.getMaskedImage()
146 except AttributeError:
150 if planeName
is None:
152 raise ValueError(
"No defects or plane name provided")
155 planeName =
"defects" 157 if defects
is not None:
158 raise ValueError(
"Provide EITHER a planeName OR a list of defects, not both")
159 if planeName
not in maskedImage.getMask().getMaskPlaneDict():
160 raise ValueError(
"maskedImage does not contain mask plane %s" % planeName)
161 defectList = ipIsr.getDefectListFromMask(maskedImage, planeName)
166 self.log.info(
"Setting psf for interpolation from image")
167 except AttributeError:
168 self.log.info(
"Creating psf model for interpolation from fwhm(pixels) = %s" %
169 (str(fwhmPixels)
if fwhmPixels
is not None else 170 (str(self.config.modelPsf.defaultFwhm)) +
" [default]"))
171 psf = self.config.modelPsf.apply(fwhm=fwhmPixels)
174 if self.config.useFallbackValueAtEdge:
179 self.log.info(
"Interpolated over %d %s pixels." % (len(defectList), planeName))
183 """Context manager to potentially transpose an image 185 This applies the ``transpose`` configuration setting. 187 Transposing the image allows us to interpolate along columns instead 188 of rows, which is useful when the saturation trails are typically 189 oriented along rows on the warped/coadded images, instead of along 190 columns as they typically are in raw CCD images. 194 maskedImage : `lsst.afw.image.MaskedImage` 195 Image on which to perform interpolation. 196 defects : iterable of `lsst.afw.image.Defect` 197 List of defects to interpolate over. 201 useImage : `lsst.afw.image.MaskedImage` 202 Image to use for interpolation; it may have been transposed. 203 useDefects : iterable of `lsst.afw.image.Defect` 204 List of defects to use for interpolation; they may have been 207 def transposeImage(image):
208 """Transpose an image""" 209 transposed = image.array.T.copy()
210 return image.Factory(transposed,
False,
lsst.geom.Point2I(*reversed(image.getXY0())))
212 useImage = maskedImage
214 if self.config.transpose:
215 useImage = afwImage.makeMaskedImage(transposeImage(maskedImage.image),
216 transposeImage(maskedImage.mask),
217 transposeImage(maskedImage.variance))
218 useDefects = ipIsr.transposeDefectList(defects)
219 yield useImage, useDefects
220 if self.config.transpose:
221 maskedImage.image.array = useImage.image.array.T
222 maskedImage.mask.array = useImage.mask.array.T
223 maskedImage.variance.array = useImage.variance.array.T
226 """Interpolate over defects in an image 230 maskedImage : `lsst.afw.image.MaskedImage` 231 Image on which to perform interpolation. 232 psf : `lsst.afw.detection.Psf` 233 Point-spread function; currently unused. 234 defectList : iterable of `lsst.afw.image.Defect` 235 List of defects to interpolate over. 236 fallbackValue : `float` 237 Value to set when interpolation fails. 242 measAlg.interpolateOverDefects(image, psf, defects, fallbackValue,
243 self.config.useFallbackValueAtEdge)
def _setFallbackValue(self, mi=None)
def transposeContext(self, maskedImage, defects)
def run(self, image, planeName=None, fwhmPixels=None, defects=None)
Interpolate in place over pixels in a maskedImage marked as bad.
def interpolateImage(self, maskedImage, psf, defectList, fallbackValue)