lsst.pipe.tasks  13.0-66-gfbf2f2ce+5
interpImage.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2015 AURA/LSST.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <https://www.lsstcorp.org/LegalNotices/>.
21 #
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
28 
29 __all__ = ["InterpImageConfig", "InterpImageTask"]
30 
31 
32 class InterpImageConfig(pexConfig.Config):
33  """Config for InterpImageTask
34  """
35  modelPsf = measAlg.GaussianPsfFactory.makeField(doc="Model Psf factory")
36 
37  useFallbackValueAtEdge = pexConfig.Field(
38  dtype=bool,
39  doc="Smoothly taper to the fallback value at the edge of the image?",
40  default=True,
41  )
42  fallbackValueType = pexConfig.ChoiceField(
43  dtype=str,
44  doc="Type of statistic to calculate edge fallbackValue for interpolation",
45  allowed={
46  "MEAN": "mean",
47  "MEDIAN": "median",
48  "MEANCLIP": "clipped mean",
49  "USER": "user value set in fallbackUserValue config",
50  },
51  default="MEDIAN",
52  )
53  fallbackUserValue = pexConfig.Field(
54  dtype=float,
55  doc="If fallbackValueType is 'USER' then use this as the fallbackValue; ignored otherwise",
56  default=0.0,
57  )
58  negativeFallbackAllowed = pexConfig.Field(
59  dtype=bool,
60  doc=("Allow negative values for egde interpolation fallbackValue? If False, set "
61  "fallbackValue to max(fallbackValue, 0.0)"),
62  default=False,
63  )
64 
65  def validate(self):
66  pexConfig.Config.validate(self)
67  if self.useFallbackValueAtEdge:
68  if (not self.negativeFallbackAllowed and self.fallbackValueType == "USER" and
69  self.fallbackUserValue < 0.0):
70  raise ValueError("User supplied fallbackValue is negative (%.2f) but "
71  "negativeFallbackAllowed is False" % self.fallbackUserValue)
72 
73 
74 class InterpImageTask(pipeBase.Task):
75  """Interpolate over bad image pixels
76  """
77  ConfigClass = InterpImageConfig
78  _DefaultName = "interpImage"
79 
80  def _setFallbackValue(self, mi=None):
81  """Set the edge fallbackValue for interpolation
82 
83  \param[in] mi input maksedImage on which to calculate the statistics
84  Must be provided if fallbackValueType != "USER".
85 
86  \return fallbackValue The value set/computed based on the fallbackValueType
87  and negativeFallbackAllowed config parameters
88  """
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
99  else:
100  raise NotImplementedError("%s : %s not implemented" %
101  ("fallbackValueType", self.config.fallbackValueType))
102 
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)
107 
108  self.log.info("fallbackValueType %s has been set to %.4f" %
109  (self.config.fallbackValueType, fallbackValue))
110 
111  return fallbackValue
112 
113  @pipeBase.timeMethod
114  def run(self, image, planeName=None, fwhmPixels=None, defects=None):
115  """!Interpolate in place over pixels in a maskedImage marked as bad
116 
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.
120 
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).
129 
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.
138  """
139  try:
140  maskedImage = image.getMaskedImage()
141  except AttributeError:
142  maskedImage = image
143 
144  # set defectList from defects OR mask planeName provided
145  if planeName is None:
146  if defects is None:
147  raise ValueError("No defects or plane name provided")
148  else:
149  defectList = defects
150  planeName = "defects"
151  else:
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)
157 
158  # set psf from exposure if provided OR using modelPsf with fwhmPixels provided
159  try:
160  psf = image.getPsf()
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)
167 
168  fallbackValue = 0.0 # interpolateOverDefects needs this to be a float, regardless if it is used
169  if self.config.useFallbackValueAtEdge:
170  fallbackValue = self._setFallbackValue(maskedImage)
171 
172  measAlg.interpolateOverDefects(maskedImage, psf, defectList, fallbackValue,
173  self.config.useFallbackValueAtEdge)
174 
175  self.log.info("Interpolated over %d %s pixels." % (len(defectList), planeName))
def run(self, image, planeName=None, fwhmPixels=None, defects=None)
Interpolate in place over pixels in a maskedImage marked as bad.
Definition: interpImage.py:114