22__all__ = [
"OverscanCorrectionTaskConfig",
"OverscanCorrectionTask"]
31from .isr
import fitOverscanImage
32from .isrFunctions
import makeThresholdMask
36 """Overscan correction options.
38 fitType = pexConfig.ChoiceField(
40 doc="The method for fitting the overscan bias level.",
43 "POLY":
"Fit ordinary polynomial to the longest axis of the overscan region",
44 "CHEB":
"Fit Chebyshev polynomial to the longest axis of the overscan region",
45 "LEG":
"Fit Legendre polynomial to the longest axis of the overscan region",
46 "NATURAL_SPLINE":
"Fit natural spline to the longest axis of the overscan region",
47 "CUBIC_SPLINE":
"Fit cubic spline to the longest axis of the overscan region",
48 "AKIMA_SPLINE":
"Fit Akima spline to the longest axis of the overscan region",
49 "MEAN":
"Correct using the mean of the overscan region",
50 "MEANCLIP":
"Correct using a clipped mean of the overscan region",
51 "MEDIAN":
"Correct using the median of the overscan region",
52 "MEDIAN_PER_ROW":
"Correct using the median per row of the overscan region",
55 order = pexConfig.Field(
57 doc=(
"Order of polynomial to fit if overscan fit type is a polynomial, "
58 "or number of spline knots if overscan fit type is a spline."),
61 numSigmaClip = pexConfig.Field(
63 doc=
"Rejection threshold (sigma) for collapsing overscan before fit",
66 maskPlanes = pexConfig.ListField(
68 doc=
"Mask planes to reject when measuring overscan",
69 default=[
'BAD',
'SAT'],
71 overscanIsInt = pexConfig.Field(
73 doc=
"Treat overscan as an integer image for purposes of fitType=MEDIAN"
74 " and fitType=MEDIAN_PER_ROW.",
78 doParallelOverscan = pexConfig.Field(
80 doc=
"Correct using parallel overscan after serial overscan correction?",
83 parallelOverscanMaskThreshold = pexConfig.Field(
85 doc=
"Threshold above which pixels in the parallel overscan are masked as bleeds.",
88 parallelOverscanMaskGrowSize = pexConfig.Field(
90 doc=
"Masks created from saturated bleeds should be grown by this many "
91 "pixels during construction of the parallel overscan mask. "
92 "This value determined from the ITL chip in the LATISS camera",
96 leadingColumnsToSkip = pexConfig.Field(
98 doc=
"Number of leading columns to skip in serial overscan correction.",
101 trailingColumnsToSkip = pexConfig.Field(
103 doc=
"Number of trailing columns to skip in serial overscan correction.",
106 leadingRowsToSkip = pexConfig.Field(
108 doc=
"Number of leading rows to skip in parallel overscan correction.",
111 trailingRowsToSkip = pexConfig.Field(
113 doc=
"Number of trailing rows to skip in parallel overscan correction.",
117 maxDeviation = pexConfig.Field(
119 doc=
"Maximum deviation from median (in ADU) to mask in overscan correction.",
120 default=1000.0, check=
lambda x: x > 0,
125 """Correction task for overscan.
127 This class contains
a number of utilities that are easier
to
128 understand
and use when they are
not embedded
in nested
if/
else
134 Statistics control object.
136 ConfigClass = OverscanCorrectionTaskConfig
137 _DefaultName = "overscan"
147 self.
statControl.setNumSigmaClip(self.config.numSigmaClip)
148 self.
statControl.setAndMask(afwImage.Mask.getPlaneBitMask(self.config.maskPlanes))
150 def run(self, exposure, amp, isTransposed=False):
151 """Measure and remove an overscan from an amplifier image.
156 Image data that will have the overscan corrections applied.
158 Amplifier to use for debugging purposes.
159 isTransposed : `bool`, optional
160 Is the image transposed, such that serial
and parallel
161 overscan regions are reversed? Default
is False.
165 overscanResults : `lsst.pipe.base.Struct`
166 Result struct
with components:
169 Value
or fit subtracted
from the amplifier image data
172 Value
or fit subtracted
from the serial overscan image
175 Image of the serial overscan region
with the serial
176 overscan correction applied
178 estimate the amplifier read noise empirically.
179 ``parallelOverscanFit``
180 Value
or fit subtracted
from the parallel overscan
182 ``parallelOverscanImage``
183 Image of the parallel overscan region
with the
184 parallel overscan correction applied
190 Raised
if an invalid overscan type
is set.
193 serialOverscanBBox = amp.getRawSerialOverscanBBox()
194 imageBBox = amp.getRawDataBBox()
196 if self.config.doParallelOverscan:
199 parallelOverscanBBox = amp.getRawParallelOverscanBBox()
200 imageBBox = imageBBox.expandedTo(parallelOverscanBBox)
203 imageBBox.getMinY()),
205 imageBBox.getHeight()))
207 imageBBox, serialOverscanBBox, isTransposed=isTransposed)
208 overscanMean = serialResults.overscanMean
209 overscanMedian = serialResults.overscanMedian
210 overscanSigma = serialResults.overscanSigma
211 residualMean = serialResults.overscanMeanResidual
212 residualMedian = serialResults.overscanMedianResidual
213 residualSigma = serialResults.overscanSigmaResidual
216 parallelResults =
None
217 if self.config.doParallelOverscan:
220 parallelOverscanBBox = amp.getRawParallelOverscanBBox()
221 imageBBox = amp.getRawDataBBox()
223 maskIm = exposure.getMaskedImage()
224 maskIm = maskIm.Factory(maskIm, parallelOverscanBBox)
237 imageBBox, parallelOverscanBBox,
238 isTransposed=
not isTransposed)
239 overscanMean = (overscanMean, parallelResults.overscanMean)
240 overscanMedian = (overscanMedian, parallelResults.overscanMedian)
241 overscanSigma = (overscanSigma, parallelResults.overscanSigma)
242 residualMean = (residualMean, parallelResults.overscanMeanResidual)
243 residualMedian = (residualMedian, parallelResults.overscanMedianResidual)
244 residualSigma = (residualSigma, parallelResults.overscanSigmaResidual)
246 parallelOverscanFit = parallelResults.overscanOverscanModel
if parallelResults
else None
247 parallelOverscanImage = parallelResults.overscanImage
if parallelResults
else None
249 return pipeBase.Struct(imageFit=serialResults.ampOverscanModel,
250 overscanFit=serialResults.overscanOverscanModel,
251 overscanImage=serialResults.overscanImage,
253 parallelOverscanFit=parallelOverscanFit,
254 parallelOverscanImage=parallelOverscanImage,
255 overscanMean=overscanMean,
256 overscanMedian=overscanMedian,
257 overscanSigma=overscanSigma,
258 residualMean=residualMean,
259 residualMedian=residualMedian,
260 residualSigma=residualSigma)
263 """Trim the exposure, fit the overscan, subtract the fit, and
264 calculate statistics.
269 Exposure containing the data.
271 The amplifier that is to be corrected.
273 Bounding box of the image data that will have the overscan
274 subtracted. If parallel overscan will be performed, that
275 area
is added to the image bounding box during serial
278 Bounding box
for the overscan data.
280 If true, then the data will be transposed before fitting
285 results : `lsst.pipe.base.Struct`
287 Overscan model broadcast to the full image size.
289 ``overscanOverscanModel``
290 Overscan model broadcast to the full overscan image
293 Overscan image
with the overscan fit subtracted.
296 Overscan model. (`float`
or `np.array`)
298 Mean value of the overscan fit. (`float`)
300 Median value of the overscan fit. (`float`)
302 Standard deviation of the overscan fit. (`float`)
303 ``overscanMeanResidual``
304 Mean value of the overscan region after overscan
305 subtraction. (`float`)
306 ``overscanMedianResidual``
307 Median value of the overscan region after overscan
308 subtraction. (`float`)
309 ``overscanSigmaResidual``
310 Standard deviation of the overscan region after
311 overscan subtraction. (`float`)
313 overscanBox = self.trimOverscan(exposure, amp, overscanBBox,
314 self.config.leadingColumnsToSkip,
315 self.config.trailingColumnsToSkip,
316 transpose=isTransposed)
317 overscanImage = exposure[overscanBox].getMaskedImage()
318 overscanArray = overscanImage.image.array
321 maskVal = overscanImage.mask.getPlaneBitMask(self.config.maskPlanes)
322 overscanMask = ~((overscanImage.mask.array & maskVal) == 0)
324 median = np.ma.median(np.ma.masked_where(overscanMask, overscanArray))
325 bad = np.where(np.abs(overscanArray - median) > self.config.maxDeviation)
326 overscanImage.mask.array[bad] = overscanImage.mask.getPlaneBitMask(
"SAT")
330 overscanResults = self.
fitOverscan(overscanImage, isTransposed=isTransposed)
333 ampImage = exposure[imageBBox]
335 ampImage.image.array,
336 transpose=isTransposed)
337 ampImage.image.array -= ampOverscanModel
341 overscanImage = exposure[overscanBBox]
344 overscanImage.image.array)
345 self.
debugView(overscanImage, overscanResults.overscanValue, amp, isTransposed=isTransposed)
346 overscanImage.image.array -= overscanOverscanModel
350 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP, self.
statControl)
351 residualMean = stats.getValue(afwMath.MEAN)
352 residualMedian = stats.getValue(afwMath.MEDIAN)
353 residualSigma = stats.getValue(afwMath.STDEVCLIP)
355 return pipeBase.Struct(ampOverscanModel=ampOverscanModel,
356 overscanOverscanModel=overscanOverscanModel,
357 overscanImage=overscanImage,
358 overscanValue=overscanResults.overscanValue,
360 overscanMean=overscanResults.overscanMean,
361 overscanMedian=overscanResults.overscanMedian,
362 overscanSigma=overscanResults.overscanSigma,
363 overscanMeanResidual=residualMean,
364 overscanMedianResidual=residualMedian,
365 overscanSigmaResidual=residualSigma
369 """Broadcast 0 or 1 dimension fit to appropriate shape.
373 overscanValue : `numpy.ndarray`, (Nrows, ) or scalar
374 Overscan fit to broadcast.
375 imageArray : `numpy.ndarray`, (Nrows, Ncols)
376 Image array that we want to match.
377 transpose : `bool`, optional
378 Switch order to broadcast along the other axis.
382 overscanModel : `numpy.ndarray`, (Nrows, Ncols)
or scalar
383 Expanded overscan fit.
388 Raised
if no axis has the appropriate dimension.
390 if isinstance(overscanValue, np.ndarray):
391 overscanModel = np.zeros_like(imageArray)
393 if transpose
is False:
394 if imageArray.shape[0] == overscanValue.shape[0]:
395 overscanModel[:, :] = overscanValue[:, np.newaxis]
396 elif imageArray.shape[1] == overscanValue.shape[0]:
397 overscanModel[:, :] = overscanValue[np.newaxis, :]
398 elif imageArray.shape[0] == overscanValue.shape[1]:
399 overscanModel[:, :] = overscanValue[np.newaxis, :]
401 raise RuntimeError(f
"Could not broadcast {overscanValue.shape} to "
402 f
"match {imageArray.shape}")
404 if imageArray.shape[1] == overscanValue.shape[0]:
405 overscanModel[:, :] = overscanValue[np.newaxis, :]
406 elif imageArray.shape[0] == overscanValue.shape[0]:
407 overscanModel[:, :] = overscanValue[:, np.newaxis]
408 elif imageArray.shape[1] == overscanValue.shape[1]:
409 overscanModel[:, :] = overscanValue[:, np.newaxis]
411 raise RuntimeError(f
"Could not broadcast {overscanValue.shape} to "
412 f
"match {imageArray.shape}")
414 overscanModel = overscanValue
418 def trimOverscan(self, exposure, amp, bbox, skipLeading, skipTrailing, transpose=False):
419 """Trim overscan region to remove edges.
424 Exposure containing data.
426 Amplifier containing geometry information.
428 Bounding box of the overscan region.
430 Number of leading (towards data region) rows/columns to skip.
432 Number of trailing (away from data region) rows/columns to skip.
433 transpose : `bool`, optional
434 Operate on the transposed array.
438 overscanArray : `numpy.array`, (N, M)
440 overscanMask : `numpy.array`, (N, M)
443 dx0, dy0, dx1, dy1 = (0, 0, 0, 0)
444 dataBBox = amp.getRawDataBBox()
446 if dataBBox.getBeginY() < bbox.getBeginY():
453 if dataBBox.getBeginX() < bbox.getBeginX():
462 bbox.getHeight() - dy0 + dy1))
466 if self.config.fitType
in (
'MEAN',
'MEANCLIP',
'MEDIAN'):
469 overscanValue = overscanResult.overscanValue
470 overscanMean = overscanValue
471 overscanMedian = overscanValue
473 elif self.config.fitType
in (
'MEDIAN_PER_ROW',
'POLY',
'CHEB',
'LEG',
474 'NATURAL_SPLINE',
'CUBIC_SPLINE',
'AKIMA_SPLINE'):
477 overscanValue = overscanResult.overscanValue
480 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP,
482 overscanMean = stats.getValue(afwMath.MEAN)
483 overscanMedian = stats.getValue(afwMath.MEDIAN)
484 overscanSigma = stats.getValue(afwMath.STDEVCLIP)
486 raise ValueError(
'%s : %s an invalid overscan type' %
487 (
"overscanCorrection", self.config.fitType))
489 return pipeBase.Struct(overscanValue=overscanValue,
490 overscanMean=overscanMean,
491 overscanMedian=overscanMedian,
492 overscanSigma=overscanSigma,
497 """Return an integer version of the input image.
502 Image to convert to integers.
507 The integer converted image.
512 Raised
if the input image could
not be converted.
514 if hasattr(image,
"image"):
516 imageI = image.image.convertI()
517 outI = afwImage.MaskedImageI(imageI, image.mask, image.variance)
518 elif hasattr(image,
"convertI"):
520 outI = image.convertI()
521 elif hasattr(image,
"astype"):
523 outI = image.astype(int)
525 raise RuntimeError(
"Could not convert this to integers: %s %s %s",
526 image,
type(image), dir(image))
530 """Mask the union of high values on all amplifiers in the parallel
533 This operates on the image in-place.
538 An untrimmed raw exposure.
540 The detetor to use
for amplifier geometry.
545 dataView = afwImage.MaskedImageF(exposure.getMaskedImage(),
546 amp.getRawParallelOverscanBBox(),
549 maskedImage=dataView,
550 threshold=self.config.parallelOverscanMaskThreshold,
551 growFootprints=self.config.parallelOverscanMaskGrowSize,
554 if parallelMask
is None:
555 parallelMask = dataView.mask.array
557 parallelMask |= dataView.mask.array
559 dataView = afwImage.MaskedImageF(exposure.getMaskedImage(),
560 amp.getRawParallelOverscanBBox(),
562 dataView.mask.array |= parallelMask
566 """Measure a constant overscan value.
571 Image data to measure the overscan
from.
575 results : `lsst.pipe.base.Struct`
576 Overscan result
with entries:
577 - ``overscanValue``: Overscan value to subtract (`float`)
578 - ``isTransposed``: Orientation of the overscan (`bool`)
583 return pipeBase.Struct(overscanValue=overscanValue,
588 """Extract the numpy array from the input image.
593 Image data to pull array
from.
595 calcImage : `numpy.ndarray`
596 Image data array
for numpy operating.
598 if hasattr(image,
"getImage"):
599 calcImage = image.getImage().getArray()
600 calcImage = np.ma.masked_where(image.getMask().getArray() & self.
statControl.getAndMask(),
603 calcImage = image.getArray()
607 """Mask outliers in a row of overscan data
from a robust sigma
612 imageArray : `numpy.ndarray`
613 Image to filter along numpy axis=1.
617 maskedArray : `numpy.ma.masked_array`
618 Masked image marking outliers.
620 lq, median, uq = np.percentile(np.ma.getdata(imageArray),
621 [25.0, 50.0, 75.0], axis=1)
623 axisStdev = 0.74*(uq - lq)
628 axisStdev = np.where(axisStdev > 2.0 * np.median(axisStdev),
629 np.median(axisStdev), axisStdev)
632 diff = np.abs(imageArray - axisMedians[:, np.newaxis])
633 masked = np.ma.masked_where(diff > self.
statControl.getNumSigmaClip()
634 * axisStdev[:, np.newaxis], imageArray)
639 """Fill masked/NaN pixels in the overscan.
643 overscanVector : `np.array` or `np.ma.masked_array`
644 Overscan vector to fill.
648 overscanVector : `np.ma.masked_array`
653 Each maskSlice
is a section of overscan
with contiguous masks.
654 Ideally this adds 5 pixels
from the left
and right of that
655 mask slice,
and takes the median of those values to fill the
656 slice. If this isn
't possible, the median of all non-masked
657 values is used. The mask
is removed
for the pixels filled.
659 workingCopy = overscanVector
660 if not isinstance(overscanVector, np.ma.MaskedArray):
661 workingCopy = np.ma.masked_array(overscanVector,
662 mask=~np.isfinite(overscanVector))
664 defaultValue = np.median(workingCopy.data[~workingCopy.mask])
665 for maskSlice
in np.ma.clump_masked(workingCopy):
667 if maskSlice.start > 5:
668 neighborhood.extend(workingCopy[maskSlice.start - 5:maskSlice.start].data)
669 if maskSlice.stop < workingCopy.size - 5:
670 neighborhood.extend(workingCopy[maskSlice.stop:maskSlice.stop+5].data)
671 if len(neighborhood) > 0:
672 workingCopy.data[maskSlice] = np.nanmedian(neighborhood)
673 workingCopy.mask[maskSlice] =
False
675 workingCopy.data[maskSlice] = defaultValue
676 workingCopy.mask[maskSlice] =
False
680 """Collapse overscan array (and mask) to a 1-D vector of values.
684 maskedArray : `numpy.ma.masked_array`
685 Masked array of input overscan data.
686 fillMasked : `bool`, optional
687 If true, fill any pixels that are masked with a median of
692 collapsed : `numpy.ma.masked_array`
693 Single dimensional overscan data, combined
with the mean.
696 collapsed = np.mean(maskedArray, axis=1)
697 if collapsed.mask.sum() > 0
and fillMasked:
703 """Collapse overscan array (and mask) to a 1-D vector of using the
704 correct integer median of row-values.
708 maskedArray : `numpy.ma.masked_array`
709 Masked array of input overscan data.
713 collapsed : `numpy.ma.masked_array`
714 Single dimensional overscan data, combined with the afwMath median.
720 for row
in integerMI:
721 newRow = row.compressed()
726 collapsed.append(rowMedian)
728 return np.array(collapsed)
731 """Wrapper function to match spline fit API to polynomial fit API.
735 indices : `numpy.ndarray`
736 Locations to evaluate the spline.
737 collapsed : `numpy.ndarray`
738 Collapsed overscan values corresponding to the spline
741 Number of bins to use in constructing the spline.
746 Interpolation object
for later evaluation.
748 if not np.ma.is_masked(collapsed):
749 collapsed.mask = np.array(len(collapsed)*[np.ma.nomask])
751 numPerBin, binEdges = np.histogram(indices, bins=numBins,
752 weights=1 - collapsed.mask.astype(int))
753 with np.errstate(invalid=
"ignore"):
754 values = np.histogram(indices, bins=numBins,
755 weights=collapsed.data*~collapsed.mask)[0]/numPerBin
756 binCenters = np.histogram(indices, bins=numBins,
757 weights=indices*~collapsed.mask)[0]/numPerBin
759 if len(binCenters[numPerBin > 0]) < 5:
760 self.log.warn(
"Cannot do spline fitting for overscan: %s valid points.",
761 len(binCenters[numPerBin > 0]))
765 if len(values[numPerBin > 0]) != 0:
766 return float(values[numPerBin > 0][0])
771 values.astype(float)[numPerBin > 0],
777 """Wrapper function to match spline evaluation API to polynomial fit
782 indices : `numpy.ndarray`
783 Locations to evaluate the spline.
784 interp : `lsst.afw.math.interpolate`
785 Interpolation object to use.
789 values : `numpy.ndarray`
790 Evaluated spline values at each index.
793 return interp.interpolate(indices.astype(float))
797 """Create mask if edges are extrapolated.
801 collapsed : `numpy.ma.masked_array`
802 Masked array to check the edges of.
806 maskArray : `numpy.ndarray`
807 Boolean numpy array of pixels to mask.
809 maskArray = np.full_like(collapsed, False, dtype=bool)
810 if np.ma.is_masked(collapsed):
812 for low
in range(num):
813 if not collapsed.mask[low]:
816 maskArray[:low] =
True
817 for high
in range(1, num):
818 if not collapsed.mask[-high]:
821 maskArray[-high:] =
True
825 """Calculate the 1-d vector overscan from the input overscan image.
830 Image containing the overscan data.
831 isTransposed : `bool`
832 If true, the image has been transposed.
836 results : `lsst.pipe.base.Struct`
837 Overscan result with entries:
840 Overscan value to subtract (`float`)
842 List of rows that should be masked
as ``SUSPECT`` when the
843 overscan solution
is applied. (`list` [ `bool` ])
845 Indicates
if the overscan data was transposed during
846 calcuation, noting along which axis the overscan should be
853 calcImage = np.transpose(calcImage)
856 if self.config.fitType ==
'MEDIAN_PER_ROW':
857 mi = afwImage.MaskedImageI(image.getBBox())
858 masked = masked.astype(int)
860 masked = masked.transpose()
862 mi.image.array[:, :] = masked.data[:, :]
863 if bool(masked.mask.shape):
864 mi.mask.array[:, :] = masked.mask[:, :]
866 overscanVector = fitOverscanImage(mi, self.config.maskPlanes, isTransposed)
873 indices = 2.0*np.arange(num)/float(num) - 1.0
877 'POLY': (poly.polynomial.polyfit, poly.polynomial.polyval),
878 'CHEB': (poly.chebyshev.chebfit, poly.chebyshev.chebval),
879 'LEG': (poly.legendre.legfit, poly.legendre.legval),
883 }[self.config.fitType]
887 coeffs = fitter(indices, collapsed, self.config.order)
889 if isinstance(coeffs, float):
890 self.log.warn(
"Using fallback value %f due to fitter failure. Amplifier will be masked.",
892 overscanVector = np.full_like(indices, coeffs)
893 maskArray = np.full_like(collapsed,
True, dtype=bool)
896 overscanVector = evaler(indices, coeffs)
899 return pipeBase.Struct(overscanValue=np.array(overscanVector),
901 isTransposed=isTransposed)
903 def debugView(self, image, model, amp=None, isTransposed=True):
904 """Debug display for the final overscan solution.
909 Input image the overscan solution was determined from.
910 model : `numpy.ndarray`
or `float`
911 Overscan model determined
for the image.
913 Amplifier to extract diagnostic information.
914 isTransposed : `bool`, optional
915 Does the data need to be transposed before display?
926 calcImage = np.transpose(calcImage)
931 indices = 2.0 * np.arange(num)/float(num) - 1.0
932 indices = np.arange(num)
934 if np.ma.is_masked(collapsed):
935 collapsedMask = collapsed.mask
937 collapsedMask = np.array(num*[np.ma.nomask])
939 import matplotlib.pyplot
as plot
940 figure = plot.figure(1)
942 axes = figure.add_axes((0.1, 0.1, 0.8, 0.8))
943 axes.plot(indices[~collapsedMask], collapsed[~collapsedMask],
'k+')
944 if collapsedMask.sum() > 0:
945 axes.plot(indices[collapsedMask], collapsed.data[collapsedMask],
'b+')
946 if isinstance(model, np.ndarray):
949 plotModel = np.zeros_like(indices)
952 axes.plot(indices, plotModel,
'r-')
953 plot.xlabel(
"position along overscan region")
954 plot.ylabel(
"pixel value/fit value")
956 plot.title(f
"{amp.getName()} DataX: "
957 f
"[{amp.getRawDataBBox().getBeginX()}:{amp.getRawBBox().getEndX()}]"
958 f
"OscanX: [{amp.getRawHorizontalOverscanBBox().getBeginX()}:"
959 f
"{amp.getRawHorizontalOverscanBBox().getEndX()}] {self.config.fitType}")
961 plot.title(
"No amp supplied.")
963 prompt =
"Press Enter or c to continue [chp]..."
965 ans = input(prompt).lower()
966 if ans
in (
"",
" ",
"c",):
975 print(
"[h]elp [c]ontinue [p]db e[x]itDebug")
Geometry and electronic information about raw amplifier images.
A representation of a detector in a mosaic camera.
A class to contain the data, WCS, and other information needed to describe an image of the sky.
A class to represent a 2-dimensional array of pixels.
A class to manipulate images, masks, and variance as a single object.
Pass parameters to a Statistics object.
An integer coordinate rectangle.
maskParallelOverscan(self, exposure, detector)
maskExtrapolated(collapsed)
measureVectorOverscan(self, image, isTransposed=False)
correctOverscan(self, exposure, amp, imageBBox, overscanBBox, isTransposed=True)
getImageArray(self, image)
fillMaskedPixels(self, overscanVector)
__init__(self, statControl=None, **kwargs)
fitOverscan(self, overscanImage, isTransposed=False)
measureConstantOverscan(self, image)
splineFit(self, indices, collapsed, numBins)
collapseArray(self, maskedArray, fillMasked=True)
broadcastFitToImage(self, overscanValue, imageArray, transpose=False)
trimOverscan(self, exposure, amp, bbox, skipLeading, skipTrailing, transpose=False)
splineEval(indices, interp)
maskOutliers(self, imageArray)
collapseArrayMedian(self, maskedArray)
debugView(self, image, model, amp=None, isTransposed=True)
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
Property stringToStatisticsProperty(std::string const property)
Conversion function to switch a string to a Property (see Statistics.h)
Interpolate::Style stringToInterpStyle(std::string const &style)
Conversion function to switch a string to an Interpolate::Style.
std::shared_ptr< Interpolate > makeInterpolate(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style=Interpolate::AKIMA_SPLINE)
A factory function to make Interpolate objects.