24 from deprecated.sphinx
import deprecated
38 from contextlib
import contextmanager
42 """Make a double Gaussian PSF. 47 FWHM of double Gaussian smoothing kernel. 51 psf : `lsst.meas.algorithms.DoubleGaussianPsf` 52 The created smoothing kernel. 54 ksize = 4*
int(fwhm) + 1
55 return measAlg.DoubleGaussianPsf(ksize, ksize, fwhm/(2*math.sqrt(2*math.log(2))))
59 """Make a transposed copy of a masked image. 63 maskedImage : `lsst.afw.image.MaskedImage` 68 transposed : `lsst.afw.image.MaskedImage` 69 The transposed copy of the input image. 71 transposed = maskedImage.Factory(
lsst.geom.Extent2I(maskedImage.getHeight(), maskedImage.getWidth()))
72 transposed.getImage().getArray()[:] = maskedImage.getImage().getArray().T
73 transposed.getMask().getArray()[:] = maskedImage.getMask().getArray().T
74 transposed.getVariance().getArray()[:] = maskedImage.getVariance().getArray().T
79 """Interpolate over defects specified in a defect list. 83 maskedImage : `lsst.afw.image.MaskedImage` 85 defectList : `lsst.meas.algorithms.Defects` 86 List of defects to interpolate over. 88 FWHM of double Gaussian smoothing kernel. 89 fallbackValue : scalar, optional 90 Fallback value if an interpolated value cannot be determined. 91 If None, then the clipped mean of the image is used. 94 if fallbackValue
is None:
96 if 'INTRP' not in maskedImage.getMask().getMaskPlaneDict():
97 maskedImage.getMask().addMaskPlane(
'INTRP')
98 measAlg.interpolateOverDefects(maskedImage, psf, defectList, fallbackValue,
True)
102 @deprecated(reason=
"Replaced by Defects.fromFootPrintList() (will be removed after v18)",
103 category=FutureWarning)
105 """Compute a defect list from a footprint list, optionally growing the footprints. 109 fpList : `list` of `lsst.afw.detection.Footprint` 110 Footprint list to process. 114 defectList : `lsst.meas.algorithms.Defects` 117 return measAlg.Defects.fromFootprintList(fpList)
119 @deprecated(reason=
"Replaced by Defects.transpose() (will be removed after v18)",
120 category=FutureWarning)
122 """Make a transposed copy of a defect list. 126 defectList : `lsst.meas.algorithms.Defects` 127 Input list of defects. 131 retDefectList : `lsst.meas.algorithms.Defects` 132 Transposed list of defects. 134 if isinstance(defectList, measAlg.Defects):
135 return defectList.transpose()
136 return measAlg.Defects(defectList).transpose()
139 @deprecated(reason=
"Replaced by Defects.maskPixels() (will be removed after v18)",
140 category=FutureWarning)
142 """Set mask plane based on a defect list. 146 maskedImage : `lsst.afw.image.MaskedImage` 147 Image to process. Only the mask plane is updated. 148 defectList : `lsst.meas.algorithms.Defects` 150 maskName : str, optional 151 Mask plane name to use. 156 @deprecated(reason=
"Replaced by Defects.fromMask() (will be removed after v18)",
157 category=FutureWarning)
159 """Compute a defect list from a specified mask plane. 163 maskedImage : `lsst.afw.image.MaskedImage` 165 maskName : `str` or `list` 166 Mask plane name, or list of names to convert. 170 defectList : `lsst.meas.algorithms.Defects` 171 Defect list constructed from masked pixels. 173 return measAlg.Defects.fromMask(maskedImage, maskName)
177 """Mask pixels based on threshold detection. 181 maskedImage : `lsst.afw.image.MaskedImage` 182 Image to process. Only the mask plane is updated. 185 growFootprints : scalar, optional 186 Number of pixels to grow footprints of detected regions. 187 maskName : str, optional 188 Mask plane name, or list of names to convert 192 defectList : `lsst.meas.algorithms.Defects` 193 Defect list constructed from pixels above the threshold. 196 thresh = afwDetection.Threshold(threshold)
197 fs = afwDetection.FootprintSet(maskedImage, thresh)
199 if growFootprints > 0:
200 fs = afwDetection.FootprintSet(fs, rGrow=growFootprints, isotropic=
False)
201 fpList = fs.getFootprints()
204 mask = maskedImage.getMask()
205 bitmask = mask.getPlaneBitMask(maskName)
206 afwDetection.setMaskFromFootprintList(mask, fpList, bitmask)
208 return measAlg.Defects.fromFootprintList(fpList)
212 maskNameList=['SAT'], fallbackValue=None):
213 """Interpolate over defects identified by a particular set of mask planes. 217 maskedImage : `lsst.afw.image.MaskedImage` 220 FWHM of double Gaussian smoothing kernel. 221 growSaturatedFootprints : scalar, optional 222 Number of pixels to grow footprints for saturated pixels. 223 maskNameList : `List` of `str`, optional 225 fallbackValue : scalar, optional 226 Value of last resort for interpolation. 228 mask = maskedImage.getMask()
230 if growSaturatedFootprints > 0
and "SAT" in maskNameList:
231 thresh = afwDetection.Threshold(mask.getPlaneBitMask(
"SAT"), afwDetection.Threshold.BITMASK)
232 fpSet = afwDetection.FootprintSet(mask, thresh)
235 fpSet = afwDetection.FootprintSet(fpSet, rGrow=growSaturatedFootprints, isotropic=
False)
236 fpSet.setMask(mask,
"SAT")
238 thresh = afwDetection.Threshold(mask.getPlaneBitMask(maskNameList), afwDetection.Threshold.BITMASK)
239 fpSet = afwDetection.FootprintSet(mask, thresh)
240 defectList = measAlg.Defects.fromFootprintList(fpSet.getFootprints())
247 def saturationCorrection(maskedImage, saturation, fwhm, growFootprints=1, interpolate=True, maskName='SAT',
249 """Mark saturated pixels and optionally interpolate over them 253 maskedImage : `lsst.afw.image.MaskedImage` 256 Saturation level used as the detection threshold. 258 FWHM of double Gaussian smoothing kernel. 259 growFootprints : scalar, optional 260 Number of pixels to grow footprints of detected regions. 261 interpolate : Bool, optional 262 If True, saturated pixels are interpolated over. 263 maskName : str, optional 265 fallbackValue : scalar, optional 266 Value of last resort for interpolation. 269 maskedImage=maskedImage,
270 threshold=saturation,
271 growFootprints=growFootprints,
281 """Compute number of edge trim pixels to match the calibration data. 283 Use the dimension difference between the raw exposure and the 284 calibration exposure to compute the edge trim pixels. This trim 285 is applied symmetrically, with the same number of pixels masked on 290 rawMaskedImage : `lsst.afw.image.MaskedImage` 292 calibMaskedImage : `lsst.afw.image.MaskedImage` 293 Calibration image to draw new bounding box from. 297 replacementMaskedImage : `lsst.afw.image.MaskedImage` 298 ``rawMaskedImage`` trimmed to the appropriate size 302 Rasied if ``rawMaskedImage`` cannot be symmetrically trimmed to 303 match ``calibMaskedImage``. 305 nx, ny = rawMaskedImage.getBBox().getDimensions() - calibMaskedImage.getBBox().getDimensions()
307 raise RuntimeError(
"Raw and calib maskedImages are trimmed differently in X and Y.")
309 raise RuntimeError(
"Calibration maskedImage is trimmed unevenly in X.")
311 raise RuntimeError(
"Calibration maskedImage is larger than raw data.")
315 replacementMaskedImage = rawMaskedImage[nEdge:-nEdge, nEdge:-nEdge, afwImage.LOCAL]
316 SourceDetectionTask.setEdgeBits(
318 replacementMaskedImage.getBBox(),
319 rawMaskedImage.getMask().getPlaneBitMask(
"EDGE")
322 replacementMaskedImage = rawMaskedImage
324 return replacementMaskedImage
328 """Apply bias correction in place. 332 maskedImage : `lsst.afw.image.MaskedImage` 333 Image to process. The image is modified by this method. 334 biasMaskedImage : `lsst.afw.image.MaskedImage` 335 Bias image of the same size as ``maskedImage`` 336 trimToFit : `Bool`, optional 337 If True, raw data is symmetrically trimmed to match 343 Raised if ``maskedImage`` and ``biasMaskedImage`` do not have 350 if maskedImage.getBBox(afwImage.LOCAL) != biasMaskedImage.getBBox(afwImage.LOCAL):
351 raise RuntimeError(
"maskedImage bbox %s != biasMaskedImage bbox %s" %
352 (maskedImage.getBBox(afwImage.LOCAL), biasMaskedImage.getBBox(afwImage.LOCAL)))
353 maskedImage -= biasMaskedImage
356 def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False, trimToFit=False):
357 """Apply dark correction in place. 361 maskedImage : `lsst.afw.image.MaskedImage` 362 Image to process. The image is modified by this method. 363 darkMaskedImage : `lsst.afw.image.MaskedImage` 364 Dark image of the same size as ``maskedImage``. 366 Dark exposure time for ``maskedImage``. 368 Dark exposure time for ``darkMaskedImage``. 369 invert : `Bool`, optional 370 If True, re-add the dark to an already corrected image. 371 trimToFit : `Bool`, optional 372 If True, raw data is symmetrically trimmed to match 378 Raised if ``maskedImage`` and ``darkMaskedImage`` do not have 383 The dark correction is applied by calculating: 384 maskedImage -= dark * expScaling / darkScaling 389 if maskedImage.getBBox(afwImage.LOCAL) != darkMaskedImage.getBBox(afwImage.LOCAL):
390 raise RuntimeError(
"maskedImage bbox %s != darkMaskedImage bbox %s" %
391 (maskedImage.getBBox(afwImage.LOCAL), darkMaskedImage.getBBox(afwImage.LOCAL)))
393 scale = expScale / darkScale
395 maskedImage.scaledMinus(scale, darkMaskedImage)
397 maskedImage.scaledPlus(scale, darkMaskedImage)
401 """Set the variance plane based on the image plane. 405 maskedImage : `lsst.afw.image.MaskedImage` 406 Image to process. The variance plane is modified. 408 The amplifier gain in electrons/ADU. 410 The amplifier read nmoise in ADU/pixel. 412 var = maskedImage.getVariance()
413 var[:] = maskedImage.getImage()
418 def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False, trimToFit=False):
419 """Apply flat correction in place. 423 maskedImage : `lsst.afw.image.MaskedImage` 424 Image to process. The image is modified. 425 flatMaskedImage : `lsst.afw.image.MaskedImage` 426 Flat image of the same size as ``maskedImage`` 428 Flat scale computation method. Allowed values are 'MEAN', 430 userScale : scalar, optional 431 Scale to use if ``scalingType``='USER'. 432 invert : `Bool`, optional 433 If True, unflatten an already flattened image. 434 trimToFit : `Bool`, optional 435 If True, raw data is symmetrically trimmed to match 441 Raised if ``maskedImage`` and ``flatMaskedImage`` do not have 442 the same size or if ``scalingType`` is not an allowed value. 447 if maskedImage.getBBox(afwImage.LOCAL) != flatMaskedImage.getBBox(afwImage.LOCAL):
448 raise RuntimeError(
"maskedImage bbox %s != flatMaskedImage bbox %s" %
449 (maskedImage.getBBox(afwImage.LOCAL), flatMaskedImage.getBBox(afwImage.LOCAL)))
454 if scalingType
in (
'MEAN',
'MEDIAN'):
457 elif scalingType ==
'USER':
458 flatScale = userScale
460 raise RuntimeError(
'%s : %s not implemented' % (
"flatCorrection", scalingType))
463 maskedImage.scaledDivides(1.0/flatScale, flatMaskedImage)
465 maskedImage.scaledMultiplies(1.0/flatScale, flatMaskedImage)
469 """Apply illumination correction in place. 473 maskedImage : `lsst.afw.image.MaskedImage` 474 Image to process. The image is modified. 475 illumMaskedImage : `lsst.afw.image.MaskedImage` 476 Illumination correction image of the same size as ``maskedImage``. 478 Scale factor for the illumination correction. 483 Raised if ``maskedImage`` and ``illumMaskedImage`` do not have 486 if maskedImage.getBBox(afwImage.LOCAL) != illumMaskedImage.getBBox(afwImage.LOCAL):
487 raise RuntimeError(
"maskedImage bbox %s != illumMaskedImage bbox %s" %
488 (maskedImage.getBBox(afwImage.LOCAL), illumMaskedImage.getBBox(afwImage.LOCAL)))
490 maskedImage.scaledDivides(1./illumScale, illumMaskedImage)
493 def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0,
494 statControl=None, overscanIsInt=True):
495 """Apply overscan correction in place. 499 ampMaskedImage : `lsst.afw.image.MaskedImage` 500 Image of amplifier to correct; modified. 501 overscanImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 502 Image of overscan; modified. 504 Type of fit for overscan correction. May be one of: 506 - ``MEAN``: use mean of overscan. 507 - ``MEANCLIP``: use clipped mean of overscan. 508 - ``MEDIAN``: use median of overscan. 509 - ``POLY``: fit with ordinary polynomial. 510 - ``CHEB``: fit with Chebyshev polynomial. 511 - ``LEG``: fit with Legendre polynomial. 512 - ``NATURAL_SPLINE``: fit with natural spline. 513 - ``CUBIC_SPLINE``: fit with cubic spline. 514 - ``AKIMA_SPLINE``: fit with Akima spline. 517 Polynomial order or number of spline knots; ignored unless 518 ``fitType`` indicates a polynomial or spline. 519 statControl : `lsst.afw.math.StatisticsControl` 520 Statistics control object. In particular, we pay attention to numSigmaClip 521 overscanIsInt : `bool` 522 Treat the overscan region as consisting of integers, even if it's been 523 converted to float. E.g. handle ties properly. 527 result : `lsst.pipe.base.Struct` 528 Result struct with components: 530 - ``imageFit``: Value(s) removed from image (scalar or 531 `lsst.afw.image.Image`) 532 - ``overscanFit``: Value(s) removed from overscan (scalar or 533 `lsst.afw.image.Image`) 534 - ``overscanImage``: Overscan corrected overscan region 535 (`lsst.afw.image.Image`) 539 Raised if ``fitType`` is not an allowed value. 543 The ``ampMaskedImage`` and ``overscanImage`` are modified, with the fit 544 subtracted. Note that the ``overscanImage`` should not be a subimage of 545 the ``ampMaskedImage``, to avoid being subtracted twice. 547 Debug plots are available for the SPLINE fitTypes by setting the 548 `debug.display` for `name` == "lsst.ip.isr.isrFunctions". These 549 plots show the scatter plot of the overscan data (collapsed along 550 the perpendicular dimension) as a function of position on the CCD 551 (normalized between +/-1). 553 ampImage = ampMaskedImage.getImage()
554 if statControl
is None:
557 numSigmaClip = statControl.getNumSigmaClip()
559 if fitType
in (
'MEAN',
'MEANCLIP'):
562 overscanFit = offImage
563 elif fitType
in (
'MEDIAN',):
566 if hasattr(overscanImage,
"image"):
567 imageI = overscanImage.image.convertI()
568 overscanImageI = afwImage.MaskedImageI(imageI, overscanImage.mask, overscanImage.variance)
570 overscanImageI = overscanImage.convertI()
572 overscanImageI = overscanImage
576 overscanFit = offImage
580 elif fitType
in (
'POLY',
'CHEB',
'LEG',
'NATURAL_SPLINE',
'CUBIC_SPLINE',
'AKIMA_SPLINE'):
581 if hasattr(overscanImage,
"getImage"):
582 biasArray = overscanImage.getImage().getArray()
583 biasArray = numpy.ma.masked_where(overscanImage.getMask().getArray() & statControl.getAndMask(),
586 biasArray = overscanImage.getArray()
588 shortInd = numpy.argmin(biasArray.shape)
591 biasArray = numpy.transpose(biasArray)
594 percentiles = numpy.percentile(biasArray, [25.0, 50.0, 75.0], axis=1)
595 medianBiasArr = percentiles[1]
596 stdevBiasArr = 0.74*(percentiles[2] - percentiles[0])
597 diff = numpy.abs(biasArray - medianBiasArr[:, numpy.newaxis])
598 biasMaskedArr = numpy.ma.masked_where(diff > numSigmaClip*stdevBiasArr[:, numpy.newaxis], biasArray)
599 collapsed = numpy.mean(biasMaskedArr, axis=1)
600 if collapsed.mask.sum() > 0:
601 collapsed.data[collapsed.mask] = numpy.mean(biasArray.data[collapsed.mask], axis=1)
602 del biasArray, percentiles, stdevBiasArr, diff, biasMaskedArr
605 collapsed = numpy.transpose(collapsed)
608 indices = 2.0*numpy.arange(num)/
float(num) - 1.0
610 if fitType
in (
'POLY',
'CHEB',
'LEG'):
612 poly = numpy.polynomial
613 fitter, evaler = {
"POLY": (poly.polynomial.polyfit, poly.polynomial.polyval),
614 "CHEB": (poly.chebyshev.chebfit, poly.chebyshev.chebval),
615 "LEG": (poly.legendre.legfit, poly.legendre.legval),
618 coeffs =
fitter(indices, collapsed, order)
619 fitBiasArr = evaler(indices, coeffs)
620 elif 'SPLINE' in fitType:
629 collapsedMask = collapsed.mask
631 if collapsedMask == numpy.ma.nomask:
632 collapsedMask = numpy.array(len(collapsed)*[numpy.ma.nomask])
636 numPerBin, binEdges = numpy.histogram(indices, bins=numBins,
637 weights=1-collapsedMask.astype(int))
640 with numpy.errstate(invalid=
"ignore"):
641 values = numpy.histogram(indices, bins=numBins,
642 weights=collapsed.data*~collapsedMask)[0]/numPerBin
643 binCenters = numpy.histogram(indices, bins=numBins,
644 weights=indices*~collapsedMask)[0]/numPerBin
646 values.astype(float)[numPerBin > 0],
648 fitBiasArr = numpy.array([interp.interpolate(i)
for i
in indices])
652 import matplotlib.pyplot
as plot
653 figure = plot.figure(1)
655 axes = figure.add_axes((0.1, 0.1, 0.8, 0.8))
656 axes.plot(indices[~collapsedMask], collapsed[~collapsedMask],
'k+')
657 if collapsedMask.sum() > 0:
658 axes.plot(indices[collapsedMask], collapsed.data[collapsedMask],
'b+')
659 axes.plot(indices, fitBiasArr,
'r-')
660 plot.xlabel(
"centered/scaled position along overscan region")
661 plot.ylabel(
"pixel value/fit value")
663 prompt =
"Press Enter or c to continue [chp]... " 665 ans = input(prompt).lower()
666 if ans
in (
"",
"c",):
672 print(
"h[elp] c[ontinue] p[db]")
675 offImage = ampImage.Factory(ampImage.getDimensions())
676 offArray = offImage.getArray()
677 overscanFit = afwImage.ImageF(overscanImage.getDimensions())
678 overscanArray = overscanFit.getArray()
680 offArray[:, :] = fitBiasArr[:, numpy.newaxis]
681 overscanArray[:, :] = fitBiasArr[:, numpy.newaxis]
683 offArray[:, :] = fitBiasArr[numpy.newaxis, :]
684 overscanArray[:, :] = fitBiasArr[numpy.newaxis, :]
692 mask = ampMaskedImage.getMask()
693 maskArray = mask.getArray()
if shortInd == 1
else mask.getArray().transpose()
694 suspect = mask.getPlaneBitMask(
"SUSPECT")
696 if collapsed.mask == numpy.ma.nomask:
700 for low
in range(num):
701 if not collapsed.mask[low]:
704 maskArray[:low, :] |= suspect
705 for high
in range(1, num):
706 if not collapsed.mask[-high]:
709 maskArray[-high:, :] |= suspect
712 raise pexExcept.Exception(
'%s : %s an invalid overscan type' % (
"overscanCorrection", fitType))
714 overscanImage -= overscanFit
715 return Struct(imageFit=offImage, overscanFit=overscanFit, overscanImage=overscanImage)
719 """Apply brighter fatter correction in place for the image. 723 exposure : `lsst.afw.image.Exposure` 724 Exposure to have brighter-fatter correction applied. Modified 726 kernel : `numpy.ndarray` 727 Brighter-fatter kernel to apply. 729 Number of correction iterations to run. 731 Convergence threshold in terms of the sum of absolute 732 deviations between an iteration and the previous one. 734 If True, then the exposure values are scaled by the gain prior 739 This correction takes a kernel that has been derived from flat 740 field images to redistribute the charge. The gradient of the 741 kernel is the deflection field due to the accumulated charge. 743 Given the original image I(x) and the kernel K(x) we can compute 744 the corrected image Ic(x) using the following equation: 746 Ic(x) = I(x) + 0.5*d/dx(I(x)*d/dx(int( dy*K(x-y)*I(y)))) 748 To evaluate the derivative term we expand it as follows: 750 0.5 * ( d/dx(I(x))*d/dx(int(dy*K(x-y)*I(y))) + I(x)*d^2/dx^2(int(dy* K(x-y)*I(y))) ) 752 Because we use the measured counts instead of the incident counts 753 we apply the correction iteratively to reconstruct the original 754 counts and the correction. We stop iterating when the summed 755 difference between the current corrected image and the one from 756 the previous iteration is below the threshold. We do not require 757 convergence because the number of iterations is too large a 758 computational cost. How we define the threshold still needs to be 759 evaluated, the current default was shown to work reasonably well 760 on a small set of images. For more information on the method see 761 DocuShare Document-19407. 763 The edges as defined by the kernel are not corrected because they 764 have spurious values due to the convolution. 766 image = exposure.getMaskedImage().getImage()
771 kLx = numpy.shape(kernel)[0]
772 kLy = numpy.shape(kernel)[1]
773 kernelImage = afwImage.ImageD(kLx, kLy)
774 kernelImage.getArray()[:, :] = kernel
775 tempImage = image.clone()
777 nanIndex = numpy.isnan(tempImage.getArray())
778 tempImage.getArray()[nanIndex] = 0.
780 outImage = afwImage.ImageF(image.getDimensions())
781 corr = numpy.zeros_like(image.getArray())
782 prev_image = numpy.zeros_like(image.getArray())
794 for iteration
in range(maxIter):
797 tmpArray = tempImage.getArray()
798 outArray = outImage.getArray()
800 with numpy.errstate(invalid=
"ignore", over=
"ignore"):
802 gradTmp = numpy.gradient(tmpArray[startY:endY, startX:endX])
803 gradOut = numpy.gradient(outArray[startY:endY, startX:endX])
804 first = (gradTmp[0]*gradOut[0] + gradTmp[1]*gradOut[1])[1:-1, 1:-1]
807 diffOut20 = numpy.diff(outArray, 2, 0)[startY:endY, startX + 1:endX - 1]
808 diffOut21 = numpy.diff(outArray, 2, 1)[startY + 1:endY - 1, startX:endX]
809 second = tmpArray[startY + 1:endY - 1, startX + 1:endX - 1]*(diffOut20 + diffOut21)
811 corr[startY + 1:endY - 1, startX + 1:endX - 1] = 0.5*(first + second)
813 tmpArray[:, :] = image.getArray()[:, :]
814 tmpArray[nanIndex] = 0.
815 tmpArray[startY:endY, startX:endX] += corr[startY:endY, startX:endX]
818 diff = numpy.sum(numpy.abs(prev_image - tmpArray))
822 prev_image[:, :] = tmpArray[:, :]
829 image.getArray()[startY + 1:endY - 1, startX + 1:endX - 1] += \
830 corr[startY + 1:endY - 1, startX + 1:endX - 1]
835 """Context manager that applies and removes gain. 839 exp : `lsst.afw.image.Exposure` 840 Exposure to apply/remove gain. 841 image : `lsst.afw.image.Image` 842 Image to apply/remove gain. 844 If True, apply and remove the amplifier gain. 848 exp : `lsst.afw.image.Exposure` 849 Exposure with the gain applied. 852 ccd = exp.getDetector()
854 sim = image.Factory(image, amp.getBBox())
861 ccd = exp.getDetector()
863 sim = image.Factory(image, amp.getBBox())
868 sensorTransmission=None, atmosphereTransmission=None):
869 """Attach a TransmissionCurve to an Exposure, given separate curves for 870 different components. 874 exposure : `lsst.afw.image.Exposure` 875 Exposure object to modify by attaching the product of all given 876 ``TransmissionCurves`` in post-assembly trimmed detector coordinates. 877 Must have a valid ``Detector`` attached that matches the detector 878 associated with sensorTransmission. 879 opticsTransmission : `lsst.afw.image.TransmissionCurve` 880 A ``TransmissionCurve`` that represents the throughput of the optics, 881 to be evaluated in focal-plane coordinates. 882 filterTransmission : `lsst.afw.image.TransmissionCurve` 883 A ``TransmissionCurve`` that represents the throughput of the filter 884 itself, to be evaluated in focal-plane coordinates. 885 sensorTransmission : `lsst.afw.image.TransmissionCurve` 886 A ``TransmissionCurve`` that represents the throughput of the sensor 887 itself, to be evaluated in post-assembly trimmed detector coordinates. 888 atmosphereTransmission : `lsst.afw.image.TransmissionCurve` 889 A ``TransmissionCurve`` that represents the throughput of the 890 atmosphere, assumed to be spatially constant. 894 combined : `lsst.afw.image.TransmissionCurve` 895 The TransmissionCurve attached to the exposure. 899 All ``TransmissionCurve`` arguments are optional; if none are provided, the 900 attached ``TransmissionCurve`` will have unit transmission everywhere. 902 combined = afwImage.TransmissionCurve.makeIdentity()
903 if atmosphereTransmission
is not None:
904 combined *= atmosphereTransmission
905 if opticsTransmission
is not None:
906 combined *= opticsTransmission
907 if filterTransmission
is not None:
908 combined *= filterTransmission
909 detector = exposure.getDetector()
910 fpToPix = detector.getTransform(fromSys=camGeom.FOCAL_PLANE,
911 toSys=camGeom.PIXELS)
912 combined = combined.transformedBy(fpToPix)
913 if sensorTransmission
is not None:
914 combined *= sensorTransmission
915 exposure.getInfo().setTransmissionCurve(combined)
920 """!Update the WCS in exposure with a distortion model based on camera 925 exposure : `lsst.afw.image.Exposure` 926 Exposure to process. Must contain a Detector and WCS. The 927 exposure is modified. 928 camera : `lsst.afw.cameraGeom.Camera` 934 Raised if ``exposure`` is lacking a Detector or WCS, or if 938 Add a model for optical distortion based on geometry found in ``camera`` 939 and the ``exposure``'s detector. The raw input exposure is assumed 940 have a TAN WCS that has no compensation for optical distortion. 941 Two other possibilities are: 942 - The raw input exposure already has a model for optical distortion, 943 as is the case for raw DECam data. 944 In that case you should set config.doAddDistortionModel False. 945 - The raw input exposure has a model for distortion, but it has known 946 deficiencies severe enough to be worth fixing (e.g. because they 947 cause problems for fitting a better WCS). In that case you should 948 override this method with a version suitable for your raw data. 951 wcs = exposure.getWcs()
953 raise RuntimeError(
"exposure has no WCS")
955 raise RuntimeError(
"camera is None")
956 detector = exposure.getDetector()
958 raise RuntimeError(
"exposure has no Detector")
959 pixelToFocalPlane = detector.getTransform(camGeom.PIXELS, camGeom.FOCAL_PLANE)
960 focalPlaneToFieldAngle = camera.getTransformMap().getTransform(camGeom.FOCAL_PLANE,
963 exposure.setWcs(distortedWcs)
967 """Scale an exposure by the amplifier gains. 971 exposure : `lsst.afw.image.Exposure` 972 Exposure to process. The image is modified. 973 normalizeGains : `Bool`, optional 974 If True, then amplifiers are scaled to force the median of 975 each amplifier to equal the median of those medians. 977 ccd = exposure.getDetector()
978 ccdImage = exposure.getMaskedImage()
982 sim = ccdImage.Factory(ccdImage, amp.getBBox())
986 medians.append(numpy.median(sim.getImage().getArray()))
989 median = numpy.median(numpy.array(medians))
990 for index, amp
in enumerate(ccd):
991 sim = ccdImage.Factory(ccdImage, amp.getBBox())
992 if medians[index] != 0.0:
993 sim *= median/medians[index]
997 """Grow the saturation trails by an amount dependent on the width of the trail. 1001 mask : `lsst.afw.image.Mask` 1002 Mask which will have the saturated areas grown. 1006 for i
in range(1, 6):
1007 extraGrowDict[i] = 0
1008 for i
in range(6, 8):
1009 extraGrowDict[i] = 1
1010 for i
in range(8, 10):
1011 extraGrowDict[i] = 3
1014 if extraGrowMax <= 0:
1017 saturatedBit = mask.getPlaneBitMask(
"SAT")
1019 xmin, ymin = mask.getBBox().getMin()
1020 width = mask.getWidth()
1022 thresh = afwDetection.Threshold(saturatedBit, afwDetection.Threshold.BITMASK)
1023 fpList = afwDetection.FootprintSet(mask, thresh).getFootprints()
1026 for s
in fp.getSpans():
1027 x0, x1 = s.getX0(), s.getX1()
1029 extraGrow = extraGrowDict.get(x1 - x0 + 1, extraGrowMax)
1032 x0 -= xmin + extraGrow
1033 x1 -= xmin - extraGrow
1040 mask.array[y, x0:x1+1] |= saturatedBit
1044 """Set all BAD areas of the chip to the average of the rest of the exposure 1048 exposure : `lsst.afw.image.Exposure` 1049 Exposure to mask. The exposure mask is modified. 1050 badStatistic : `str`, optional 1051 Statistic to use to generate the replacement value from the 1052 image data. Allowed values are 'MEDIAN' or 'MEANCLIP'. 1056 badPixelCount : scalar 1057 Number of bad pixels masked. 1058 badPixelValue : scalar 1059 Value substituted for bad pixels. 1064 Raised if `badStatistic` is not an allowed value. 1066 if badStatistic ==
"MEDIAN":
1067 statistic = afwMath.MEDIAN
1068 elif badStatistic ==
"MEANCLIP":
1069 statistic = afwMath.MEANCLIP
1071 raise RuntimeError(
"Impossible method %s of bad region correction" % badStatistic)
1073 mi = exposure.getMaskedImage()
1075 BAD = mask.getPlaneBitMask(
"BAD")
1076 INTRP = mask.getPlaneBitMask(
"INTRP")
1079 sctrl.setAndMask(BAD)
1082 maskArray = mask.getArray()
1083 imageArray = mi.getImage().getArray()
1084 badPixels = numpy.logical_and((maskArray & BAD) > 0, (maskArray & INTRP) == 0)
1085 imageArray[:] = numpy.where(badPixels, value, imageArray)
1087 return badPixels.sum(), value
def illuminationCorrection(maskedImage, illumMaskedImage, illumScale)
Interpolate::Style stringToInterpStyle(std::string const &style)
Conversion function to switch a string to an Interpolate::Style.
def addDistortionModel(exposure, camera)
Update the WCS in exposure with a distortion model based on camera geometry.
def saturationCorrection(maskedImage, saturation, fwhm, growFootprints=1, interpolate=True, maskName='SAT', fallbackValue=None)
def setBadRegions(exposure, badStatistic="MEDIAN")
def brighterFatterCorrection(exposure, kernel, maxIter, threshold, applyGain)
def transposeDefectList(defectList)
Parameters to control convolution.
def getDefectListFromMask(maskedImage, maskName)
def interpolateFromMask(maskedImage, fwhm, growSaturatedFootprints=1, maskNameList=['SAT'], fallbackValue=None)
def interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=None)
def defectListFromFootprintList(fpList)
Provides consistent interface for LSST exceptions.
def transposeMaskedImage(maskedImage)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
def trimToMatchCalibBBox(rawMaskedImage, calibMaskedImage)
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 attachTransmissionCurve(exposure, opticsTransmission=None, filterTransmission=None, sensorTransmission=None, atmosphereTransmission=None)
Property stringToStatisticsProperty(std::string const property)
Conversion function to switch a string to a Property (see Statistics.h)
Pass parameters to a Statistics object.
def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False, trimToFit=False)
def makeThresholdMask(maskedImage, threshold, growFootprints=1, maskName='SAT')
std::shared_ptr< Interpolate > makeInterpolate(ndarray::Array< double const, 1 > const &x, ndarray::Array< double const, 1 > const &y, Interpolate::Style const style=Interpolate::AKIMA_SPLINE)
def widenSaturationTrails(mask)
def applyGains(exposure, normalizeGains=False)
def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False, trimToFit=False)
def makeDistortedTanWcs(tanWcs, pixelToFocalPlane, focalPlaneToFieldAngle)
def biasCorrection(maskedImage, biasMaskedImage, trimToFit=False)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)
Old, deprecated version of convolve.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
def gainContext(exp, image, apply)
def updateVariance(maskedImage, gain, readNoise)
def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0, statControl=None, overscanIsInt=True)
A kernel created from an Image.
def maskPixelsFromDefectList(maskedImage, defectList, maskName='BAD')