LSST Applications g180d380827+78227d2bc4,g2079a07aa2+86d27d4dc4,g2305ad1205+bdd7851fe3,g2bbee38e9b+c6a8a0fb72,g337abbeb29+c6a8a0fb72,g33d1c0ed96+c6a8a0fb72,g3a166c0a6a+c6a8a0fb72,g3d1719c13e+260d7c3927,g3ddfee87b4+723a6db5f3,g487adcacf7+29e55ea757,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+9443c4b912,g62aa8f1a4b+7e2ea9cd42,g858d7b2824+260d7c3927,g864b0138d7+8498d97249,g95921f966b+dffe86973d,g991b906543+260d7c3927,g99cad8db69+4809d78dd9,g9c22b2923f+e2510deafe,g9ddcbc5298+9a081db1e4,ga1e77700b3+03d07e1c1f,gb0e22166c9+60f28cb32d,gb23b769143+260d7c3927,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e22341fd87,gbd998247f1+585e252eca,gc120e1dc64+713f94b854,gc28159a63d+c6a8a0fb72,gc3e9b769f7+385ea95214,gcf0d15dbbd+723a6db5f3,gdaeeff99f8+f9a426f77a,ge6526c86ff+fde82a80b9,ge79ae78c31+c6a8a0fb72,gee10cc3b42+585e252eca,w.2024.18
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Static Protected Attributes | List of all members
lsst.ip.isr.overscan.OverscanCorrectionTaskBase Class Reference
Inheritance diagram for lsst.ip.isr.overscan.OverscanCorrectionTaskBase:
lsst.ip.isr.overscan.OverscanCorrectionTask lsst.ip.isr.overscan.ParallelOverscanCorrectionTask lsst.ip.isr.overscan.SerialOverscanCorrectionTask

Public Member Functions

 __init__ (self, statControl=None, **kwargs)
 
 run (self, exposure, amp, isTransposed=False)
 
 correctOverscan (self, exposure, amp, imageBBox, overscanBBox, isTransposed=True, leadingToSkip=0, trailingToSkip=0)
 
 broadcastFitToImage (self, overscanValue, imageArray, transpose=False)
 
 trimOverscan (self, exposure, amp, bbox, skipLeading, skipTrailing, transpose=False)
 
 fitOverscan (self, overscanImage, isTransposed=False)
 
 maskParallelOverscan (self, exposure, detector)
 
 measureConstantOverscan (self, image)
 
 getImageArray (self, image)
 
 maskOutliers (self, imageArray)
 
 fillMaskedPixels (self, overscanVector)
 
 collapseArray (self, maskedArray, fillMasked=True)
 
 collapseArrayMedian (self, maskedArray)
 
 splineFit (self, indices, collapsed, numBins)
 
 measureVectorOverscan (self, image, isTransposed=False)
 
 debugView (self, image, model, amp=None, isTransposed=True)
 

Static Public Member Functions

 integerConvert (image)
 
 splineEval (indices, interp)
 
 maskExtrapolated (collapsed)
 

Public Attributes

 allowDebug
 
 statControl
 
 splineFit
 
 splineEval
 

Static Public Attributes

 ConfigClass = OverscanCorrectionTaskConfigBase
 

Static Protected Attributes

str _DefaultName = "overscanBase"
 

Detailed Description

Base Correction task for overscan.

This class contains a number of utilities that are easier to
understand and use when they are not embedded in nested if/else
loops.

Parameters
----------
statControl : `lsst.afw.math.StatisticsControl`, optional
    Statistics control object.

Definition at line 127 of file overscan.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.__init__ ( self,
statControl = None,
** kwargs )

Definition at line 142 of file overscan.py.

142 def __init__(self, statControl=None, **kwargs):
143 super().__init__(**kwargs)
144 self.allowDebug = True
145
146 if statControl:
147 self.statControl = statControl
148 else:
149 self.statControl = afwMath.StatisticsControl()
150 self.statControl.setNumSigmaClip(self.config.numSigmaClip)
151 self.statControl.setAndMask(afwImage.Mask.getPlaneBitMask(self.config.maskPlanes))
152
Pass parameters to a Statistics object.
Definition Statistics.h:83

Member Function Documentation

◆ broadcastFitToImage()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.broadcastFitToImage ( self,
overscanValue,
imageArray,
transpose = False )
Broadcast 0 or 1 dimension fit to appropriate shape.

Parameters
----------
overscanValue : `numpy.ndarray`, (Nrows, ) or scalar
    Overscan fit to broadcast.
imageArray : `numpy.ndarray`, (Nrows, Ncols)
    Image array that we want to match.
transpose : `bool`, optional
    Switch order to broadcast along the other axis.

Returns
-------
overscanModel : `numpy.ndarray`, (Nrows, Ncols) or scalar
    Expanded overscan fit.

Raises
------
RuntimeError
    Raised if no axis has the appropriate dimension.

Definition at line 267 of file overscan.py.

267 def broadcastFitToImage(self, overscanValue, imageArray, transpose=False):
268 """Broadcast 0 or 1 dimension fit to appropriate shape.
269
270 Parameters
271 ----------
272 overscanValue : `numpy.ndarray`, (Nrows, ) or scalar
273 Overscan fit to broadcast.
274 imageArray : `numpy.ndarray`, (Nrows, Ncols)
275 Image array that we want to match.
276 transpose : `bool`, optional
277 Switch order to broadcast along the other axis.
278
279 Returns
280 -------
281 overscanModel : `numpy.ndarray`, (Nrows, Ncols) or scalar
282 Expanded overscan fit.
283
284 Raises
285 ------
286 RuntimeError
287 Raised if no axis has the appropriate dimension.
288 """
289 if isinstance(overscanValue, np.ndarray):
290 overscanModel = np.zeros_like(imageArray)
291
292 if transpose is False:
293 if imageArray.shape[0] == overscanValue.shape[0]:
294 overscanModel[:, :] = overscanValue[:, np.newaxis]
295 elif imageArray.shape[1] == overscanValue.shape[0]:
296 overscanModel[:, :] = overscanValue[np.newaxis, :]
297 elif imageArray.shape[0] == overscanValue.shape[1]:
298 overscanModel[:, :] = overscanValue[np.newaxis, :]
299 else:
300 raise RuntimeError(f"Could not broadcast {overscanValue.shape} to "
301 f"match {imageArray.shape}")
302 else:
303 if imageArray.shape[1] == overscanValue.shape[0]:
304 overscanModel[:, :] = overscanValue[np.newaxis, :]
305 elif imageArray.shape[0] == overscanValue.shape[0]:
306 overscanModel[:, :] = overscanValue[:, np.newaxis]
307 elif imageArray.shape[1] == overscanValue.shape[1]:
308 overscanModel[:, :] = overscanValue[:, np.newaxis]
309 else:
310 raise RuntimeError(f"Could not broadcast {overscanValue.shape} to "
311 f"match {imageArray.shape}")
312 else:
313 overscanModel = overscanValue
314
315 return overscanModel
316

◆ collapseArray()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.collapseArray ( self,
maskedArray,
fillMasked = True )
Collapse overscan array (and mask) to a 1-D vector of values.

Parameters
----------
maskedArray : `numpy.ma.masked_array`
    Masked array of input overscan data.
fillMasked : `bool`, optional
    If true, fill any pixels that are masked with a median of
    neighbors.

Returns
-------
collapsed : `numpy.ma.masked_array`
    Single dimensional overscan data, combined with the mean.

Definition at line 578 of file overscan.py.

578 def collapseArray(self, maskedArray, fillMasked=True):
579 """Collapse overscan array (and mask) to a 1-D vector of values.
580
581 Parameters
582 ----------
583 maskedArray : `numpy.ma.masked_array`
584 Masked array of input overscan data.
585 fillMasked : `bool`, optional
586 If true, fill any pixels that are masked with a median of
587 neighbors.
588
589 Returns
590 -------
591 collapsed : `numpy.ma.masked_array`
592 Single dimensional overscan data, combined with the mean.
593
594 """
595 collapsed = np.mean(maskedArray, axis=1)
596 if collapsed.mask.sum() > 0 and fillMasked:
597 collapsed = self.fillMaskedPixels(collapsed)
598
599 return collapsed
600

◆ collapseArrayMedian()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.collapseArrayMedian ( self,
maskedArray )
Collapse overscan array (and mask) to a 1-D vector of using the
correct integer median of row-values.

Parameters
----------
maskedArray : `numpy.ma.masked_array`
    Masked array of input overscan data.

Returns
-------
collapsed : `numpy.ma.masked_array`
    Single dimensional overscan data, combined with the afwMath median.

Definition at line 601 of file overscan.py.

601 def collapseArrayMedian(self, maskedArray):
602 """Collapse overscan array (and mask) to a 1-D vector of using the
603 correct integer median of row-values.
604
605 Parameters
606 ----------
607 maskedArray : `numpy.ma.masked_array`
608 Masked array of input overscan data.
609
610 Returns
611 -------
612 collapsed : `numpy.ma.masked_array`
613 Single dimensional overscan data, combined with the afwMath median.
614 """
615 integerMI = self.integerConvert(maskedArray)
616
617 collapsed = []
618 fitType = afwMath.stringToStatisticsProperty('MEDIAN')
619 for row in integerMI:
620 newRow = row.compressed()
621 if len(newRow) > 0:
622 rowMedian = afwMath.makeStatistics(newRow, fitType, self.statControl).getValue()
623 else:
624 rowMedian = np.nan
625 collapsed.append(rowMedian)
626
627 return np.array(collapsed)
628
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)
Definition Statistics.h:361
Property stringToStatisticsProperty(std::string const property)
Conversion function to switch a string to a Property (see Statistics.h)

◆ correctOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.correctOverscan ( self,
exposure,
amp,
imageBBox,
overscanBBox,
isTransposed = True,
leadingToSkip = 0,
trailingToSkip = 0 )
Trim the exposure, fit the overscan, subtract the fit, and
calculate statistics.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure containing the data.
amp : `lsst.afw.cameraGeom.Amplifier`
    The amplifier that is to be corrected.
imageBBox: `lsst.geom.Box2I`
    Bounding box of the image data that will have the overscan
    subtracted.  If parallel overscan will be performed, that
    area is added to the image bounding box during serial
    overscan correction.
overscanBBox: `lsst.geom.Box2I`
    Bounding box for the overscan data.
isTransposed: `bool`
    If true, then the data will be transposed before fitting
    the overscan.
leadingToSkip : `int`, optional
    Leading rows/columns to skip.
trailingToSkip : `int`, optional
    Leading rows/columns to skip.

Returns
-------
results : `lsst.pipe.base.Struct`
    ``ampOverscanModel``
        Overscan model broadcast to the full image size.
        (`lsst.afw.image.Exposure`)
    ``overscanOverscanModel``
        Overscan model broadcast to the full overscan image
        size. (`lsst.afw.image.Exposure`)
    ``overscanImage``
        Overscan image with the overscan fit subtracted.
        (`lsst.afw.image.Exposure`)
    ``overscanValue``
        Overscan model. (`float` or `np.array`)
    ``overscanMean``
        Mean value of the overscan fit. (`float`)
    ``overscanMedian``
        Median value of the overscan fit. (`float`)
    ``overscanSigma``
        Standard deviation of the overscan fit. (`float`)
    ``overscanMeanResidual``
        Mean value of the overscan region after overscan
        subtraction. (`float`)
    ``overscanMedianResidual``
        Median value of the overscan region after overscan
        subtraction. (`float`)
    ``overscanSigmaResidual``
        Standard deviation of the overscan region after
        overscan subtraction. (`float`)

Definition at line 156 of file overscan.py.

157 isTransposed=True, leadingToSkip=0, trailingToSkip=0):
158 """Trim the exposure, fit the overscan, subtract the fit, and
159 calculate statistics.
160
161 Parameters
162 ----------
163 exposure : `lsst.afw.image.Exposure`
164 Exposure containing the data.
165 amp : `lsst.afw.cameraGeom.Amplifier`
166 The amplifier that is to be corrected.
167 imageBBox: `lsst.geom.Box2I`
168 Bounding box of the image data that will have the overscan
169 subtracted. If parallel overscan will be performed, that
170 area is added to the image bounding box during serial
171 overscan correction.
172 overscanBBox: `lsst.geom.Box2I`
173 Bounding box for the overscan data.
174 isTransposed: `bool`
175 If true, then the data will be transposed before fitting
176 the overscan.
177 leadingToSkip : `int`, optional
178 Leading rows/columns to skip.
179 trailingToSkip : `int`, optional
180 Leading rows/columns to skip.
181
182 Returns
183 -------
184 results : `lsst.pipe.base.Struct`
185 ``ampOverscanModel``
186 Overscan model broadcast to the full image size.
187 (`lsst.afw.image.Exposure`)
188 ``overscanOverscanModel``
189 Overscan model broadcast to the full overscan image
190 size. (`lsst.afw.image.Exposure`)
191 ``overscanImage``
192 Overscan image with the overscan fit subtracted.
193 (`lsst.afw.image.Exposure`)
194 ``overscanValue``
195 Overscan model. (`float` or `np.array`)
196 ``overscanMean``
197 Mean value of the overscan fit. (`float`)
198 ``overscanMedian``
199 Median value of the overscan fit. (`float`)
200 ``overscanSigma``
201 Standard deviation of the overscan fit. (`float`)
202 ``overscanMeanResidual``
203 Mean value of the overscan region after overscan
204 subtraction. (`float`)
205 ``overscanMedianResidual``
206 Median value of the overscan region after overscan
207 subtraction. (`float`)
208 ``overscanSigmaResidual``
209 Standard deviation of the overscan region after
210 overscan subtraction. (`float`)
211 """
212 overscanBox = self.trimOverscan(exposure, amp, overscanBBox,
213 leadingToSkip,
214 trailingToSkip,
215 transpose=isTransposed)
216 overscanImage = exposure[overscanBox].getMaskedImage()
217 overscanArray = overscanImage.image.array
218
219 # Mask pixels.
220 maskVal = overscanImage.mask.getPlaneBitMask(self.config.maskPlanes)
221 overscanMask = ~((overscanImage.mask.array & maskVal) == 0)
222
223 median = np.ma.median(np.ma.masked_where(overscanMask, overscanArray))
224 bad = np.where(np.abs(overscanArray - median) > self.config.maxDeviation)
225 overscanImage.mask.array[bad] = overscanImage.mask.getPlaneBitMask("SAT")
226
227 # Do overscan fit.
228 # CZW: Handle transposed correctly.
229 overscanResults = self.fitOverscan(overscanImage, isTransposed=isTransposed)
230
231 # Correct image region (and possibly parallel-overscan region).
232 ampImage = exposure[imageBBox]
233 ampOverscanModel = self.broadcastFitToImage(overscanResults.overscanValue,
234 ampImage.image.array,
235 transpose=isTransposed)
236 ampImage.image.array -= ampOverscanModel
237
238 # Correct overscan region (and possibly doubly-overscaned
239 # region).
240 overscanImage = exposure[overscanBBox]
241 # CZW: Transposed?
242 overscanOverscanModel = self.broadcastFitToImage(overscanResults.overscanValue,
243 overscanImage.image.array)
244 self.debugView(overscanImage, overscanResults.overscanValue, amp, isTransposed=isTransposed)
245 overscanImage.image.array -= overscanOverscanModel
246
247 # Find residual fit statistics.
248 stats = afwMath.makeStatistics(overscanImage.getMaskedImage(),
249 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP, self.statControl)
250 residualMean = stats.getValue(afwMath.MEAN)
251 residualMedian = stats.getValue(afwMath.MEDIAN)
252 residualSigma = stats.getValue(afwMath.STDEVCLIP)
253
254 return pipeBase.Struct(ampOverscanModel=ampOverscanModel,
255 overscanOverscanModel=overscanOverscanModel,
256 overscanImage=overscanImage,
257 overscanValue=overscanResults.overscanValue,
258
259 overscanMean=overscanResults.overscanMean,
260 overscanMedian=overscanResults.overscanMedian,
261 overscanSigma=overscanResults.overscanSigma,
262 overscanMeanResidual=residualMean,
263 overscanMedianResidual=residualMedian,
264 overscanSigmaResidual=residualSigma
265 )
266

◆ debugView()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.debugView ( self,
image,
model,
amp = None,
isTransposed = True )
Debug display for the final overscan solution.

Parameters
----------
image : `lsst.afw.image.Image`
    Input image the overscan solution was determined from.
model : `numpy.ndarray` or `float`
    Overscan model determined for the image.
amp : `lsst.afw.cameraGeom.Amplifier`, optional
    Amplifier to extract diagnostic information.
isTransposed : `bool`, optional
    Does the data need to be transposed before display?

Definition at line 802 of file overscan.py.

802 def debugView(self, image, model, amp=None, isTransposed=True):
803 """Debug display for the final overscan solution.
804
805 Parameters
806 ----------
807 image : `lsst.afw.image.Image`
808 Input image the overscan solution was determined from.
809 model : `numpy.ndarray` or `float`
810 Overscan model determined for the image.
811 amp : `lsst.afw.cameraGeom.Amplifier`, optional
812 Amplifier to extract diagnostic information.
813 isTransposed : `bool`, optional
814 Does the data need to be transposed before display?
815 """
816 import lsstDebug
817 if not lsstDebug.Info(__name__).display:
818 return
819 if not self.allowDebug:
820 return
821
822 calcImage = self.getImageArray(image)
823 # CZW: Check that this is ok
824 if isTransposed:
825 calcImage = np.transpose(calcImage)
826 masked = self.maskOutliers(calcImage)
827 collapsed = self.collapseArray(masked, fillMasked=False)
828
829 num = len(collapsed)
830 indices = 2.0 * np.arange(num)/float(num) - 1.0
831 indices = np.arange(num)
832
833 if np.ma.is_masked(collapsed):
834 collapsedMask = collapsed.mask
835 else:
836 collapsedMask = np.array(num*[np.ma.nomask])
837
838 import matplotlib.pyplot as plot
839 figure = plot.figure(1)
840 figure.clear()
841 axes = figure.add_axes((0.1, 0.1, 0.8, 0.8))
842 axes.plot(indices[~collapsedMask], collapsed[~collapsedMask], 'k+')
843 if collapsedMask.sum() > 0:
844 axes.plot(indices[collapsedMask], collapsed.data[collapsedMask], 'b+')
845 if isinstance(model, np.ndarray):
846 plotModel = model
847 else:
848 plotModel = np.zeros_like(indices)
849 plotModel += model
850
851 axes.plot(indices, plotModel, 'r-')
852 plot.xlabel("position along overscan region")
853 plot.ylabel("pixel value/fit value")
854 if amp:
855 plot.title(f"{amp.getName()} DataX: "
856 f"[{amp.getRawDataBBox().getBeginX()}:{amp.getRawBBox().getEndX()}]"
857 f"OscanX: [{amp.getRawHorizontalOverscanBBox().getBeginX()}:"
858 f"{amp.getRawHorizontalOverscanBBox().getEndX()}] {self.config.fitType}")
859 else:
860 plot.title("No amp supplied.")
861 figure.show()
862 prompt = "Press Enter or c to continue [chp]..."
863 while True:
864 ans = input(prompt).lower()
865 if ans in ("", " ", "c",):
866 break
867 elif ans in ("p", ):
868 import pdb
869 pdb.set_trace()
870 elif ans in ('x', ):
871 self.allowDebug = False
872 break
873 elif ans in ("h", ):
874 print("[h]elp [c]ontinue [p]db e[x]itDebug")
875 plot.close()
876
877

◆ fillMaskedPixels()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.fillMaskedPixels ( self,
overscanVector )
Fill masked/NaN pixels in the overscan.

Parameters
----------
overscanVector : `np.array` or `np.ma.masked_array`
    Overscan vector to fill.

Returns
-------
overscanVector : `np.ma.masked_array`
    Filled vector.

Notes
-----
Each maskSlice is a section of overscan with contiguous masks.
Ideally this adds 5 pixels from the left and right of that
mask slice, and takes the median of those values to fill the
slice.  If this isn't possible, the median of all non-masked
values is used.  The mask is removed for the pixels filled.

Definition at line 537 of file overscan.py.

537 def fillMaskedPixels(self, overscanVector):
538 """Fill masked/NaN pixels in the overscan.
539
540 Parameters
541 ----------
542 overscanVector : `np.array` or `np.ma.masked_array`
543 Overscan vector to fill.
544
545 Returns
546 -------
547 overscanVector : `np.ma.masked_array`
548 Filled vector.
549
550 Notes
551 -----
552 Each maskSlice is a section of overscan with contiguous masks.
553 Ideally this adds 5 pixels from the left and right of that
554 mask slice, and takes the median of those values to fill the
555 slice. If this isn't possible, the median of all non-masked
556 values is used. The mask is removed for the pixels filled.
557 """
558 workingCopy = overscanVector
559 if not isinstance(overscanVector, np.ma.MaskedArray):
560 workingCopy = np.ma.masked_array(overscanVector,
561 mask=~np.isfinite(overscanVector))
562
563 defaultValue = np.median(workingCopy.data[~workingCopy.mask])
564 for maskSlice in np.ma.clump_masked(workingCopy):
565 neighborhood = []
566 if maskSlice.start > 5:
567 neighborhood.extend(workingCopy[maskSlice.start - 5:maskSlice.start].data)
568 if maskSlice.stop < workingCopy.size - 5:
569 neighborhood.extend(workingCopy[maskSlice.stop:maskSlice.stop+5].data)
570 if len(neighborhood) > 0:
571 workingCopy.data[maskSlice] = np.nanmedian(neighborhood)
572 workingCopy.mask[maskSlice] = False
573 else:
574 workingCopy.data[maskSlice] = defaultValue
575 workingCopy.mask[maskSlice] = False
576 return workingCopy
577

◆ fitOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.fitOverscan ( self,
overscanImage,
isTransposed = False )

Definition at line 364 of file overscan.py.

364 def fitOverscan(self, overscanImage, isTransposed=False):
365 if self.config.fitType in ('MEAN', 'MEANCLIP', 'MEDIAN'):
366 # Transposition has no effect here.
367 overscanResult = self.measureConstantOverscan(overscanImage)
368 overscanValue = overscanResult.overscanValue
369 overscanMean = overscanValue
370 overscanMedian = overscanValue
371 overscanSigma = 0.0
372 elif self.config.fitType in ('MEDIAN_PER_ROW', 'POLY', 'CHEB', 'LEG',
373 'NATURAL_SPLINE', 'CUBIC_SPLINE', 'AKIMA_SPLINE'):
374 # Force transposes as needed
375 overscanResult = self.measureVectorOverscan(overscanImage, isTransposed)
376 overscanValue = overscanResult.overscanValue
377
378 stats = afwMath.makeStatistics(overscanResult.overscanValue,
379 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP,
380 self.statControl)
381 overscanMean = stats.getValue(afwMath.MEAN)
382 overscanMedian = stats.getValue(afwMath.MEDIAN)
383 overscanSigma = stats.getValue(afwMath.STDEVCLIP)
384 else:
385 raise ValueError('%s : %s an invalid overscan type' %
386 ("overscanCorrection", self.config.fitType))
387
388 return pipeBase.Struct(overscanValue=overscanValue,
389 overscanMean=overscanMean,
390 overscanMedian=overscanMedian,
391 overscanSigma=overscanSigma,
392 )
393

◆ getImageArray()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.getImageArray ( self,
image )
Extract the numpy array from the input image.

Parameters
----------
image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
    Image data to pull array from.

calcImage : `numpy.ndarray`
    Image data array for numpy operating.

Definition at line 486 of file overscan.py.

486 def getImageArray(self, image):
487 """Extract the numpy array from the input image.
488
489 Parameters
490 ----------
491 image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
492 Image data to pull array from.
493
494 calcImage : `numpy.ndarray`
495 Image data array for numpy operating.
496 """
497 if hasattr(image, "getImage"):
498 calcImage = image.getImage().getArray()
499 calcImage = np.ma.masked_where(image.getMask().getArray() & self.statControl.getAndMask(),
500 calcImage)
501 else:
502 calcImage = image.getArray()
503 return calcImage
504

◆ integerConvert()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.integerConvert ( image)
static
Return an integer version of the input image.

Parameters
----------
image : `numpy.ndarray`, `lsst.afw.image.Image` or `MaskedImage`
    Image to convert to integers.

Returns
-------
outI : `numpy.ndarray`, `lsst.afw.image.Image` or `MaskedImage`
    The integer converted image.

Raises
------
RuntimeError
    Raised if the input image could not be converted.

Definition at line 395 of file overscan.py.

395 def integerConvert(image):
396 """Return an integer version of the input image.
397
398 Parameters
399 ----------
400 image : `numpy.ndarray`, `lsst.afw.image.Image` or `MaskedImage`
401 Image to convert to integers.
402
403 Returns
404 -------
405 outI : `numpy.ndarray`, `lsst.afw.image.Image` or `MaskedImage`
406 The integer converted image.
407
408 Raises
409 ------
410 RuntimeError
411 Raised if the input image could not be converted.
412 """
413 if hasattr(image, "image"):
414 # Is a maskedImage:
415 imageI = image.image.convertI()
416 outI = afwImage.MaskedImageI(imageI, image.mask, image.variance)
417 elif hasattr(image, "convertI"):
418 # Is an Image:
419 outI = image.convertI()
420 elif hasattr(image, "astype"):
421 # Is a numpy array:
422 outI = image.astype(int)
423 else:
424 raise RuntimeError("Could not convert this to integers: %s %s %s",
425 image, type(image), dir(image))
426 return outI
427

◆ maskExtrapolated()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.maskExtrapolated ( collapsed)
static
Create mask if edges are extrapolated.

Parameters
----------
collapsed : `numpy.ma.masked_array`
    Masked array to check the edges of.

Returns
-------
maskArray : `numpy.ndarray`
    Boolean numpy array of pixels to mask.

Definition at line 695 of file overscan.py.

695 def maskExtrapolated(collapsed):
696 """Create mask if edges are extrapolated.
697
698 Parameters
699 ----------
700 collapsed : `numpy.ma.masked_array`
701 Masked array to check the edges of.
702
703 Returns
704 -------
705 maskArray : `numpy.ndarray`
706 Boolean numpy array of pixels to mask.
707 """
708 maskArray = np.full_like(collapsed, False, dtype=bool)
709 if np.ma.is_masked(collapsed):
710 num = len(collapsed)
711 for low in range(num):
712 if not collapsed.mask[low]:
713 break
714 if low > 0:
715 maskArray[:low] = True
716 for high in range(1, num):
717 if not collapsed.mask[-high]:
718 break
719 if high > 1:
720 maskArray[-high:] = True
721 return maskArray
722

◆ maskOutliers()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.maskOutliers ( self,
imageArray )
Mask  outliers in  a  row  of overscan  data  from  a robust  sigma
clipping procedure.

Parameters
----------
imageArray : `numpy.ndarray`
    Image to filter along numpy axis=1.

Returns
-------
maskedArray : `numpy.ma.masked_array`
    Masked image marking outliers.

Definition at line 505 of file overscan.py.

505 def maskOutliers(self, imageArray):
506 """Mask outliers in a row of overscan data from a robust sigma
507 clipping procedure.
508
509 Parameters
510 ----------
511 imageArray : `numpy.ndarray`
512 Image to filter along numpy axis=1.
513
514 Returns
515 -------
516 maskedArray : `numpy.ma.masked_array`
517 Masked image marking outliers.
518 """
519 lq, median, uq = np.percentile(np.ma.getdata(imageArray),
520 [25.0, 50.0, 75.0], axis=1)
521 axisMedians = median
522 axisStdev = 0.74*(uq - lq) # robust stdev
523
524 # Replace pixels that have excessively large stdev values
525 # with the median of stdev values. A large stdev likely
526 # indicates a bleed is spilling into the overscan.
527 axisStdev = np.where(axisStdev > 2.0 * np.median(axisStdev),
528 np.median(axisStdev), axisStdev)
529
530 # Mask pixels that are N-sigma away from their array medians.
531 diff = np.abs(imageArray - axisMedians[:, np.newaxis])
532 masked = np.ma.masked_where(diff > self.statControl.getNumSigmaClip()
533 * axisStdev[:, np.newaxis], imageArray)
534
535 return masked
536

◆ maskParallelOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.maskParallelOverscan ( self,
exposure,
detector )
Mask the union of high values on all amplifiers in the parallel
overscan.

This operates on the image in-place.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    An untrimmed raw exposure.
detector : `lsst.afw.cameraGeom.Detector`
    The detetor to use for amplifier geometry.

Reimplemented in lsst.ip.isr.overscan.ParallelOverscanCorrectionTask.

Definition at line 428 of file overscan.py.

428 def maskParallelOverscan(self, exposure, detector):
429 """Mask the union of high values on all amplifiers in the parallel
430 overscan.
431
432 This operates on the image in-place.
433
434 Parameters
435 ----------
436 exposure : `lsst.afw.image.Exposure`
437 An untrimmed raw exposure.
438 detector : `lsst.afw.cameraGeom.Detector`
439 The detetor to use for amplifier geometry.
440 """
441 parallelMask = None
442
443 for amp in detector:
444 dataView = afwImage.MaskedImageF(exposure.getMaskedImage(),
445 amp.getRawParallelOverscanBBox(),
446 afwImage.PARENT)
447 makeThresholdMask(
448 maskedImage=dataView,
449 threshold=self.config.parallelOverscanMaskThreshold,
450 growFootprints=self.config.parallelOverscanMaskGrowSize,
451 maskName="BAD"
452 )
453 if parallelMask is None:
454 parallelMask = dataView.mask.array
455 else:
456 parallelMask |= dataView.mask.array
457 for amp in detector:
458 dataView = afwImage.MaskedImageF(exposure.getMaskedImage(),
459 amp.getRawParallelOverscanBBox(),
460 afwImage.PARENT)
461 dataView.mask.array |= parallelMask
462

◆ measureConstantOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.measureConstantOverscan ( self,
image )
Measure a constant overscan value.

Parameters
----------
image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
    Image data to measure the overscan from.

Returns
-------
results : `lsst.pipe.base.Struct`
    Overscan result with entries:
    - ``overscanValue``: Overscan value to subtract (`float`)
    - ``isTransposed``: Orientation of the overscan (`bool`)

Definition at line 464 of file overscan.py.

464 def measureConstantOverscan(self, image):
465 """Measure a constant overscan value.
466
467 Parameters
468 ----------
469 image : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
470 Image data to measure the overscan from.
471
472 Returns
473 -------
474 results : `lsst.pipe.base.Struct`
475 Overscan result with entries:
476 - ``overscanValue``: Overscan value to subtract (`float`)
477 - ``isTransposed``: Orientation of the overscan (`bool`)
478 """
479 fitType = afwMath.stringToStatisticsProperty(self.config.fitType)
480 overscanValue = afwMath.makeStatistics(image, fitType, self.statControl).getValue()
481
482 return pipeBase.Struct(overscanValue=overscanValue,
483 isTransposed=False)
484

◆ measureVectorOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.measureVectorOverscan ( self,
image,
isTransposed = False )
Calculate the 1-d vector overscan from the input overscan image.

Parameters
----------
image : `lsst.afw.image.MaskedImage`
    Image containing the overscan data.
isTransposed : `bool`
    If true, the image has been transposed.

Returns
-------
results : `lsst.pipe.base.Struct`
    Overscan result with entries:

    ``overscanValue``
        Overscan value to subtract (`float`)
    ``maskArray``
        List of rows that should be masked as ``SUSPECT`` when the
        overscan solution is applied. (`list` [ `bool` ])
    ``isTransposed``
       Indicates if the overscan data was transposed during
       calcuation, noting along which axis the overscan should be
       subtracted. (`bool`)

Definition at line 723 of file overscan.py.

723 def measureVectorOverscan(self, image, isTransposed=False):
724 """Calculate the 1-d vector overscan from the input overscan image.
725
726 Parameters
727 ----------
728 image : `lsst.afw.image.MaskedImage`
729 Image containing the overscan data.
730 isTransposed : `bool`
731 If true, the image has been transposed.
732
733 Returns
734 -------
735 results : `lsst.pipe.base.Struct`
736 Overscan result with entries:
737
738 ``overscanValue``
739 Overscan value to subtract (`float`)
740 ``maskArray``
741 List of rows that should be masked as ``SUSPECT`` when the
742 overscan solution is applied. (`list` [ `bool` ])
743 ``isTransposed``
744 Indicates if the overscan data was transposed during
745 calcuation, noting along which axis the overscan should be
746 subtracted. (`bool`)
747 """
748 calcImage = self.getImageArray(image)
749
750 # operate on numpy-arrays from here
751 if isTransposed:
752 calcImage = np.transpose(calcImage)
753 masked = self.maskOutliers(calcImage)
754
755 if self.config.fitType == 'MEDIAN_PER_ROW':
756 mi = afwImage.MaskedImageI(image.getBBox())
757 masked = masked.astype(int)
758 if isTransposed:
759 masked = masked.transpose()
760
761 mi.image.array[:, :] = masked.data[:, :]
762 if bool(masked.mask.shape):
763 mi.mask.array[:, :] = masked.mask[:, :]
764
765 overscanVector = fitOverscanImage(mi, self.config.maskPlanes, isTransposed)
766 overscanVector = self.fillMaskedPixels(overscanVector)
767 maskArray = self.maskExtrapolated(overscanVector)
768 else:
769 collapsed = self.collapseArray(masked)
770
771 num = len(collapsed)
772 indices = 2.0*np.arange(num)/float(num) - 1.0
773
774 poly = np.polynomial
775 fitter, evaler = {
776 'POLY': (poly.polynomial.polyfit, poly.polynomial.polyval),
777 'CHEB': (poly.chebyshev.chebfit, poly.chebyshev.chebval),
778 'LEG': (poly.legendre.legfit, poly.legendre.legval),
779 'NATURAL_SPLINE': (self.splineFit, self.splineEval),
780 'CUBIC_SPLINE': (self.splineFit, self.splineEval),
781 'AKIMA_SPLINE': (self.splineFit, self.splineEval)
782 }[self.config.fitType]
783
784 # These are the polynomial coefficients, or an
785 # interpolation object.
786 coeffs = fitter(indices, collapsed, self.config.order)
787
788 if isinstance(coeffs, float):
789 self.log.warning("Using fallback value %f due to fitter failure. Amplifier will be masked.",
790 coeffs)
791 overscanVector = np.full_like(indices, coeffs)
792 maskArray = np.full_like(collapsed, True, dtype=bool)
793 else:
794 # Otherwise we can just use things as normal.
795 overscanVector = evaler(indices, coeffs)
796 maskArray = self.maskExtrapolated(collapsed)
797
798 return pipeBase.Struct(overscanValue=np.array(overscanVector),
799 maskArray=maskArray,
800 isTransposed=isTransposed)
801

◆ run()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.run ( self,
exposure,
amp,
isTransposed = False )

Reimplemented in lsst.ip.isr.overscan.OverscanCorrectionTask, lsst.ip.isr.overscan.SerialOverscanCorrectionTask, and lsst.ip.isr.overscan.ParallelOverscanCorrectionTask.

Definition at line 153 of file overscan.py.

153 def run(self, exposure, amp, isTransposed=False):
154 raise NotImplementedError("run method is not defined for OverscanCorrectionTaskBase")
155

◆ splineEval()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.splineEval ( indices,
interp )
static
Wrapper function to match spline evaluation API to polynomial fit
API.

Parameters
----------
indices : `numpy.ndarray`
    Locations to evaluate the spline.
interp : `lsst.afw.math.interpolate`
    Interpolation object to use.

Returns
-------
values : `numpy.ndarray`
    Evaluated spline values at each index.

Definition at line 675 of file overscan.py.

675 def splineEval(indices, interp):
676 """Wrapper function to match spline evaluation API to polynomial fit
677 API.
678
679 Parameters
680 ----------
681 indices : `numpy.ndarray`
682 Locations to evaluate the spline.
683 interp : `lsst.afw.math.interpolate`
684 Interpolation object to use.
685
686 Returns
687 -------
688 values : `numpy.ndarray`
689 Evaluated spline values at each index.
690 """
691
692 return interp.interpolate(indices.astype(float))
693

◆ splineFit()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.splineFit ( self,
indices,
collapsed,
numBins )
Wrapper function to match spline fit API to polynomial fit API.

Parameters
----------
indices : `numpy.ndarray`
    Locations to evaluate the spline.
collapsed : `numpy.ndarray`
    Collapsed overscan values corresponding to the spline
    evaluation points.
numBins : `int`
    Number of bins to use in constructing the spline.

Returns
-------
interp : `lsst.afw.math.Interpolate`
    Interpolation object for later evaluation.

Definition at line 629 of file overscan.py.

629 def splineFit(self, indices, collapsed, numBins):
630 """Wrapper function to match spline fit API to polynomial fit API.
631
632 Parameters
633 ----------
634 indices : `numpy.ndarray`
635 Locations to evaluate the spline.
636 collapsed : `numpy.ndarray`
637 Collapsed overscan values corresponding to the spline
638 evaluation points.
639 numBins : `int`
640 Number of bins to use in constructing the spline.
641
642 Returns
643 -------
644 interp : `lsst.afw.math.Interpolate`
645 Interpolation object for later evaluation.
646 """
647 if not np.ma.is_masked(collapsed):
648 collapsed.mask = np.array(len(collapsed)*[np.ma.nomask])
649
650 numPerBin, binEdges = np.histogram(indices, bins=numBins,
651 weights=1 - collapsed.mask.astype(int))
652 with np.errstate(invalid="ignore"):
653 values = np.histogram(indices, bins=numBins,
654 weights=collapsed.data*~collapsed.mask)[0]/numPerBin
655 binCenters = np.histogram(indices, bins=numBins,
656 weights=indices*~collapsed.mask)[0]/numPerBin
657
658 if len(binCenters[numPerBin > 0]) < 5:
659 self.log.warning("Cannot do spline fitting for overscan: %s valid points.",
660 len(binCenters[numPerBin > 0]))
661 # Return a scalar value if we have one, otherwise
662 # return zero. This amplifier is hopefully already
663 # masked.
664 if len(values[numPerBin > 0]) != 0:
665 return float(values[numPerBin > 0][0])
666 else:
667 return 0.0
668
669 interp = afwMath.makeInterpolate(binCenters.astype(float)[numPerBin > 0],
670 values.astype(float)[numPerBin > 0],
671 afwMath.stringToInterpStyle(self.config.fitType))
672 return interp
673
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.

◆ trimOverscan()

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.trimOverscan ( self,
exposure,
amp,
bbox,
skipLeading,
skipTrailing,
transpose = False )
Trim overscan region to remove edges.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure containing data.
amp : `lsst.afw.cameraGeom.Amplifier`
    Amplifier containing geometry information.
bbox : `lsst.geom.Box2I`
    Bounding box of the overscan region.
skipLeading : `int`
    Number of leading (towards data region) rows/columns to skip.
skipTrailing : `int`
    Number of trailing (away from data region) rows/columns to skip.
transpose : `bool`, optional
    Operate on the transposed array.

Returns
-------
overscanArray : `numpy.array`, (N, M)
    Data array to fit.
overscanMask : `numpy.array`, (N, M)
    Data mask.

Definition at line 317 of file overscan.py.

317 def trimOverscan(self, exposure, amp, bbox, skipLeading, skipTrailing, transpose=False):
318 """Trim overscan region to remove edges.
319
320 Parameters
321 ----------
322 exposure : `lsst.afw.image.Exposure`
323 Exposure containing data.
324 amp : `lsst.afw.cameraGeom.Amplifier`
325 Amplifier containing geometry information.
326 bbox : `lsst.geom.Box2I`
327 Bounding box of the overscan region.
328 skipLeading : `int`
329 Number of leading (towards data region) rows/columns to skip.
330 skipTrailing : `int`
331 Number of trailing (away from data region) rows/columns to skip.
332 transpose : `bool`, optional
333 Operate on the transposed array.
334
335 Returns
336 -------
337 overscanArray : `numpy.array`, (N, M)
338 Data array to fit.
339 overscanMask : `numpy.array`, (N, M)
340 Data mask.
341 """
342 dx0, dy0, dx1, dy1 = (0, 0, 0, 0)
343 dataBBox = amp.getRawDataBBox()
344 if transpose:
345 if dataBBox.getBeginY() < bbox.getBeginY():
346 dy0 += skipLeading
347 dy1 -= skipTrailing
348 else:
349 dy0 += skipTrailing
350 dy1 -= skipLeading
351 else:
352 if dataBBox.getBeginX() < bbox.getBeginX():
353 dx0 += skipLeading
354 dx1 -= skipTrailing
355 else:
356 dx0 += skipTrailing
357 dx1 -= skipLeading
358
359 overscanBBox = geom.Box2I(bbox.getBegin() + geom.Extent2I(dx0, dy0),
360 geom.Extent2I(bbox.getWidth() - dx0 + dx1,
361 bbox.getHeight() - dy0 + dy1))
362 return overscanBBox
363
An integer coordinate rectangle.
Definition Box.h:55

Member Data Documentation

◆ _DefaultName

str lsst.ip.isr.overscan.OverscanCorrectionTaskBase._DefaultName = "overscanBase"
staticprotected

Definition at line 140 of file overscan.py.

◆ allowDebug

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.allowDebug

Definition at line 144 of file overscan.py.

◆ ConfigClass

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.ConfigClass = OverscanCorrectionTaskConfigBase
static

Definition at line 139 of file overscan.py.

◆ splineEval

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.splineEval

Definition at line 779 of file overscan.py.

◆ splineFit

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.splineFit

Definition at line 779 of file overscan.py.

◆ statControl

lsst.ip.isr.overscan.OverscanCorrectionTaskBase.statControl

Definition at line 147 of file overscan.py.


The documentation for this class was generated from the following file: