lsst.ip.isr  15.0-4-gf5d1e39
isrFunctions.py
Go to the documentation of this file.
1 from __future__ import division, print_function, absolute_import
2 from builtins import input
3 from builtins import range
4 #
5 # LSST Data Management System
6 # Copyright 2008, 2009, 2010 LSST Corporation.
7 #
8 # This product includes software developed by the
9 # LSST Project (http://www.lsst.org/).
10 #
11 # This program is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation, either version 3 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the LSST License Statement and
22 # the GNU General Public License along with this program. If not,
23 # see <http://www.lsstcorp.org/LegalNotices/>.
24 #
25 import math
26 
27 import numpy
28 
29 import lsst.afw.geom as afwGeom
30 import lsst.afw.image as afwImage
31 import lsst.afw.detection as afwDetection
32 import lsst.afw.math as afwMath
33 import lsst.meas.algorithms as measAlg
34 import lsst.pex.exceptions as pexExcept
35 import lsst.afw.cameraGeom as camGeom
36 
37 from lsst.pipe.base import Struct
38 
39 
40 def createPsf(fwhm):
41  """Make a double Gaussian PSF
42 
43  @param[in] fwhm FWHM of double Gaussian smoothing kernel
44  @return measAlg.DoubleGaussianPsf
45  """
46  ksize = 4*int(fwhm) + 1
47  return measAlg.DoubleGaussianPsf(ksize, ksize, fwhm/(2*math.sqrt(2*math.log(2))))
48 
49 def transposeMaskedImage(maskedImage):
50  """Make a transposed copy of a masked image
51 
52  @param[in] maskedImage afw.image.MaskedImage to process
53  @return transposed masked image
54  """
55  transposed = maskedImage.Factory(afwGeom.Extent2I(maskedImage.getHeight(), maskedImage.getWidth()))
56  transposed.getImage().getArray()[:] = maskedImage.getImage().getArray().T
57  transposed.getMask().getArray()[:] = maskedImage.getMask().getArray().T
58  transposed.getVariance().getArray()[:] = maskedImage.getVariance().getArray().T
59  return transposed
60 
61 
62 def interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=None):
63  """Interpolate over defects specified in a defect list
64 
65  @param[in,out] maskedImage masked image to process
66  @param[in] defectList defect list
67  @param[in] fwhm FWHM of double Gaussian smoothing kernel
68  @param[in] fallbackValue fallback value if an interpolated value cannot be determined;
69  if None then use clipped mean image value
70  """
71  psf = createPsf(fwhm)
72  if fallbackValue is None:
73  fallbackValue = afwMath.makeStatistics(maskedImage.getImage(), afwMath.MEANCLIP).getValue()
74  if 'INTRP' not in maskedImage.getMask().getMaskPlaneDict():
75  maskedImage.getMask.addMaskPlane('INTRP')
76  measAlg.interpolateOverDefects(maskedImage, psf, defectList, fallbackValue, True)
77 
78 
80  """Compute a defect list from a footprint list, optionally growing the footprints
81 
82  @param[in] fpList footprint list
83  """
84  defectList = []
85  for fp in fpList:
86  for bbox in afwDetection.footprintToBBoxList(fp):
87  defect = measAlg.Defect(bbox)
88  defectList.append(defect)
89  return defectList
90 
91 
92 def transposeDefectList(defectList):
93  """Make a transposed copy of a defect list
94 
95  @param[in] defectList a list of defects (afw.meas.algorithms.Defect)
96  @return a defect list with transposed defects
97  """
98  retDefectList = []
99  for defect in defectList:
100  bbox = defect.getBBox()
101  nbbox = afwGeom.Box2I(afwGeom.Point2I(bbox.getMinY(), bbox.getMinX()),
102  afwGeom.Extent2I(bbox.getDimensions()[1], bbox.getDimensions()[0]))
103  retDefectList.append(measAlg.Defect(nbbox))
104  return retDefectList
105 
106 
107 def maskPixelsFromDefectList(maskedImage, defectList, maskName='BAD'):
108  """Set mask plane based on a defect list
109 
110  @param[in,out] maskedImage afw.image.MaskedImage to process; mask plane is updated
111  @param[in] defectList a list of defects (afw.meas.algorithms.Defect)
112  @param[in] maskName mask plane name
113  """
114  # mask bad pixels
115  mask = maskedImage.getMask()
116  bitmask = mask.getPlaneBitMask(maskName)
117  for defect in defectList:
118  bbox = defect.getBBox()
119  afwGeom.SpanSet(bbox).clippedTo(mask.getBBox()).setMask(mask, bitmask)
120 
121 
122 def getDefectListFromMask(maskedImage, maskName):
123  """Compute a defect list from a specified mask plane
124 
125  @param[in] maskedImage masked image to process
126  @param[in] maskName mask plane name, or list of names
127  """
128  mask = maskedImage.getMask()
129  thresh = afwDetection.Threshold(mask.getPlaneBitMask(maskName), afwDetection.Threshold.BITMASK)
130  fpList = afwDetection.FootprintSet(mask, thresh).getFootprints()
131  return defectListFromFootprintList(fpList)
132 
133 
134 def makeThresholdMask(maskedImage, threshold, growFootprints=1, maskName='SAT'):
135  """Mask pixels based on threshold detection
136 
137  @param[in,out] maskedImage afw.image.MaskedImage to process; the mask is altered
138  @param[in] threshold detection threshold
139  @param[in] growFootprints amount by which to grow footprints of detected regions
140  @param[in] maskName mask plane name
141  @return a list of defects (meas.algrithms.Defect) of regions set in the mask.
142  """
143  # find saturated regions
144  thresh = afwDetection.Threshold(threshold)
145  fs = afwDetection.FootprintSet(maskedImage, thresh)
146 
147  if growFootprints > 0:
148  fs = afwDetection.FootprintSet(fs, growFootprints)
149 
150  fpList = fs.getFootprints()
151  # set mask
152  mask = maskedImage.getMask()
153  bitmask = mask.getPlaneBitMask(maskName)
154  afwDetection.setMaskFromFootprintList(mask, fpList, bitmask)
155 
156  return defectListFromFootprintList(fpList)
157 
158 
159 def interpolateFromMask(maskedImage, fwhm, growFootprints=1, maskName='SAT', fallbackValue=None):
160  """Interpolate over defects identified by a particular mask plane
161 
162  @param[in,out] maskedImage afw.image.MaskedImage to process
163  @param[in] fwhm FWHM of double Gaussian smoothing kernel
164  @param[in] growFootprints amount by which to grow footprints of detected regions
165  @param[in] maskName mask plane name
166  @param[in] fallbackValue value of last resort for interpolation
167  """
168  mask = maskedImage.getMask()
169  thresh = afwDetection.Threshold(mask.getPlaneBitMask(maskName), afwDetection.Threshold.BITMASK)
170  fpSet = afwDetection.FootprintSet(mask, thresh)
171  if growFootprints > 0:
172  fpSet = afwDetection.FootprintSet(fpSet, rGrow=growFootprints, isotropic=False)
173  # If we are interpolating over an area larger than the original masked region, we need
174  # to expand the original mask bit to the full area to explain why we interpolated there.
175  fpSet.setMask(mask, maskName)
176  defectList = defectListFromFootprintList(fpSet.getFootprints())
177  interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=fallbackValue)
178 
179 
180 def saturationCorrection(maskedImage, saturation, fwhm, growFootprints=1, interpolate=True, maskName='SAT',
181  fallbackValue=None):
182  """Mark saturated pixels and optionally interpolate over them
183 
184  @param[in,out] maskedImage afw.image.MaskedImage to process
185  @param[in] saturation saturation level (used as a detection threshold)
186  @param[in] fwhm FWHM of double Gaussian smoothing kernel
187  @param[in] growFootprints amount by which to grow footprints of detected regions
188  @param[in] interpolate interpolate over saturated pixels?
189  @param[in] maskName mask plane name
190  @param[in] fallbackValue value of last resort for interpolation
191  """
192  defectList = makeThresholdMask(
193  maskedImage=maskedImage,
194  threshold=saturation,
195  growFootprints=growFootprints,
196  maskName=maskName,
197  )
198  if interpolate:
199  interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=fallbackValue)
200 
201 
202 def biasCorrection(maskedImage, biasMaskedImage):
203  """Apply bias correction in place
204 
205  @param[in,out] maskedImage masked image to correct
206  @param[in] biasMaskedImage bias, as a masked image
207  """
208  if maskedImage.getBBox(afwImage.LOCAL) != biasMaskedImage.getBBox(afwImage.LOCAL):
209  raise RuntimeError("maskedImage bbox %s != biasMaskedImage bbox %s" %
210  (maskedImage.getBBox(afwImage.LOCAL), biasMaskedImage.getBBox(afwImage.LOCAL)))
211  maskedImage -= biasMaskedImage
212 
213 
214 def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False):
215  """Apply dark correction in place
216 
217  maskedImage -= dark * expScaling / darkScaling
218 
219  @param[in,out] maskedImage afw.image.MaskedImage to correct
220  @param[in] darkMaskedImage dark afw.image.MaskedImage
221  @param[in] expScale exposure scale
222  @param[in] darkScale dark scale
223  @param[in] invert if True, remove the dark from an already-corrected image
224  """
225  if maskedImage.getBBox(afwImage.LOCAL) != darkMaskedImage.getBBox(afwImage.LOCAL):
226  raise RuntimeError("maskedImage bbox %s != darkMaskedImage bbox %s" %
227  (maskedImage.getBBox(afwImage.LOCAL), darkMaskedImage.getBBox(afwImage.LOCAL)))
228 
229  scale = expScale / darkScale
230  if not invert:
231  maskedImage.scaledMinus(scale, darkMaskedImage)
232  else:
233  maskedImage.scaledPlus(scale, darkMaskedImage)
234 
235 
236 def updateVariance(maskedImage, gain, readNoise):
237  """Set the variance plane based on the image plane
238 
239  @param[in,out] maskedImage afw.image.MaskedImage; image plane is read and variance plane is written
240  @param[in] gain amplifier gain (e-/ADU)
241  @param[in] readNoise amplifier read noise (ADU/pixel)
242  """
243  var = maskedImage.getVariance()
244  var[:] = maskedImage.getImage()
245  var /= gain
246  var += readNoise**2
247 
248 
249 def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False):
250  """Apply flat correction in place
251 
252  @param[in,out] maskedImage afw.image.MaskedImage to correct
253  @param[in] flatMaskedImage flat field afw.image.MaskedImage
254  @param[in] scalingType how to compute flat scale; one of 'MEAN', 'MEDIAN' or 'USER'
255  @param[in] userScale scale to use if scalingType is 'USER', else ignored
256  @param[in] invert if True, unflatten an already-flattened image instead.
257  """
258  if maskedImage.getBBox(afwImage.LOCAL) != flatMaskedImage.getBBox(afwImage.LOCAL):
259  raise RuntimeError("maskedImage bbox %s != flatMaskedImage bbox %s" %
260  (maskedImage.getBBox(afwImage.LOCAL), flatMaskedImage.getBBox(afwImage.LOCAL)))
261 
262  # Figure out scale from the data
263  # Ideally the flats are normalized by the calibration product pipelin, but this allows some flexibility
264  # in the case that the flat is created by some other mechanism.
265  if scalingType == 'MEAN':
266  flatScale = afwMath.makeStatistics(flatMaskedImage.getImage(), afwMath.MEAN).getValue(afwMath.MEAN)
267  elif scalingType == 'MEDIAN':
268  flatScale = afwMath.makeStatistics(flatMaskedImage.getImage(),
269  afwMath.MEDIAN).getValue(afwMath.MEDIAN)
270  elif scalingType == 'USER':
271  flatScale = userScale
272  else:
273  raise pexExcept.Exception('%s : %s not implemented' % ("flatCorrection", scalingType))
274 
275  if not invert:
276  maskedImage.scaledDivides(1.0/flatScale, flatMaskedImage)
277  else:
278  maskedImage.scaledMultiplies(1.0/flatScale, flatMaskedImage)
279 
280 
281 def illuminationCorrection(maskedImage, illumMaskedImage, illumScale):
282  """Apply illumination correction in place
283 
284  @param[in,out] maskedImage afw.image.MaskedImage to correct
285  @param[in] illumMaskedImage illumination correction masked image
286  @param[in] illumScale scale value for illumination correction
287  """
288  if maskedImage.getBBox(afwImage.LOCAL) != illumMaskedImage.getBBox(afwImage.LOCAL):
289  raise RuntimeError("maskedImage bbox %s != illumMaskedImage bbox %s" %
290  (maskedImage.getBBox(afwImage.LOCAL), illumMaskedImage.getBBox(afwImage.LOCAL)))
291 
292  maskedImage.scaledDivides(1./illumScale, illumMaskedImage)
293 
294 
295 def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0,
296  statControl=None):
297  """Apply overscan correction in-place
298 
299  The ``ampMaskedImage`` and ``overscanImage`` are modified, with the fit
300  subtracted. Note that the ``overscanImage`` should not be a subimage of
301  the ``ampMaskedImage``, to avoid being subtracted twice.
302 
303  Parameters
304  ----------
305  ampMaskedImage : `lsst.afw.image.MaskedImage`
306  Image of amplifier to correct; modified.
307  overscanImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
308  Image of overscan; modified.
309  fitType : `str`
310  Type of fit for overscan correction. May be one of:
311 
312  - ``MEAN``: use mean of overscan.
313  - ``MEDIAN``: use median of overscan.
314  - ``POLY``: fit with ordinary polynomial.
315  - ``CHEB``: fit with Chebyshev polynomial.
316  - ``LEG``: fit with Legendre polynomial.
317  - ``NATURAL_SPLINE``: fit with natural spline.
318  - ``CUBIC_SPLINE``: fit with cubic spline.
319  - ``AKIMA_SPLINE``: fit with Akima spline.
320 
321  order : `int`
322  Polynomial order or number of spline knots; ignored unless
323  ``fitType`` indicates a polynomial or spline.
324  collapseRej : `float`
325  Rejection threshold (sigma) for collapsing dimension of overscan.
326  statControl : `lsst.afw.math.StatisticsControl`
327  Statistics control object.
328 
329  Returns
330  -------
331  result : `lsst.pipe.base.Struct`
332  Result struct with components:
333 
334  - ``imageFit``: Value(s) removed from image (scalar or
335  `lsst.afw.image.Image`)
336  - ``overscanFit``: Value(s) removed from overscan (scalar or
337  `lsst.afw.image.Image`)
338  """
339  ampImage = ampMaskedImage.getImage()
340  if statControl is None:
341  statControl = afwMath.StatisticsControl()
342  if fitType == 'MEAN':
343  offImage = afwMath.makeStatistics(overscanImage, afwMath.MEAN, statControl).getValue(afwMath.MEAN)
344  overscanFit = offImage
345  elif fitType == 'MEDIAN':
346  offImage = afwMath.makeStatistics(overscanImage, afwMath.MEDIAN, statControl).getValue(afwMath.MEDIAN)
347  overscanFit = offImage
348  elif fitType in ('POLY', 'CHEB', 'LEG', 'NATURAL_SPLINE', 'CUBIC_SPLINE', 'AKIMA_SPLINE'):
349  if hasattr(overscanImage, "getImage"):
350  biasArray = overscanImage.getImage().getArray()
351  biasArray = numpy.ma.masked_where(overscanImage.getMask().getArray() & statControl.getAndMask(),
352  biasArray)
353  else:
354  biasArray = overscanImage.getArray()
355  # Fit along the long axis, so collapse along each short row and fit the resulting array
356  shortInd = numpy.argmin(biasArray.shape)
357  if shortInd == 0:
358  # Convert to some 'standard' representation to make things easier
359  biasArray = numpy.transpose(biasArray)
360 
361  # Do a single round of clipping to weed out CR hits and signal leaking into the overscan
362  percentiles = numpy.percentile(biasArray, [25.0, 50.0, 75.0], axis=1)
363  medianBiasArr = percentiles[1]
364  stdevBiasArr = 0.74*(percentiles[2] - percentiles[0]) # robust stdev
365  diff = numpy.abs(biasArray - medianBiasArr[:, numpy.newaxis])
366  biasMaskedArr = numpy.ma.masked_where(diff > collapseRej*stdevBiasArr[:, numpy.newaxis], biasArray)
367  collapsed = numpy.mean(biasMaskedArr, axis=1)
368  if collapsed.mask.sum() > 0:
369  collapsed.data[collapsed.mask] = numpy.mean(biasArray.data[collapsed.mask], axis=1)
370  del biasArray, percentiles, stdevBiasArr, diff, biasMaskedArr
371 
372  if shortInd == 0:
373  collapsed = numpy.transpose(collapsed)
374 
375  num = len(collapsed)
376  indices = 2.0*numpy.arange(num)/float(num) - 1.0
377 
378  if fitType in ('POLY', 'CHEB', 'LEG'):
379  # A numpy polynomial
380  poly = numpy.polynomial
381  fitter, evaler = {"POLY": (poly.polynomial.polyfit, poly.polynomial.polyval),
382  "CHEB": (poly.chebyshev.chebfit, poly.chebyshev.chebval),
383  "LEG": (poly.legendre.legfit, poly.legendre.legval),
384  }[fitType]
385 
386  coeffs = fitter(indices, collapsed, order)
387  fitBiasArr = evaler(indices, coeffs)
388  elif 'SPLINE' in fitType:
389  # An afw interpolation
390  numBins = order
391  #
392  # numpy.histogram needs a real array for the mask, but numpy.ma "optimises" the case
393  # no-values-are-masked by replacing the mask array by a scalar, numpy.ma.nomask
394  #
395  # Issue DM-415
396  #
397  collapsedMask = collapsed.mask
398  try:
399  if collapsedMask == numpy.ma.nomask:
400  collapsedMask = numpy.array(len(collapsed)*[numpy.ma.nomask])
401  except ValueError: # If collapsedMask is an array the test fails [needs .all()]
402  pass
403 
404  numPerBin, binEdges = numpy.histogram(indices, bins=numBins,
405  weights=1-collapsedMask.astype(int))
406  # Binning is just a histogram, with weights equal to the values.
407  # Use a similar trick to get the bin centers (this deals with different numbers per bin).
408  with numpy.errstate(invalid="ignore"): # suppress NAN warnings
409  values = numpy.histogram(indices, bins=numBins,
410  weights=collapsed.data*~collapsedMask)[0]/numPerBin
411  binCenters = numpy.histogram(indices, bins=numBins,
412  weights=indices*~collapsedMask)[0]/numPerBin
413  interp = afwMath.makeInterpolate(binCenters.astype(float)[numPerBin > 0],
414  values.astype(float)[numPerBin > 0],
415  afwMath.stringToInterpStyle(fitType))
416  fitBiasArr = numpy.array([interp.interpolate(i) for i in indices])
417 
418  import lsstDebug
419  if lsstDebug.Info(__name__).display:
420  import matplotlib.pyplot as plot
421  figure = plot.figure(1)
422  figure.clear()
423  axes = figure.add_axes((0.1, 0.1, 0.8, 0.8))
424  axes.plot(indices[~collapsedMask], collapsed[~collapsedMask], 'k+')
425  if collapsedMask.sum() > 0:
426  axes.plot(indices[collapsedMask], collapsed.data[collapsedMask], 'b+')
427  axes.plot(indices, fitBiasArr, 'r-')
428  figure.show()
429  prompt = "Press Enter or c to continue [chp]... "
430  while True:
431  ans = input(prompt).lower()
432  if ans in ("", "c",):
433  break
434  if ans in ("p",):
435  import pdb
436  pdb.set_trace()
437  elif ans in ("h", ):
438  print("h[elp] c[ontinue] p[db]")
439  figure.close()
440 
441  offImage = ampImage.Factory(ampImage.getDimensions())
442  offArray = offImage.getArray()
443  overscanFit = afwImage.ImageF(overscanImage.getDimensions())
444  overscanArray = overscanFit.getArray()
445  if shortInd == 1:
446  offArray[:, :] = fitBiasArr[:, numpy.newaxis]
447  overscanArray[:, :] = fitBiasArr[:, numpy.newaxis]
448  else:
449  offArray[:, :] = fitBiasArr[numpy.newaxis, :]
450  overscanArray[:, :] = fitBiasArr[numpy.newaxis, :]
451 
452  # We don't trust any extrapolation: mask those pixels as SUSPECT
453  # This will occur when the top and or bottom edges of the overscan
454  # contain saturated values. The values will be extrapolated from
455  # the surrounding pixels, but we cannot entirely trust the value of
456  # the extrapolation, and will mark the image mask plane to flag the
457  # image as such.
458  mask = ampMaskedImage.getMask()
459  maskArray = mask.getArray() if shortInd == 1 else mask.getArray().transpose()
460  suspect = mask.getPlaneBitMask("SUSPECT")
461  try:
462  if collapsed.mask == numpy.ma.nomask:
463  # There is no mask, so the whole array is fine
464  pass
465  except ValueError: # If collapsed.mask is an array the test fails [needs .all()]
466  for low in range(num):
467  if not collapsed.mask[low]:
468  break
469  if low > 0:
470  maskArray[:low, :] |= suspect
471  for high in range(1, num):
472  if not collapsed.mask[-high]:
473  break
474  if high > 1:
475  maskArray[-high:, :] |= suspect
476 
477  else:
478  raise pexExcept.Exception('%s : %s an invalid overscan type' % \
479  ("overscanCorrection", fitType))
480  ampImage -= offImage
481  overscanImage -= overscanFit
482  return Struct(imageFit=offImage, overscanFit=overscanFit)
483 
484 
485 def attachTransmissionCurve(exposure, opticsTransmission=None, filterTransmission=None,
486  sensorTransmission=None, atmosphereTransmission=None):
487  """Attach a TransmissionCurve to an Exposure, given separate curves for
488  different components.
489 
490  Parameters
491  ----------
492  exposure : `lsst.afw.image.Exposure`
493  Exposure object to modify by attaching the product of all given
494  ``TransmissionCurves`` in post-assembly trimmed detector coordinates.
495  Must have a valid ``Detector`` attached that matches the detector
496  associated with sensorTransmission.
497  opticsTransmission : `lsst.afw.image.TransmissionCurve`
498  A ``TransmissionCurve`` that represents the throughput of the optics,
499  to be evaluated in focal-plane coordinates.
500  filterTransmission : `lsst.afw.image.TransmissionCurve`
501  A ``TransmissionCurve`` that represents the throughput of the filter
502  itself, to be evaluated in focal-plane coordinates.
503  sensorTransmission : `lsst.afw.image.TransmissionCurve`
504  A ``TransmissionCurve`` that represents the throughput of the sensor
505  itself, to be evaluated in post-assembly trimmed detector coordinates.
506  atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
507  A ``TransmissionCurve`` that represents the throughput of the
508  atmosphere, assumed to be spatially constant.
509 
510  All ``TransmissionCurve`` arguments are optional; if none are provided, the
511  attached ``TransmissionCurve`` will have unit transmission everywhere.
512 
513  Returns
514  -------
515  combined : ``lsst.afw.image.TransmissionCurve``
516  The TransmissionCurve attached to the exposure.
517  """
518  combined = afwImage.TransmissionCurve.makeIdentity()
519  if atmosphereTransmission is not None:
520  combined *= atmosphereTransmission
521  if opticsTransmission is not None:
522  combined *= opticsTransmission
523  if filterTransmission is not None:
524  combined *= filterTransmission
525  detector = exposure.getDetector()
526  fpToPix = detector.getTransform(fromSys=camGeom.FOCAL_PLANE,
527  toSys=camGeom.PIXELS)
528  combined = combined.transformedBy(fpToPix)
529  if sensorTransmission is not None:
530  combined *= sensorTransmission
531  exposure.getInfo().setTransmissionCurve(combined)
532  return combined
def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False)
def illuminationCorrection(maskedImage, illumMaskedImage, illumScale)
def saturationCorrection(maskedImage, saturation, fwhm, growFootprints=1, interpolate=True, maskName='SAT', fallbackValue=None)
def transposeDefectList(defectList)
Definition: isrFunctions.py:92
def getDefectListFromMask(maskedImage, maskName)
def interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=None)
Definition: isrFunctions.py:62
def defectListFromFootprintList(fpList)
Definition: isrFunctions.py:79
def transposeMaskedImage(maskedImage)
Definition: isrFunctions.py:49
def biasCorrection(maskedImage, biasMaskedImage)
def interpolateFromMask(maskedImage, fwhm, growFootprints=1, maskName='SAT', fallbackValue=None)
def attachTransmissionCurve(exposure, opticsTransmission=None, filterTransmission=None, sensorTransmission=None, atmosphereTransmission=None)
def makeThresholdMask(maskedImage, threshold, growFootprints=1, maskName='SAT')
def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0, statControl=None)
def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False)
def updateVariance(maskedImage, gain, readNoise)
def maskPixelsFromDefectList(maskedImage, defectList, maskName='BAD')