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)