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)
def _setFallbackValue(self, mi=None)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
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::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
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)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...