22 from __future__
import absolute_import, division, print_function
23 import lsst.pex.config
as pexConfig
24 import lsst.afw.math
as afwMath
25 import lsst.meas.algorithms
as measAlg
26 import lsst.pipe.base
as pipeBase
27 import lsst.ip.isr
as ipIsr
29 __all__ = [
"InterpImageConfig",
"InterpImageTask"]
33 """Config for InterpImageTask 35 modelPsf = measAlg.GaussianPsfFactory.makeField(doc=
"Model Psf factory")
37 useFallbackValueAtEdge = pexConfig.Field(
39 doc=
"Smoothly taper to the fallback value at the edge of the image?",
42 fallbackValueType = pexConfig.ChoiceField(
44 doc=
"Type of statistic to calculate edge fallbackValue for interpolation",
48 "MEANCLIP":
"clipped mean",
49 "USER":
"user value set in fallbackUserValue config",
53 fallbackUserValue = pexConfig.Field(
55 doc=
"If fallbackValueType is 'USER' then use this as the fallbackValue; ignored otherwise",
58 negativeFallbackAllowed = pexConfig.Field(
60 doc=(
"Allow negative values for egde interpolation fallbackValue? If False, set " 61 "fallbackValue to max(fallbackValue, 0.0)"),
66 pexConfig.Config.validate(self)
70 raise ValueError(
"User supplied fallbackValue is negative (%.2f) but " 75 """Interpolate over bad image pixels 77 ConfigClass = InterpImageConfig
78 _DefaultName =
"interpImage" 80 def _setFallbackValue(self, mi=None):
81 """Set the edge fallbackValue for interpolation 83 \param[in] mi input maksedImage on which to calculate the statistics 84 Must be provided if fallbackValueType != "USER". 86 \return fallbackValue The value set/computed based on the fallbackValueType 87 and negativeFallbackAllowed config parameters 89 if self.config.fallbackValueType !=
'USER':
90 assert mi,
"No maskedImage provided" 91 if self.config.fallbackValueType ==
'MEAN':
92 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEAN).getValue()
93 elif self.config.fallbackValueType ==
'MEDIAN':
94 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEDIAN).getValue()
95 elif self.config.fallbackValueType ==
'MEANCLIP':
96 fallbackValue = afwMath.makeStatistics(mi, afwMath.MEANCLIP).getValue()
97 elif self.config.fallbackValueType ==
'USER':
98 fallbackValue = self.config.fallbackUserValue
100 raise NotImplementedError(
"%s : %s not implemented" %
101 (
"fallbackValueType", self.config.fallbackValueType))
103 if not self.config.negativeFallbackAllowed
and fallbackValue < 0.0:
104 self.log.warn(
"Negative interpolation edge fallback value computed but " 105 "negativeFallbackAllowed is False: setting fallbackValue to 0.0")
106 fallbackValue = max(fallbackValue, 0.0)
108 self.log.info(
"fallbackValueType %s has been set to %.4f" %
109 (self.config.fallbackValueType, fallbackValue))
114 def run(self, image, planeName=None, fwhmPixels=None, defects=None):
115 """!Interpolate in place over pixels in a maskedImage marked as bad 117 Pixels to be interpolated are set by either a mask planeName provided 118 by the caller OR a defects list of type measAlg.DefectListT. If both 119 are provided an exception is raised. 121 Note that the interpolation code in meas_algorithms currently doesn't 122 use the input PSF (though it's a required argument), so it's not 123 important to set the input PSF parameters exactly. This PSF is set 124 here as the psf attached to the "image" (i.e if the image passed in 125 is an Exposure). Otherwise, a psf model is created using 126 measAlg.GaussianPsfFactory with the value of fwhmPixels (the value 127 passed in by the caller, or the default defaultFwhm set in 128 measAlg.GaussianPsfFactory if None). 130 \param[in,out] image MaskedImage OR Exposure to be interpolated 131 \param[in] planeName name of mask plane over which to interpolate 132 If None, must provide a defects list. 133 \param[in] fwhmPixels FWHM of core star (pixels) 134 If None the default is used, where the default 135 is set to the exposure psf if available 136 \param[in] defects List of defects of type measAlg.DefectListT 137 over which to interpolate. 140 maskedImage = image.getMaskedImage()
141 except AttributeError:
145 if planeName
is None:
147 raise ValueError(
"No defects or plane name provided")
150 planeName =
"defects" 152 if defects
is not None:
153 raise ValueError(
"Provide EITHER a planeName OR a list of defects, not both")
154 if planeName
not in maskedImage.getMask().getMaskPlaneDict():
155 raise ValueError(
"maskedImage does not contain mask plane %s" % planeName)
156 defectList = ipIsr.getDefectListFromMask(maskedImage, planeName, growFootprints=0)
161 self.log.info(
"Setting psf for interpolation from image")
162 except AttributeError:
163 self.log.info(
"Creating psf model for interpolation from fwhm(pixels) = %s" %
164 (str(fwhmPixels)
if fwhmPixels
is not None else 165 (str(self.config.modelPsf.defaultFwhm)) +
" [default]"))
166 psf = self.config.modelPsf.apply(fwhm=fwhmPixels)
169 if self.config.useFallbackValueAtEdge:
172 measAlg.interpolateOverDefects(maskedImage, psf, defectList, fallbackValue,
173 self.config.useFallbackValueAtEdge)
175 self.log.info(
"Interpolated over %d %s pixels." % (len(defectList), planeName))
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.