22 from contextlib
import contextmanager
23 import lsst.pex.config
as pexConfig
30 __all__ = [
"InterpImageConfig",
"InterpImageTask"]
34 """Config for InterpImageTask
36 modelPsf = measAlg.GaussianPsfFactory.makeField(doc=
"Model Psf factory")
38 useFallbackValueAtEdge = pexConfig.Field(
40 doc=
"Smoothly taper to the fallback value at the edge of the image?",
43 fallbackValueType = pexConfig.ChoiceField(
45 doc=
"Type of statistic to calculate edge fallbackValue for interpolation",
49 "MEANCLIP":
"clipped mean",
50 "USER":
"user value set in fallbackUserValue config",
54 fallbackUserValue = pexConfig.Field(
56 doc=
"If fallbackValueType is 'USER' then use this as the fallbackValue; ignored otherwise",
59 negativeFallbackAllowed = pexConfig.Field(
61 doc=(
"Allow negative values for egde interpolation fallbackValue? If False, set "
62 "fallbackValue to max(fallbackValue, 0.0)"),
65 transpose = pexConfig.Field(dtype=int, default=
False,
66 doc=
"Transpose image before interpolating? "
67 "This allows the interpolation to act over columns instead of rows.")
70 pexConfig.Config.validate(self)
74 raise ValueError(
"User supplied fallbackValue is negative (%.2f) but "
79 """Interpolate over bad image pixels
81 ConfigClass = InterpImageConfig
82 _DefaultName =
"interpImage"
84 def _setFallbackValue(self, mi=None):
85 """Set the edge fallbackValue for interpolation
87 @param[in] mi input maksedImage on which to calculate the statistics
88 Must be provided if fallbackValueType != "USER".
90 @return fallbackValue The value set/computed based on the fallbackValueType
91 and negativeFallbackAllowed config parameters
93 if self.config.fallbackValueType !=
'USER':
94 assert mi,
"No maskedImage provided"
95 if self.config.fallbackValueType ==
'MEAN':
97 elif self.config.fallbackValueType ==
'MEDIAN':
99 elif self.config.fallbackValueType ==
'MEANCLIP':
101 elif self.config.fallbackValueType ==
'USER':
102 fallbackValue = self.config.fallbackUserValue
104 raise NotImplementedError(
"%s : %s not implemented" %
105 (
"fallbackValueType", self.config.fallbackValueType))
107 if not self.config.negativeFallbackAllowed
and fallbackValue < 0.0:
108 self.log.
warn(
"Negative interpolation edge fallback value computed but "
109 "negativeFallbackAllowed is False: setting fallbackValue to 0.0")
110 fallbackValue =
max(fallbackValue, 0.0)
112 self.log.
info(
"fallbackValueType %s has been set to %.4f" %
113 (self.config.fallbackValueType, fallbackValue))
118 def run(self, image, planeName=None, fwhmPixels=None, defects=None):
119 """!Interpolate in place over pixels in a maskedImage marked as bad
121 Pixels to be interpolated are set by either a mask planeName provided
122 by the caller OR a defects list of type `~lsst.meas.algorithms.Defects`
123 If both are provided an exception is raised.
125 Note that the interpolation code in meas_algorithms currently doesn't
126 use the input PSF (though it's a required argument), so it's not
127 important to set the input PSF parameters exactly. This PSF is set
128 here as the psf attached to the "image" (i.e if the image passed in
129 is an Exposure). Otherwise, a psf model is created using
130 measAlg.GaussianPsfFactory with the value of fwhmPixels (the value
131 passed in by the caller, or the default defaultFwhm set in
132 measAlg.GaussianPsfFactory if None).
134 @param[in,out] image MaskedImage OR Exposure to be interpolated
135 @param[in] planeName name of mask plane over which to interpolate
136 If None, must provide a defects list.
137 @param[in] fwhmPixels FWHM of core star (pixels)
138 If None the default is used, where the default
139 is set to the exposure psf if available
140 @param[in] defects List of defects of type measAlg.Defects
141 over which to interpolate.
144 maskedImage = image.getMaskedImage()
145 except AttributeError:
149 if planeName
is None:
151 raise ValueError(
"No defects or plane name provided")
153 if not isinstance(defects, measAlg.Defects):
154 defectList = measAlg.Defects(defects)
157 planeName =
"defects"
159 if defects
is not None:
160 raise ValueError(
"Provide EITHER a planeName OR a list of defects, not both")
161 if planeName
not in maskedImage.getMask().getMaskPlaneDict():
162 raise ValueError(
"maskedImage does not contain mask plane %s" % planeName)
163 defectList = measAlg.Defects.fromMask(maskedImage, planeName)
168 self.log.
info(
"Setting psf for interpolation from image")
169 except AttributeError:
170 self.log.
info(
"Creating psf model for interpolation from fwhm(pixels) = %s" %
171 (str(fwhmPixels)
if fwhmPixels
is not None else
172 (str(self.config.modelPsf.defaultFwhm)) +
" [default]"))
173 psf = self.config.modelPsf.apply(fwhm=fwhmPixels)
176 if self.config.useFallbackValueAtEdge:
181 self.log.
info(
"Interpolated over %d %s pixels." % (len(defectList), planeName))
185 """Context manager to potentially transpose an image
187 This applies the ``transpose`` configuration setting.
189 Transposing the image allows us to interpolate along columns instead
190 of rows, which is useful when the saturation trails are typically
191 oriented along rows on the warped/coadded images, instead of along
192 columns as they typically are in raw CCD images.
196 maskedImage : `lsst.afw.image.MaskedImage`
197 Image on which to perform interpolation.
198 defects : `lsst.meas.algorithms.Defects`
199 List of defects to interpolate over.
203 useImage : `lsst.afw.image.MaskedImage`
204 Image to use for interpolation; it may have been transposed.
205 useDefects : `lsst.meas.algorithms.Defects`
206 List of defects to use for interpolation; they may have been
209 def transposeImage(image):
210 """Transpose an image"""
211 transposed = image.array.T.copy()
212 return image.Factory(transposed,
False,
lsst.geom.Point2I(*reversed(image.getXY0())))
214 useImage = maskedImage
216 if self.config.transpose:
218 transposeImage(maskedImage.mask),
219 transposeImage(maskedImage.variance))
220 useDefects = defects.transpose()
221 yield useImage, useDefects
222 if self.config.transpose:
223 maskedImage.image.array = useImage.image.array.T
224 maskedImage.mask.array = useImage.mask.array.T
225 maskedImage.variance.array = useImage.variance.array.T
228 """Interpolate over defects in an image
232 maskedImage : `lsst.afw.image.MaskedImage`
233 Image on which to perform interpolation.
234 psf : `lsst.afw.detection.Psf`
235 Point-spread function; currently unused.
236 defectList : `lsst.meas.algorithms.Defects`
237 List of defects to interpolate over.
238 fallbackValue : `float`
239 Value to set when interpolation fails.
244 measAlg.interpolateOverDefects(image, psf, defects, fallbackValue,
245 self.config.useFallbackValueAtEdge)