22__all__ = [
"InterpImageConfig",
"InterpImageTask"]
24from contextlib
import contextmanager
32from lsst.utils.timer
import timeMethod
36 """Config for InterpImageTask
38 modelPsf = measAlg.GaussianPsfFactory.makeField(doc="Model Psf factory")
40 useFallbackValueAtEdge = pexConfig.Field(
42 doc=
"Smoothly taper to the fallback value at the edge of the image?",
45 fallbackValueType = pexConfig.ChoiceField(
47 doc=
"Type of statistic to calculate edge fallbackValue for interpolation",
51 "MEANCLIP":
"clipped mean",
52 "USER":
"user value set in fallbackUserValue config",
56 fallbackUserValue = pexConfig.Field(
58 doc=
"If fallbackValueType is 'USER' then use this as the fallbackValue; ignored otherwise",
61 negativeFallbackAllowed = pexConfig.Field(
63 doc=(
"Allow negative values for egde interpolation fallbackValue? If False, set "
64 "fallbackValue to max(fallbackValue, 0.0)"),
67 transpose = pexConfig.Field(dtype=int, default=
False,
68 doc=
"Transpose image before interpolating? "
69 "This allows the interpolation to act over columns instead of rows.")
72 pexConfig.Config.validate(self)
76 raise ValueError(
"User supplied fallbackValue is negative (%.2f) but "
81 """Interpolate over bad image pixels
83 ConfigClass = InterpImageConfig
84 _DefaultName = "interpImage"
86 def _setFallbackValue(self, mi=None):
87 """Set the edge fallbackValue for interpolation
92 Input maskedImage on which to calculate the statistics
93 Must be provided if fallbackValueType !=
"USER".
97 fallbackValue : `float`
98 The value set/computed based on the fallbackValueType
99 and negativeFallbackAllowed config parameters.
101 if self.config.fallbackValueType !=
'USER':
102 assert mi,
"No maskedImage provided"
103 if self.config.fallbackValueType ==
'MEAN':
105 elif self.config.fallbackValueType ==
'MEDIAN':
107 elif self.config.fallbackValueType ==
'MEANCLIP':
109 elif self.config.fallbackValueType ==
'USER':
110 fallbackValue = self.config.fallbackUserValue
112 raise NotImplementedError(
"%s : %s not implemented" %
113 (
"fallbackValueType", self.config.fallbackValueType))
115 if not self.config.negativeFallbackAllowed
and fallbackValue < 0.0:
116 self.log.warning(
"Negative interpolation edge fallback value computed but "
117 "negativeFallbackAllowed is False: setting fallbackValue to 0.0")
118 fallbackValue =
max(fallbackValue, 0.0)
120 self.log.info(
"fallbackValueType %s has been set to %.4f",
121 self.config.fallbackValueType, fallbackValue)
126 def run(self, image, planeName=None, fwhmPixels=None, defects=None):
127 """Interpolate in place over pixels in a maskedImage marked as bad
129 Pixels to be interpolated are set by either a mask planeName provided
130 by the caller OR a defects list of type `~lsst.meas.algorithms.Defects`
131 If both are provided an exception is raised.
133 Note that the interpolation code
in meas_algorithms currently doesn
't
134 use the input PSF (though it's a required argument), so it's
not
135 important to set the input PSF parameters exactly. This PSF
is set
136 here
as the psf attached to the
"image" (i.e
if the image passed
in
137 is an Exposure). Otherwise, a psf model
is created using
138 measAlg.GaussianPsfFactory
with the value of fwhmPixels (the value
139 passed
in by the caller,
or the default defaultFwhm set
in
140 measAlg.GaussianPsfFactory
if None).
145 MaskedImage OR Exposure to be interpolated.
146 planeName : `str`, optional
147 Name of mask plane over which to interpolate.
148 If
None, must provide a defects list.
149 fwhmPixels : `int`, optional
150 FWHM of core star (pixels).
151 If
None the default
is used, where the default
152 is set to the exposure psf
if available.
153 defects : `lsst.meas.algorithms.Defects`, optional
154 List of defects of type ipIsr.Defects
155 over which to interpolate.
158 maskedImage = image.getMaskedImage()
159 except AttributeError:
163 if planeName
is None:
165 raise ValueError(
"No defects or plane name provided")
167 if not isinstance(defects, ipIsr.Defects):
168 defectList = ipIsr.Defects(defects)
171 planeName =
"defects"
173 if defects
is not None:
174 raise ValueError(
"Provide EITHER a planeName OR a list of defects, not both")
175 if planeName
not in maskedImage.getMask().getMaskPlaneDict():
176 raise ValueError(
"maskedImage does not contain mask plane %s" % planeName)
177 defectList = ipIsr.Defects.fromMask(maskedImage, planeName)
182 self.log.info(
"Setting psf for interpolation from image")
183 except AttributeError:
184 self.log.info(
"Creating psf model for interpolation from fwhm(pixels) = %s",
185 str(fwhmPixels)
if fwhmPixels
is not None else
186 (
str(self.config.modelPsf.defaultFwhm)) +
" [default]")
187 psf = self.config.modelPsf.apply(fwhm=fwhmPixels)
190 if self.config.useFallbackValueAtEdge:
195 self.log.info(
"Interpolated over %d %s pixels.", len(defectList), planeName)
199 """Context manager to potentially transpose an image
201 This applies the ``transpose`` configuration setting.
203 Transposing the image allows us to interpolate along columns instead
204 of rows, which is useful when the saturation trails are typically
205 oriented along rows on the warped/coadded images, instead of along
206 columns
as they typically are
in raw CCD images.
211 Image on which to perform interpolation.
212 defects : `lsst.meas.algorithms.Defects`
213 List of defects to interpolate over.
218 Image to use
for interpolation; it may have been transposed.
219 useDefects : `lsst.meas.algorithms.Defects`
220 List of defects to use
for interpolation; they may have been
223 def transposeImage(image):
224 """Transpose an image
230 transposed = image.array.T.copy()
231 return image.Factory(transposed,
False,
lsst.geom.Point2I(*reversed(image.getXY0())))
233 useImage = maskedImage
235 if self.config.transpose:
237 transposeImage(maskedImage.mask),
238 transposeImage(maskedImage.variance))
239 useDefects = defects.transpose()
240 yield useImage, useDefects
241 if self.config.transpose:
242 maskedImage.image.array = useImage.image.array.T
243 maskedImage.mask.array = useImage.mask.array.T
244 maskedImage.variance.array = useImage.variance.array.T
247 """Interpolate over defects in an image
252 Image on which to perform interpolation.
254 Point-spread function; currently unused.
255 defectList : `lsst.meas.algorithms.Defects`
256 List of defects to interpolate over.
257 fallbackValue : `float`
258 Value to set when interpolation fails.
263 measAlg.interpolateOverDefects(image, psf, defects, fallbackValue,
264 self.config.useFallbackValueAtEdge)
A polymorphic base class for representing an image's Point Spread Function.
A class to manipulate images, masks, and variance as a single object.
def interpolateImage(self, maskedImage, psf, defectList, fallbackValue)
def _setFallbackValue(self, mi=None)
def transposeContext(self, maskedImage, defects)
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT > > image, typename std::shared_ptr< Mask< MaskPixelT > > mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT > > variance=Image< VariancePixelT >())
A function to return a MaskedImage of the correct type (cf.
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)