22 from contextlib
import contextmanager
30 from lsst.utils.timer
import timeMethod
32 __all__ = [
"InterpImageConfig",
"InterpImageTask"]
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
89 @param[in] mi input maksedImage on which to calculate the statistics
90 Must be provided if fallbackValueType != "USER".
92 @return fallbackValue The value set/computed based on the fallbackValueType
93 and negativeFallbackAllowed config parameters
95 if self.config.fallbackValueType !=
'USER':
96 assert mi,
"No maskedImage provided"
97 if self.config.fallbackValueType ==
'MEAN':
99 elif self.config.fallbackValueType ==
'MEDIAN':
101 elif self.config.fallbackValueType ==
'MEANCLIP':
103 elif self.config.fallbackValueType ==
'USER':
104 fallbackValue = self.config.fallbackUserValue
106 raise NotImplementedError(
"%s : %s not implemented" %
107 (
"fallbackValueType", self.config.fallbackValueType))
109 if not self.config.negativeFallbackAllowed
and fallbackValue < 0.0:
110 self.log.
warning(
"Negative interpolation edge fallback value computed but "
111 "negativeFallbackAllowed is False: setting fallbackValue to 0.0")
112 fallbackValue =
max(fallbackValue, 0.0)
114 self.log.
info(
"fallbackValueType %s has been set to %.4f",
115 self.config.fallbackValueType, fallbackValue)
120 def run(self, image, planeName=None, fwhmPixels=None, defects=None):
121 """!Interpolate in place over pixels in a maskedImage marked as bad
123 Pixels to be interpolated are set by either a mask planeName provided
124 by the caller OR a defects list of type `~lsst.meas.algorithms.Defects`
125 If both are provided an exception is raised.
127 Note that the interpolation code in meas_algorithms currently doesn't
128 use the input PSF (though it's a required argument), so it's not
129 important to set the input PSF parameters exactly. This PSF is set
130 here as the psf attached to the "image" (i.e if the image passed in
131 is an Exposure). Otherwise, a psf model is created using
132 measAlg.GaussianPsfFactory with the value of fwhmPixels (the value
133 passed in by the caller, or the default defaultFwhm set in
134 measAlg.GaussianPsfFactory if None).
136 @param[in,out] image MaskedImage OR Exposure to be interpolated
137 @param[in] planeName name of mask plane over which to interpolate
138 If None, must provide a defects list.
139 @param[in] fwhmPixels FWHM of core star (pixels)
140 If None the default is used, where the default
141 is set to the exposure psf if available
142 @param[in] defects List of defects of type ipIsr.Defects
143 over which to interpolate.
146 maskedImage = image.getMaskedImage()
147 except AttributeError:
151 if planeName
is None:
153 raise ValueError(
"No defects or plane name provided")
155 if not isinstance(defects, ipIsr.Defects):
156 defectList = ipIsr.Defects(defects)
159 planeName =
"defects"
161 if defects
is not None:
162 raise ValueError(
"Provide EITHER a planeName OR a list of defects, not both")
163 if planeName
not in maskedImage.getMask().getMaskPlaneDict():
164 raise ValueError(
"maskedImage does not contain mask plane %s" % planeName)
165 defectList = ipIsr.Defects.fromMask(maskedImage, planeName)
170 self.log.
info(
"Setting psf for interpolation from image")
171 except AttributeError:
172 self.log.
info(
"Creating psf model for interpolation from fwhm(pixels) = %s",
173 str(fwhmPixels)
if fwhmPixels
is not None else
174 (str(self.config.modelPsf.defaultFwhm)) +
" [default]")
175 psf = self.config.modelPsf.apply(fwhm=fwhmPixels)
178 if self.config.useFallbackValueAtEdge:
181 self.
interpolateImageinterpolateImage(maskedImage, psf, defectList, fallbackValue)
183 self.log.
info(
"Interpolated over %d %s pixels.", len(defectList), planeName)
187 """Context manager to potentially transpose an image
189 This applies the ``transpose`` configuration setting.
191 Transposing the image allows us to interpolate along columns instead
192 of rows, which is useful when the saturation trails are typically
193 oriented along rows on the warped/coadded images, instead of along
194 columns as they typically are in raw CCD images.
198 maskedImage : `lsst.afw.image.MaskedImage`
199 Image on which to perform interpolation.
200 defects : `lsst.meas.algorithms.Defects`
201 List of defects to interpolate over.
205 useImage : `lsst.afw.image.MaskedImage`
206 Image to use for interpolation; it may have been transposed.
207 useDefects : `lsst.meas.algorithms.Defects`
208 List of defects to use for interpolation; they may have been
211 def transposeImage(image):
212 """Transpose an image"""
213 transposed = image.array.T.copy()
214 return image.Factory(transposed,
False,
lsst.geom.Point2I(*reversed(image.getXY0())))
216 useImage = maskedImage
218 if self.config.transpose:
220 transposeImage(maskedImage.mask),
221 transposeImage(maskedImage.variance))
222 useDefects = defects.transpose()
223 yield useImage, useDefects
224 if self.config.transpose:
225 maskedImage.image.array = useImage.image.array.T
226 maskedImage.mask.array = useImage.mask.array.T
227 maskedImage.variance.array = useImage.variance.array.T
230 """Interpolate over defects in an image
234 maskedImage : `lsst.afw.image.MaskedImage`
235 Image on which to perform interpolation.
236 psf : `lsst.afw.detection.Psf`
237 Point-spread function; currently unused.
238 defectList : `lsst.meas.algorithms.Defects`
239 List of defects to interpolate over.
240 fallbackValue : `float`
241 Value to set when interpolation fails.
245 with self.
transposeContexttransposeContext(maskedImage, defectList)
as (image, defects):
246 measAlg.interpolateOverDefects(image, psf, defects, fallbackValue,
247 self.config.useFallbackValueAtEdge)
def interpolateImage(self, maskedImage, psf, defectList, fallbackValue)
def _setFallbackValue(self, mi=None)
def run(self, image, planeName=None, fwhmPixels=None, defects=None)
Interpolate in place over pixels in a maskedImage marked as bad.
def transposeContext(self, maskedImage, defects)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
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)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.