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)
103 """Mask pixels based on threshold detection. 107 maskedImage : `lsst.afw.image.MaskedImage` 108 Image to process. Only the mask plane is updated. 111 growFootprints : scalar, optional 112 Number of pixels to grow footprints of detected regions. 113 maskName : str, optional 114 Mask plane name, or list of names to convert 118 defectList : `lsst.meas.algorithms.Defects` 119 Defect list constructed from pixels above the threshold. 122 thresh = afwDetection.Threshold(threshold)
123 fs = afwDetection.FootprintSet(maskedImage, thresh)
125 if growFootprints > 0:
126 fs = afwDetection.FootprintSet(fs, rGrow=growFootprints, isotropic=
False)
127 fpList = fs.getFootprints()
130 mask = maskedImage.getMask()
131 bitmask = mask.getPlaneBitMask(maskName)
132 afwDetection.setMaskFromFootprintList(mask, fpList, bitmask)
134 return measAlg.Defects.fromFootprintList(fpList)
138 maskNameList=['SAT'], fallbackValue=None):
139 """Interpolate over defects identified by a particular set of mask planes. 143 maskedImage : `lsst.afw.image.MaskedImage` 146 FWHM of double Gaussian smoothing kernel. 147 growSaturatedFootprints : scalar, optional 148 Number of pixels to grow footprints for saturated pixels. 149 maskNameList : `List` of `str`, optional 151 fallbackValue : scalar, optional 152 Value of last resort for interpolation. 154 mask = maskedImage.getMask()
156 if growSaturatedFootprints > 0
and "SAT" in maskNameList:
157 thresh = afwDetection.Threshold(mask.getPlaneBitMask(
"SAT"), afwDetection.Threshold.BITMASK)
158 fpSet = afwDetection.FootprintSet(mask, thresh)
161 fpSet = afwDetection.FootprintSet(fpSet, rGrow=growSaturatedFootprints, isotropic=
False)
162 fpSet.setMask(mask,
"SAT")
164 thresh = afwDetection.Threshold(mask.getPlaneBitMask(maskNameList), afwDetection.Threshold.BITMASK)
165 fpSet = afwDetection.FootprintSet(mask, thresh)
166 defectList = measAlg.Defects.fromFootprintList(fpSet.getFootprints())
173 def saturationCorrection(maskedImage, saturation, fwhm, growFootprints=1, interpolate=True, maskName='SAT',
175 """Mark saturated pixels and optionally interpolate over them 179 maskedImage : `lsst.afw.image.MaskedImage` 182 Saturation level used as the detection threshold. 184 FWHM of double Gaussian smoothing kernel. 185 growFootprints : scalar, optional 186 Number of pixels to grow footprints of detected regions. 187 interpolate : Bool, optional 188 If True, saturated pixels are interpolated over. 189 maskName : str, optional 191 fallbackValue : scalar, optional 192 Value of last resort for interpolation. 195 maskedImage=maskedImage,
196 threshold=saturation,
197 growFootprints=growFootprints,
207 """Compute number of edge trim pixels to match the calibration data. 209 Use the dimension difference between the raw exposure and the 210 calibration exposure to compute the edge trim pixels. This trim 211 is applied symmetrically, with the same number of pixels masked on 216 rawMaskedImage : `lsst.afw.image.MaskedImage` 218 calibMaskedImage : `lsst.afw.image.MaskedImage` 219 Calibration image to draw new bounding box from. 223 replacementMaskedImage : `lsst.afw.image.MaskedImage` 224 ``rawMaskedImage`` trimmed to the appropriate size 228 Rasied if ``rawMaskedImage`` cannot be symmetrically trimmed to 229 match ``calibMaskedImage``. 231 nx, ny = rawMaskedImage.getBBox().getDimensions() - calibMaskedImage.getBBox().getDimensions()
233 raise RuntimeError(
"Raw and calib maskedImages are trimmed differently in X and Y.")
235 raise RuntimeError(
"Calibration maskedImage is trimmed unevenly in X.")
237 raise RuntimeError(
"Calibration maskedImage is larger than raw data.")
241 replacementMaskedImage = rawMaskedImage[nEdge:-nEdge, nEdge:-nEdge, afwImage.LOCAL]
242 SourceDetectionTask.setEdgeBits(
244 replacementMaskedImage.getBBox(),
245 rawMaskedImage.getMask().getPlaneBitMask(
"EDGE")
248 replacementMaskedImage = rawMaskedImage
250 return replacementMaskedImage
254 """Apply bias correction in place. 258 maskedImage : `lsst.afw.image.MaskedImage` 259 Image to process. The image is modified by this method. 260 biasMaskedImage : `lsst.afw.image.MaskedImage` 261 Bias image of the same size as ``maskedImage`` 262 trimToFit : `Bool`, optional 263 If True, raw data is symmetrically trimmed to match 269 Raised if ``maskedImage`` and ``biasMaskedImage`` do not have 276 if maskedImage.getBBox(afwImage.LOCAL) != biasMaskedImage.getBBox(afwImage.LOCAL):
277 raise RuntimeError(
"maskedImage bbox %s != biasMaskedImage bbox %s" %
278 (maskedImage.getBBox(afwImage.LOCAL), biasMaskedImage.getBBox(afwImage.LOCAL)))
279 maskedImage -= biasMaskedImage
282 def darkCorrection(maskedImage, darkMaskedImage, expScale, darkScale, invert=False, trimToFit=False):
283 """Apply dark correction in place. 287 maskedImage : `lsst.afw.image.MaskedImage` 288 Image to process. The image is modified by this method. 289 darkMaskedImage : `lsst.afw.image.MaskedImage` 290 Dark image of the same size as ``maskedImage``. 292 Dark exposure time for ``maskedImage``. 294 Dark exposure time for ``darkMaskedImage``. 295 invert : `Bool`, optional 296 If True, re-add the dark to an already corrected image. 297 trimToFit : `Bool`, optional 298 If True, raw data is symmetrically trimmed to match 304 Raised if ``maskedImage`` and ``darkMaskedImage`` do not have 309 The dark correction is applied by calculating: 310 maskedImage -= dark * expScaling / darkScaling 315 if maskedImage.getBBox(afwImage.LOCAL) != darkMaskedImage.getBBox(afwImage.LOCAL):
316 raise RuntimeError(
"maskedImage bbox %s != darkMaskedImage bbox %s" %
317 (maskedImage.getBBox(afwImage.LOCAL), darkMaskedImage.getBBox(afwImage.LOCAL)))
319 scale = expScale / darkScale
321 maskedImage.scaledMinus(scale, darkMaskedImage)
323 maskedImage.scaledPlus(scale, darkMaskedImage)
327 """Set the variance plane based on the image plane. 331 maskedImage : `lsst.afw.image.MaskedImage` 332 Image to process. The variance plane is modified. 334 The amplifier gain in electrons/ADU. 336 The amplifier read nmoise in ADU/pixel. 338 var = maskedImage.getVariance()
339 var[:] = maskedImage.getImage()
344 def flatCorrection(maskedImage, flatMaskedImage, scalingType, userScale=1.0, invert=False, trimToFit=False):
345 """Apply flat correction in place. 349 maskedImage : `lsst.afw.image.MaskedImage` 350 Image to process. The image is modified. 351 flatMaskedImage : `lsst.afw.image.MaskedImage` 352 Flat image of the same size as ``maskedImage`` 354 Flat scale computation method. Allowed values are 'MEAN', 356 userScale : scalar, optional 357 Scale to use if ``scalingType``='USER'. 358 invert : `Bool`, optional 359 If True, unflatten an already flattened image. 360 trimToFit : `Bool`, optional 361 If True, raw data is symmetrically trimmed to match 367 Raised if ``maskedImage`` and ``flatMaskedImage`` do not have 368 the same size or if ``scalingType`` is not an allowed value. 373 if maskedImage.getBBox(afwImage.LOCAL) != flatMaskedImage.getBBox(afwImage.LOCAL):
374 raise RuntimeError(
"maskedImage bbox %s != flatMaskedImage bbox %s" %
375 (maskedImage.getBBox(afwImage.LOCAL), flatMaskedImage.getBBox(afwImage.LOCAL)))
380 if scalingType
in (
'MEAN',
'MEDIAN'):
383 elif scalingType ==
'USER':
384 flatScale = userScale
386 raise RuntimeError(
'%s : %s not implemented' % (
"flatCorrection", scalingType))
389 maskedImage.scaledDivides(1.0/flatScale, flatMaskedImage)
391 maskedImage.scaledMultiplies(1.0/flatScale, flatMaskedImage)
395 """Apply illumination correction in place. 399 maskedImage : `lsst.afw.image.MaskedImage` 400 Image to process. The image is modified. 401 illumMaskedImage : `lsst.afw.image.MaskedImage` 402 Illumination correction image of the same size as ``maskedImage``. 404 Scale factor for the illumination correction. 405 trimToFit : `Bool`, optional 406 If True, raw data is symmetrically trimmed to match 412 Raised if ``maskedImage`` and ``illumMaskedImage`` do not have 418 if maskedImage.getBBox(afwImage.LOCAL) != illumMaskedImage.getBBox(afwImage.LOCAL):
419 raise RuntimeError(
"maskedImage bbox %s != illumMaskedImage bbox %s" %
420 (maskedImage.getBBox(afwImage.LOCAL), illumMaskedImage.getBBox(afwImage.LOCAL)))
422 maskedImage.scaledDivides(1.0/illumScale, illumMaskedImage)
425 def overscanCorrection(ampMaskedImage, overscanImage, fitType='MEDIAN', order=1, collapseRej=3.0,
426 statControl=None, overscanIsInt=True):
427 """Apply overscan correction in place. 431 ampMaskedImage : `lsst.afw.image.MaskedImage` 432 Image of amplifier to correct; modified. 433 overscanImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 434 Image of overscan; modified. 436 Type of fit for overscan correction. May be one of: 438 - ``MEAN``: use mean of overscan. 439 - ``MEANCLIP``: use clipped mean of overscan. 440 - ``MEDIAN``: use median of overscan. 441 - ``POLY``: fit with ordinary polynomial. 442 - ``CHEB``: fit with Chebyshev polynomial. 443 - ``LEG``: fit with Legendre polynomial. 444 - ``NATURAL_SPLINE``: fit with natural spline. 445 - ``CUBIC_SPLINE``: fit with cubic spline. 446 - ``AKIMA_SPLINE``: fit with Akima spline. 449 Polynomial order or number of spline knots; ignored unless 450 ``fitType`` indicates a polynomial or spline. 451 statControl : `lsst.afw.math.StatisticsControl` 452 Statistics control object. In particular, we pay attention to numSigmaClip 453 overscanIsInt : `bool` 454 Treat the overscan region as consisting of integers, even if it's been 455 converted to float. E.g. handle ties properly. 459 result : `lsst.pipe.base.Struct` 460 Result struct with components: 462 - ``imageFit``: Value(s) removed from image (scalar or 463 `lsst.afw.image.Image`) 464 - ``overscanFit``: Value(s) removed from overscan (scalar or 465 `lsst.afw.image.Image`) 466 - ``overscanImage``: Overscan corrected overscan region 467 (`lsst.afw.image.Image`) 471 Raised if ``fitType`` is not an allowed value. 475 The ``ampMaskedImage`` and ``overscanImage`` are modified, with the fit 476 subtracted. Note that the ``overscanImage`` should not be a subimage of 477 the ``ampMaskedImage``, to avoid being subtracted twice. 479 Debug plots are available for the SPLINE fitTypes by setting the 480 `debug.display` for `name` == "lsst.ip.isr.isrFunctions". These 481 plots show the scatter plot of the overscan data (collapsed along 482 the perpendicular dimension) as a function of position on the CCD 483 (normalized between +/-1). 485 ampImage = ampMaskedImage.getImage()
486 if statControl
is None:
489 numSigmaClip = statControl.getNumSigmaClip()
491 if fitType
in (
'MEAN',
'MEANCLIP'):
494 overscanFit = offImage
495 elif fitType
in (
'MEDIAN',):
498 if hasattr(overscanImage,
"image"):
499 imageI = overscanImage.image.convertI()
500 overscanImageI = afwImage.MaskedImageI(imageI, overscanImage.mask, overscanImage.variance)
502 overscanImageI = overscanImage.convertI()
504 overscanImageI = overscanImage
508 overscanFit = offImage
512 elif fitType
in (
'POLY',
'CHEB',
'LEG',
'NATURAL_SPLINE',
'CUBIC_SPLINE',
'AKIMA_SPLINE'):
513 if hasattr(overscanImage,
"getImage"):
514 biasArray = overscanImage.getImage().getArray()
515 biasArray = numpy.ma.masked_where(overscanImage.getMask().getArray() & statControl.getAndMask(),
518 biasArray = overscanImage.getArray()
520 shortInd = numpy.argmin(biasArray.shape)
523 biasArray = numpy.transpose(biasArray)
526 percentiles = numpy.percentile(biasArray, [25.0, 50.0, 75.0], axis=1)
527 medianBiasArr = percentiles[1]
528 stdevBiasArr = 0.74*(percentiles[2] - percentiles[0])
529 diff = numpy.abs(biasArray - medianBiasArr[:, numpy.newaxis])
530 biasMaskedArr = numpy.ma.masked_where(diff > numSigmaClip*stdevBiasArr[:, numpy.newaxis], biasArray)
531 collapsed = numpy.mean(biasMaskedArr, axis=1)
532 if collapsed.mask.sum() > 0:
533 collapsed.data[collapsed.mask] = numpy.mean(biasArray.data[collapsed.mask], axis=1)
534 del biasArray, percentiles, stdevBiasArr, diff, biasMaskedArr
537 collapsed = numpy.transpose(collapsed)
540 indices = 2.0*numpy.arange(num)/float(num) - 1.0
542 if fitType
in (
'POLY',
'CHEB',
'LEG'):
544 poly = numpy.polynomial
545 fitter, evaler = {
"POLY": (poly.polynomial.polyfit, poly.polynomial.polyval),
546 "CHEB": (poly.chebyshev.chebfit, poly.chebyshev.chebval),
547 "LEG": (poly.legendre.legfit, poly.legendre.legval),
550 coeffs =
fitter(indices, collapsed, order)
551 fitBiasArr = evaler(indices, coeffs)
552 elif 'SPLINE' in fitType:
561 collapsedMask = collapsed.mask
563 if collapsedMask == numpy.ma.nomask:
564 collapsedMask = numpy.array(len(collapsed)*[numpy.ma.nomask])
568 numPerBin, binEdges = numpy.histogram(indices, bins=numBins,
569 weights=1-collapsedMask.astype(int))
572 with numpy.errstate(invalid=
"ignore"):
573 values = numpy.histogram(indices, bins=numBins,
574 weights=collapsed.data*~collapsedMask)[0]/numPerBin
575 binCenters = numpy.histogram(indices, bins=numBins,
576 weights=indices*~collapsedMask)[0]/numPerBin
578 values.astype(float)[numPerBin > 0],
580 fitBiasArr = numpy.array([interp.interpolate(i)
for i
in indices])
584 import matplotlib.pyplot
as plot
585 figure = plot.figure(1)
587 axes = figure.add_axes((0.1, 0.1, 0.8, 0.8))
588 axes.plot(indices[~collapsedMask], collapsed[~collapsedMask],
'k+')
589 if collapsedMask.sum() > 0:
590 axes.plot(indices[collapsedMask], collapsed.data[collapsedMask],
'b+')
591 axes.plot(indices, fitBiasArr,
'r-')
592 plot.xlabel(
"centered/scaled position along overscan region")
593 plot.ylabel(
"pixel value/fit value")
595 prompt =
"Press Enter or c to continue [chp]... " 597 ans = input(prompt).lower()
598 if ans
in (
"",
"c",):
604 print(
"h[elp] c[ontinue] p[db]")
607 offImage = ampImage.Factory(ampImage.getDimensions())
608 offArray = offImage.getArray()
609 overscanFit = afwImage.ImageF(overscanImage.getDimensions())
610 overscanArray = overscanFit.getArray()
612 offArray[:, :] = fitBiasArr[:, numpy.newaxis]
613 overscanArray[:, :] = fitBiasArr[:, numpy.newaxis]
615 offArray[:, :] = fitBiasArr[numpy.newaxis, :]
616 overscanArray[:, :] = fitBiasArr[numpy.newaxis, :]
624 mask = ampMaskedImage.getMask()
625 maskArray = mask.getArray()
if shortInd == 1
else mask.getArray().transpose()
626 suspect = mask.getPlaneBitMask(
"SUSPECT")
628 if collapsed.mask == numpy.ma.nomask:
632 for low
in range(num):
633 if not collapsed.mask[low]:
636 maskArray[:low, :] |= suspect
637 for high
in range(1, num):
638 if not collapsed.mask[-high]:
641 maskArray[-high:, :] |= suspect
644 raise pexExcept.Exception(
'%s : %s an invalid overscan type' % (
"overscanCorrection", fitType))
646 overscanImage -= overscanFit
647 return Struct(imageFit=offImage, overscanFit=overscanFit, overscanImage=overscanImage)
651 """Apply brighter fatter correction in place for the image. 655 exposure : `lsst.afw.image.Exposure` 656 Exposure to have brighter-fatter correction applied. Modified 658 kernel : `numpy.ndarray` 659 Brighter-fatter kernel to apply. 661 Number of correction iterations to run. 663 Convergence threshold in terms of the sum of absolute 664 deviations between an iteration and the previous one. 666 If True, then the exposure values are scaled by the gain prior 672 Final difference between iterations achieved in correction. 674 Number of iterations used to calculate correction. 678 This correction takes a kernel that has been derived from flat 679 field images to redistribute the charge. The gradient of the 680 kernel is the deflection field due to the accumulated charge. 682 Given the original image I(x) and the kernel K(x) we can compute 683 the corrected image Ic(x) using the following equation: 685 Ic(x) = I(x) + 0.5*d/dx(I(x)*d/dx(int( dy*K(x-y)*I(y)))) 687 To evaluate the derivative term we expand it as follows: 689 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))) ) 691 Because we use the measured counts instead of the incident counts 692 we apply the correction iteratively to reconstruct the original 693 counts and the correction. We stop iterating when the summed 694 difference between the current corrected image and the one from 695 the previous iteration is below the threshold. We do not require 696 convergence because the number of iterations is too large a 697 computational cost. How we define the threshold still needs to be 698 evaluated, the current default was shown to work reasonably well 699 on a small set of images. For more information on the method see 700 DocuShare Document-19407. 702 The edges as defined by the kernel are not corrected because they 703 have spurious values due to the convolution. 705 image = exposure.getMaskedImage().getImage()
710 kLx = numpy.shape(kernel)[0]
711 kLy = numpy.shape(kernel)[1]
712 kernelImage = afwImage.ImageD(kLx, kLy)
713 kernelImage.getArray()[:, :] = kernel
714 tempImage = image.clone()
716 nanIndex = numpy.isnan(tempImage.getArray())
717 tempImage.getArray()[nanIndex] = 0.
719 outImage = afwImage.ImageF(image.getDimensions())
720 corr = numpy.zeros_like(image.getArray())
721 prev_image = numpy.zeros_like(image.getArray())
733 for iteration
in range(maxIter):
736 tmpArray = tempImage.getArray()
737 outArray = outImage.getArray()
739 with numpy.errstate(invalid=
"ignore", over=
"ignore"):
741 gradTmp = numpy.gradient(tmpArray[startY:endY, startX:endX])
742 gradOut = numpy.gradient(outArray[startY:endY, startX:endX])
743 first = (gradTmp[0]*gradOut[0] + gradTmp[1]*gradOut[1])[1:-1, 1:-1]
746 diffOut20 = numpy.diff(outArray, 2, 0)[startY:endY, startX + 1:endX - 1]
747 diffOut21 = numpy.diff(outArray, 2, 1)[startY + 1:endY - 1, startX:endX]
748 second = tmpArray[startY + 1:endY - 1, startX + 1:endX - 1]*(diffOut20 + diffOut21)
750 corr[startY + 1:endY - 1, startX + 1:endX - 1] = 0.5*(first + second)
752 tmpArray[:, :] = image.getArray()[:, :]
753 tmpArray[nanIndex] = 0.
754 tmpArray[startY:endY, startX:endX] += corr[startY:endY, startX:endX]
757 diff = numpy.sum(numpy.abs(prev_image - tmpArray))
761 prev_image[:, :] = tmpArray[:, :]
763 image.getArray()[startY + 1:endY - 1, startX + 1:endX - 1] += \
764 corr[startY + 1:endY - 1, startX + 1:endX - 1]
766 return diff, iteration
771 """Context manager that applies and removes gain. 775 exp : `lsst.afw.image.Exposure` 776 Exposure to apply/remove gain. 777 image : `lsst.afw.image.Image` 778 Image to apply/remove gain. 780 If True, apply and remove the amplifier gain. 784 exp : `lsst.afw.image.Exposure` 785 Exposure with the gain applied. 788 ccd = exp.getDetector()
790 sim = image.Factory(image, amp.getBBox())
797 ccd = exp.getDetector()
799 sim = image.Factory(image, amp.getBBox())
804 sensorTransmission=None, atmosphereTransmission=None):
805 """Attach a TransmissionCurve to an Exposure, given separate curves for 806 different components. 810 exposure : `lsst.afw.image.Exposure` 811 Exposure object to modify by attaching the product of all given 812 ``TransmissionCurves`` in post-assembly trimmed detector coordinates. 813 Must have a valid ``Detector`` attached that matches the detector 814 associated with sensorTransmission. 815 opticsTransmission : `lsst.afw.image.TransmissionCurve` 816 A ``TransmissionCurve`` that represents the throughput of the optics, 817 to be evaluated in focal-plane coordinates. 818 filterTransmission : `lsst.afw.image.TransmissionCurve` 819 A ``TransmissionCurve`` that represents the throughput of the filter 820 itself, to be evaluated in focal-plane coordinates. 821 sensorTransmission : `lsst.afw.image.TransmissionCurve` 822 A ``TransmissionCurve`` that represents the throughput of the sensor 823 itself, to be evaluated in post-assembly trimmed detector coordinates. 824 atmosphereTransmission : `lsst.afw.image.TransmissionCurve` 825 A ``TransmissionCurve`` that represents the throughput of the 826 atmosphere, assumed to be spatially constant. 830 combined : `lsst.afw.image.TransmissionCurve` 831 The TransmissionCurve attached to the exposure. 835 All ``TransmissionCurve`` arguments are optional; if none are provided, the 836 attached ``TransmissionCurve`` will have unit transmission everywhere. 838 combined = afwImage.TransmissionCurve.makeIdentity()
839 if atmosphereTransmission
is not None:
840 combined *= atmosphereTransmission
841 if opticsTransmission
is not None:
842 combined *= opticsTransmission
843 if filterTransmission
is not None:
844 combined *= filterTransmission
845 detector = exposure.getDetector()
846 fpToPix = detector.getTransform(fromSys=camGeom.FOCAL_PLANE,
847 toSys=camGeom.PIXELS)
848 combined = combined.transformedBy(fpToPix)
849 if sensorTransmission
is not None:
850 combined *= sensorTransmission
851 exposure.getInfo().setTransmissionCurve(combined)
855 @deprecated(reason=
"Camera geometry-based SkyWcs are now set when reading raws. To be removed after v19.",
856 category=FutureWarning)
858 """!Update the WCS in exposure with a distortion model based on camera 863 exposure : `lsst.afw.image.Exposure` 864 Exposure to process. Must contain a Detector and WCS. The 865 exposure is modified. 866 camera : `lsst.afw.cameraGeom.Camera` 872 Raised if ``exposure`` is lacking a Detector or WCS, or if 876 Add a model for optical distortion based on geometry found in ``camera`` 877 and the ``exposure``'s detector. The raw input exposure is assumed 878 have a TAN WCS that has no compensation for optical distortion. 879 Two other possibilities are: 880 - The raw input exposure already has a model for optical distortion, 881 as is the case for raw DECam data. 882 In that case you should set config.doAddDistortionModel False. 883 - The raw input exposure has a model for distortion, but it has known 884 deficiencies severe enough to be worth fixing (e.g. because they 885 cause problems for fitting a better WCS). In that case you should 886 override this method with a version suitable for your raw data. 889 wcs = exposure.getWcs()
891 raise RuntimeError(
"exposure has no WCS")
893 raise RuntimeError(
"camera is None")
894 detector = exposure.getDetector()
896 raise RuntimeError(
"exposure has no Detector")
897 pixelToFocalPlane = detector.getTransform(camGeom.PIXELS, camGeom.FOCAL_PLANE)
898 focalPlaneToFieldAngle = camera.getTransformMap().getTransform(camGeom.FOCAL_PLANE,
901 exposure.setWcs(distortedWcs)
905 """Scale an exposure by the amplifier gains. 909 exposure : `lsst.afw.image.Exposure` 910 Exposure to process. The image is modified. 911 normalizeGains : `Bool`, optional 912 If True, then amplifiers are scaled to force the median of 913 each amplifier to equal the median of those medians. 915 ccd = exposure.getDetector()
916 ccdImage = exposure.getMaskedImage()
920 sim = ccdImage.Factory(ccdImage, amp.getBBox())
924 medians.append(numpy.median(sim.getImage().getArray()))
927 median = numpy.median(numpy.array(medians))
928 for index, amp
in enumerate(ccd):
929 sim = ccdImage.Factory(ccdImage, amp.getBBox())
930 if medians[index] != 0.0:
931 sim *= median/medians[index]
935 """Grow the saturation trails by an amount dependent on the width of the trail. 939 mask : `lsst.afw.image.Mask` 940 Mask which will have the saturated areas grown. 944 for i
in range(1, 6):
946 for i
in range(6, 8):
948 for i
in range(8, 10):
952 if extraGrowMax <= 0:
955 saturatedBit = mask.getPlaneBitMask(
"SAT")
957 xmin, ymin = mask.getBBox().getMin()
958 width = mask.getWidth()
960 thresh = afwDetection.Threshold(saturatedBit, afwDetection.Threshold.BITMASK)
961 fpList = afwDetection.FootprintSet(mask, thresh).getFootprints()
964 for s
in fp.getSpans():
965 x0, x1 = s.getX0(), s.getX1()
967 extraGrow = extraGrowDict.get(x1 - x0 + 1, extraGrowMax)
970 x0 -= xmin + extraGrow
971 x1 -= xmin - extraGrow
978 mask.array[y, x0:x1+1] |= saturatedBit
982 """Set all BAD areas of the chip to the average of the rest of the exposure 986 exposure : `lsst.afw.image.Exposure` 987 Exposure to mask. The exposure mask is modified. 988 badStatistic : `str`, optional 989 Statistic to use to generate the replacement value from the 990 image data. Allowed values are 'MEDIAN' or 'MEANCLIP'. 994 badPixelCount : scalar 995 Number of bad pixels masked. 996 badPixelValue : scalar 997 Value substituted for bad pixels. 1002 Raised if `badStatistic` is not an allowed value. 1004 if badStatistic ==
"MEDIAN":
1005 statistic = afwMath.MEDIAN
1006 elif badStatistic ==
"MEANCLIP":
1007 statistic = afwMath.MEANCLIP
1009 raise RuntimeError(
"Impossible method %s of bad region correction" % badStatistic)
1011 mi = exposure.getMaskedImage()
1013 BAD = mask.getPlaneBitMask(
"BAD")
1014 INTRP = mask.getPlaneBitMask(
"INTRP")
1017 sctrl.setAndMask(BAD)
1020 maskArray = mask.getArray()
1021 imageArray = mi.getImage().getArray()
1022 badPixels = numpy.logical_and((maskArray & BAD) > 0, (maskArray & INTRP) == 0)
1023 imageArray[:] = numpy.where(badPixels, value, imageArray)
1025 return badPixels.sum(), value
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)
Parameters to control convolution.
def interpolateFromMask(maskedImage, fwhm, growSaturatedFootprints=1, maskNameList=['SAT'], fallbackValue=None)
def interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=None)
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 illuminationCorrection(maskedImage, illumMaskedImage, illumScale, trimToFit=True)
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.