24 from scipy
import ndimage
29 __all__ = [
"DcrModel",
"applyDcr",
"calculateDcr",
"calculateImageParallacticAngle"]
33 """A model of the true sky after correcting chromatic effects. 37 dcrNumSubfilters : `int` 38 Number of sub-filters used to model chromatic effects within a band. 39 modelImages : `list` of `lsst.afw.image.Image` 40 A list of masked images, each containing the model for one subfilter 44 The ``DcrModel`` contains an estimate of the true sky, at a higher 45 wavelength resolution than the input observations. It can be forward- 46 modeled to produce Differential Chromatic Refraction (DCR) matched 47 templates for a given ``Exposure``, and provides utilities for conditioning 48 the model in ``dcrAssembleCoadd`` to avoid oscillating solutions between 49 iterations of forward modeling or between the subfilters of the model. 52 def __init__(self, modelImages, filterInfo=None, psf=None, mask=None, variance=None):
61 def fromImage(cls, maskedImage, dcrNumSubfilters, filterInfo=None, psf=None):
62 """Initialize a DcrModel by dividing a coadd between the subfilters. 66 maskedImage : `lsst.afw.image.MaskedImage` 67 Input coadded image to divide equally between the subfilters. 68 dcrNumSubfilters : `int` 69 Number of sub-filters used to model chromatic effects within a band. 70 filterInfo : `lsst.afw.image.Filter`, optional 71 The filter definition, set in the current instruments' obs package. 72 Required for any calculation of DCR, including making matched templates. 73 psf : `lsst.afw.detection.Psf`, optional 74 Point spread function (PSF) of the model. 75 Required if the ``DcrModel`` will be persisted. 79 dcrModel : `lsst.pipe.tasks.DcrModel` 80 Best fit model of the true sky after correcting chromatic effects. 85 If there are any unmasked NAN values in ``maskedImage``. 89 model = maskedImage.image.clone()
90 mask = maskedImage.mask.clone()
96 variance = maskedImage.variance.clone()
97 variance /= dcrNumSubfilters
98 model /= dcrNumSubfilters
99 modelImages = [model, ]
100 for subfilter
in range(1, dcrNumSubfilters):
101 modelImages.append(model.clone())
102 return cls(modelImages, filterInfo, psf, mask, variance)
105 def fromDataRef(cls, dataRef, datasetType="dcrCoadd", numSubfilters=None, **kwargs):
106 """Load an existing DcrModel from a repository. 110 dataRef : `lsst.daf.persistence.ButlerDataRef` 111 Data reference defining the patch for coaddition and the 113 datasetType : `str`, optional 114 Name of the DcrModel in the registry {"dcrCoadd", "dcrCoadd_sub"} 115 numSubfilters : `int` 116 Number of sub-filters used to model chromatic effects within a band. 118 Additional keyword arguments to pass to look up the model in the data registry. 119 Common keywords and their types include: ``tract``:`str`, ``patch``:`str`, 120 ``bbox``:`lsst.afw.geom.Box2I` 124 dcrModel : `lsst.pipe.tasks.DcrModel` 125 Best fit model of the true sky after correcting chromatic effects. 132 for subfilter
in range(numSubfilters):
133 dcrCoadd = dataRef.get(datasetType, subfilter=subfilter,
134 numSubfilters=numSubfilters, **kwargs)
135 if filterInfo
is None:
136 filterInfo = dcrCoadd.getFilter()
138 psf = dcrCoadd.getPsf()
142 variance = dcrCoadd.variance
143 modelImages.append(dcrCoadd.image)
144 return cls(modelImages, filterInfo, psf, mask, variance)
147 """Return the number of subfilters. 151 dcrNumSubfilters : `int` 152 The number of DCR subfilters in the model. 157 """Iterate over the subfilters of the DCR model. 162 Index of the current ``subfilter`` within the full band. 163 Negative indices are allowed, and count in reverse order 164 from the highest ``subfilter``. 168 modelImage : `lsst.afw.image.Image` 169 The DCR model for the given ``subfilter``. 174 If the requested ``subfilter`` is greater or equal to the number 175 of subfilters in the model. 177 if np.abs(subfilter) >= len(self):
178 raise IndexError(
"subfilter out of bounds.")
182 """Update the model image for one subfilter. 187 Index of the current subfilter within the full band. 188 maskedImage : `lsst.afw.image.Image` 189 The DCR model to set for the given ``subfilter``. 194 If the requested ``subfilter`` is greater or equal to the number 195 of subfilters in the model. 197 If the bounding box of the new image does not match. 199 if np.abs(subfilter) >= len(self):
200 raise IndexError(
"subfilter out of bounds.")
201 if maskedImage.getBBox() != self.
bbox:
202 raise ValueError(
"The bounding box of a subfilter must not change.")
207 """Return the filter of the model. 211 filter : `lsst.afw.image.Filter` 212 The filter definition, set in the current instruments' obs package. 218 """Return the psf of the model. 222 psf : `lsst.afw.detection.Psf` 223 Point spread function (PSF) of the model. 229 """Return the common bounding box of each subfilter image. 233 bbox : `lsst.afw.geom.Box2I` 234 Bounding box of the DCR model. 236 return self[0].getBBox()
240 """Return the common mask of each subfilter image. 244 mask : `lsst.afw.image.Mask` 245 Mask plane of the DCR model. 251 """Return the common variance of each subfilter image. 255 variance : `lsst.afw.image.Image` 256 Variance plane of the DCR model. 261 """Calculate a reference image from the average of the subfilter images. 265 bbox : `lsst.afw.geom.Box2I`, optional 266 Sub-region of the coadd. Returns the entire image if `None`. 270 refImage : `numpy.ndarray` 271 The reference image with no chromatic effects applied. 273 bbox = bbox
or self.
bbox 274 return np.mean([model[bbox].array
for model
in self], axis=0)
276 def assign(self, dcrSubModel, bbox=None):
277 """Update a sub-region of the ``DcrModel`` with new values. 281 dcrSubModel : `lsst.pipe.tasks.DcrModel` 282 New model of the true scene after correcting chromatic effects. 283 bbox : `lsst.afw.geom.Box2I`, optional 284 Sub-region of the coadd. 285 Defaults to the bounding box of ``dcrSubModel``. 290 If the new model has a different number of subfilters. 292 if len(dcrSubModel) != len(self):
293 raise ValueError(
"The number of DCR subfilters must be the same " 294 "between the old and new models.")
295 bbox = bbox
or self.
bbox 296 for model, subModel
in zip(self, dcrSubModel):
297 model.assign(subModel[bbox], bbox)
300 visitInfo=None, bbox=None, wcs=None, mask=None,
301 splitSubfilters=True, splitThreshold=0., amplifyModel=1.):
302 """Create a DCR-matched template image for an exposure. 306 exposure : `lsst.afw.image.Exposure`, optional 307 The input exposure to build a matched template for. 308 May be omitted if all of the metadata is supplied separately 309 order : `int`, optional 310 Interpolation order of the DCR shift. 311 visitInfo : `lsst.afw.image.VisitInfo`, optional 312 Metadata for the exposure. Ignored if ``exposure`` is set. 313 bbox : `lsst.afw.geom.Box2I`, optional 314 Sub-region of the coadd. Ignored if ``exposure`` is set. 315 wcs : `lsst.afw.geom.SkyWcs`, optional 316 Coordinate system definition (wcs) for the exposure. 317 Ignored if ``exposure`` is set. 318 mask : `lsst.afw.image.Mask`, optional 319 reference mask to use for the template image. 320 splitSubfilters : `bool`, optional 321 Calculate DCR for two evenly-spaced wavelengths in each subfilter, 322 instead of at the midpoint. Default: True 323 splitThreshold : `float`, optional 324 Minimum DCR difference within a subfilter required to use ``splitSubfilters`` 325 amplifyModel : `float`, optional 326 Multiplication factor to amplify differences between model planes. 327 Used to speed convergence of iterative forward modeling. 331 templateImage : `lsst.afw.image.ImageF` 332 The DCR-matched template 337 If neither ``exposure`` or all of ``visitInfo``, ``bbox``, and ``wcs`` are set. 340 raise ValueError(
"'filterInfo' must be set for the DcrModel in order to calculate DCR.")
341 if exposure
is not None:
342 visitInfo = exposure.getInfo().getVisitInfo()
343 bbox = exposure.getBBox()
344 wcs = exposure.getInfo().getWcs()
345 elif visitInfo
is None or bbox
is None or wcs
is None:
346 raise ValueError(
"Either exposure or visitInfo, bbox, and wcs must be set.")
347 dcrShift =
calculateDcr(visitInfo, wcs, self.
filter, len(self), splitSubfilters=splitSubfilters)
348 templateImage = afwImage.ImageF(bbox)
350 for subfilter, dcr
in enumerate(dcrShift):
352 model = (self[subfilter][bbox].array - refModel)*amplifyModel + refModel
354 model = self[subfilter][bbox].array
355 templateImage.array +=
applyDcr(model, dcr, splitSubfilters=splitSubfilters,
356 splitThreshold=splitThreshold, order=order)
360 visitInfo=None, bbox=None, wcs=None, mask=None):
361 """Wrapper to create an exposure from a template image. 365 exposure : `lsst.afw.image.Exposure`, optional 366 The input exposure to build a matched template for. 367 May be omitted if all of the metadata is supplied separately 368 visitInfo : `lsst.afw.image.VisitInfo`, optional 369 Metadata for the exposure. Ignored if ``exposure`` is set. 370 bbox : `lsst.afw.geom.Box2I`, optional 371 Sub-region of the coadd. Ignored if ``exposure`` is set. 372 wcs : `lsst.afw.geom.SkyWcs`, optional 373 Coordinate system definition (wcs) for the exposure. 374 Ignored if ``exposure`` is set. 375 mask : `lsst.afw.image.Mask`, optional 376 reference mask to use for the template image. 380 templateExposure : `lsst.afw.image.exposureF` 381 The DCR-matched template 384 bbox = exposure.getBBox()
386 bbox=bbox, wcs=wcs, mask=mask)
387 maskedImage = afwImage.MaskedImageF(bbox)
388 maskedImage.image = templateImage[bbox]
389 maskedImage.mask = self.
mask[bbox]
390 maskedImage.variance = self.
variance[bbox]
391 templateExposure = afwImage.ExposureF(bbox, wcs)
392 templateExposure.setMaskedImage(maskedImage[bbox])
393 templateExposure.setPsf(self.
psf)
394 templateExposure.setFilter(self.
filter)
395 return templateExposure
398 """Average two iterations' solutions to reduce oscillations. 402 modelImages : `list` of `lsst.afw.image.Image` 403 The new DCR model images from the current iteration. 404 The values will be modified in place. 405 bbox : `lsst.afw.geom.Box2I` 406 Sub-region of the coadd 407 gain : `float`, optional 408 Relative weight to give the new solution when updating the model. 409 Defaults to 1.0, which gives equal weight to both solutions. 412 for model, newModel
in zip(self, modelImages):
414 newModel += model[bbox]
415 newModel /= 1. + gain
418 regularizationWidth=2):
419 """Restrict large variations in the model between iterations. 424 Index of the current subfilter within the full band. 425 newModel : `lsst.afw.image.Image` 426 The new DCR model for one subfilter from the current iteration. 427 Values in ``newModel`` that are extreme compared with the last 428 iteration are modified in place. 429 bbox : `lsst.afw.geom.Box2I` 431 regularizationFactor : `float` 432 Maximum relative change of the model allowed between iterations. 433 regularizationWidth : int, optional 434 Minimum radius of a region to include in regularization, in pixels. 436 refImage = self[subfilter][bbox].array
437 highThreshold = np.abs(refImage)*regularizationFactor
438 lowThreshold = refImage/regularizationFactor
439 newImage = newModel.array
441 regularizationWidth=regularizationWidth)
444 regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED"):
445 """Restrict large variations in the model between subfilters. 449 modelImages : `list` of `lsst.afw.image.Image` 450 The new DCR model images from the current iteration. 451 The values will be modified in place. 452 bbox : `lsst.afw.geom.Box2I` 454 statsCtrl : `lsst.afw.math.StatisticsControl` 455 Statistics control object for coaddition. 456 regularizationFactor : `float` 457 Maximum relative change of the model allowed between subfilters. 458 regularizationWidth : `int`, optional 459 Minimum radius of a region to include in regularization, in pixels. 460 mask : `lsst.afw.image.Mask`, optional 461 Optional alternate mask 462 convergenceMaskPlanes : `list` of `str`, or `str`, optional 463 Mask planes to use to calculate convergence. 467 This implementation of frequency regularization restricts each subfilter 468 image to be a smoothly-varying function times a reference image. 472 maxDiff = np.sqrt(regularizationFactor)
473 noiseLevel = self.
calculateNoiseCutoff(modelImages[0], statsCtrl, bufferSize=5, mask=mask, bbox=bbox)
475 badPixels = np.isnan(referenceImage) | (referenceImage <= 0.)
476 if np.sum(~badPixels) == 0:
479 referenceImage[badPixels] = 0.
480 filterWidth = regularizationWidth
481 fwhm = 2.*filterWidth
484 smoothRef = ndimage.filters.gaussian_filter(referenceImage, filterWidth, mode=
'constant')
487 smoothRef += 3.*noiseLevel
489 lowThreshold = smoothRef/maxDiff
490 highThreshold = smoothRef*maxDiff
491 for model
in modelImages:
493 highThreshold=highThreshold,
494 lowThreshold=lowThreshold,
495 regularizationWidth=regularizationWidth)
496 smoothModel = ndimage.filters.gaussian_filter(model.array, filterWidth, mode=
'constant')
497 smoothModel += 3.*noiseLevel
498 relativeModel = smoothModel/smoothRef
501 relativeModel2 = ndimage.filters.gaussian_filter(relativeModel, filterWidth/alpha)
502 relativeModel += alpha*(relativeModel - relativeModel2)
503 model.array = relativeModel*referenceImage
506 convergenceMaskPlanes="DETECTED", mask=None, bbox=None):
507 """Helper function to calculate the background noise level of an image. 511 image : `lsst.afw.image.Image` 512 The input image to evaluate the background noise properties. 513 statsCtrl : `lsst.afw.math.StatisticsControl` 514 Statistics control object for coaddition. 516 Number of additional pixels to exclude 517 from the edges of the bounding box. 518 convergenceMaskPlanes : `list` of `str`, or `str` 519 Mask planes to use to calculate convergence. 520 mask : `lsst.afw.image.Mask`, Optional 521 Optional alternate mask 522 bbox : `lsst.afw.geom.Box2I`, optional 523 Sub-region of the masked image to calculate the noise level over. 527 noiseCutoff : `float` 528 The threshold value to treat pixels as noise in an image.. 533 mask = self.
mask[bbox]
535 bboxShrink.grow(-bufferSize)
536 convergeMask = mask.getPlaneBitMask(convergenceMaskPlanes)
538 backgroundPixels = mask[bboxShrink].array & (statsCtrl.getAndMask() | convergeMask) == 0
539 noiseCutoff = np.std(image[bboxShrink].array[backgroundPixels])
543 """Restrict image values to be between upper and lower limits. 545 This method flags all pixels in an image that are outside of the given 546 threshold values. The threshold values are taken from a reference image, 547 so noisy pixels are likely to get flagged. In order to exclude those 548 noisy pixels, the array of flags is eroded and dilated, which removes 549 isolated pixels outside of the thresholds from the list of pixels to be 550 modified. Pixels that remain flagged after this operation have their 551 values set to the appropriate upper or lower threshold value. 555 image : `numpy.ndarray` 556 The image to apply the thresholds to. 557 The values will be modified in place. 558 highThreshold : `numpy.ndarray`, optional 559 Array of upper limit values for each pixel of ``image``. 560 lowThreshold : `numpy.ndarray`, optional 561 Array of lower limit values for each pixel of ``image``. 562 regularizationWidth : `int`, optional 563 Minimum radius of a region to include in regularization, in pixels. 568 filterStructure = ndimage.iterate_structure(ndimage.generate_binary_structure(2, 1),
570 if highThreshold
is not None:
571 highPixels = image > highThreshold
572 if regularizationWidth > 0:
574 highPixels = ndimage.morphology.binary_opening(highPixels, structure=filterStructure)
575 image[highPixels] = highThreshold[highPixels]
576 if lowThreshold
is not None:
577 lowPixels = image < lowThreshold
578 if regularizationWidth > 0:
580 lowPixels = ndimage.morphology.binary_opening(lowPixels, structure=filterStructure)
581 image[lowPixels] = lowThreshold[lowPixels]
584 def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
585 doPrefilter=True, order=3):
586 """Shift an image along the X and Y directions. 590 image : `numpy.ndarray` 591 The input image to shift. 593 Shift calculated with ``calculateDcr``. 594 Uses numpy axes ordering (Y, X). 595 If ``splitSubfilters`` is set, each element is itself a `tuple` 596 of two `float`, corresponding to the DCR shift at the two wavelengths. 597 Otherwise, each element is a `float` corresponding to the DCR shift at 598 the effective wavelength of the subfilter. 599 useInverse : `bool`, optional 600 Apply the shift in the opposite direction. Default: False 601 splitSubfilters : `bool`, optional 602 Calculate DCR for two evenly-spaced wavelengths in each subfilter, 603 instead of at the midpoint. Default: False 604 splitThreshold : `float`, optional 605 Minimum DCR difference within a subfilter required to use ``splitSubfilters`` 606 doPrefilter : `bool`, optional 607 Spline filter the image before shifting, if set. Filtering is required, 608 so only set to False if the image is already filtered. 609 Filtering takes ~20% of the time of shifting, so if `applyDcr` will be 610 called repeatedly on the same image it is more efficient to precalculate 612 order : `int`, optional 613 The order of the spline interpolation, default is 3. 617 shiftedImage : `numpy.ndarray` 618 A copy of the input image with the specified shift applied. 621 prefilteredImage = ndimage.spline_filter(image, order=order)
623 prefilteredImage = image
625 shiftAmp = np.max(np.abs([_dcr0 - _dcr1
for _dcr0, _dcr1
in zip(dcr[0], dcr[1])]))
626 if shiftAmp >= splitThreshold:
628 shift = [-1.*s
for s
in dcr[0]]
629 shift1 = [-1.*s
for s
in dcr[1]]
633 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
634 shiftedImage += ndimage.shift(prefilteredImage, shift1, prefilter=
False, order=order)
640 dcr = (np.mean(dcr[0]), np.mean(dcr[1]))
642 shift = [-1.*s
for s
in dcr]
645 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
649 def calculateDcr(visitInfo, wcs, filterInfo, dcrNumSubfilters, splitSubfilters=False):
650 """Calculate the shift in pixels of an exposure due to DCR. 654 visitInfo : `lsst.afw.image.VisitInfo` 655 Metadata for the exposure. 656 wcs : `lsst.afw.geom.SkyWcs` 657 Coordinate system definition (wcs) for the exposure. 658 filterInfo : `lsst.afw.image.Filter` 659 The filter definition, set in the current instruments' obs package. 660 dcrNumSubfilters : `int` 661 Number of sub-filters used to model chromatic effects within a band. 662 splitSubfilters : `bool`, optional 663 Calculate DCR for two evenly-spaced wavelengths in each subfilter, 664 instead of at the midpoint. Default: False 668 dcrShift : `tuple` of two `float` 669 The 2D shift due to DCR, in pixels. 670 Uses numpy axes ordering (Y, X). 674 weight = [0.75, 0.25]
675 lambdaEff = filterInfo.getFilterProperty().getLambdaEff()
679 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
680 observatory=visitInfo.getObservatory(),
681 weather=visitInfo.getWeather())
683 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
684 observatory=visitInfo.getObservatory(),
685 weather=visitInfo.getWeather())
687 diffRefractPix0 = diffRefractAmp0.asArcseconds()/wcs.getPixelScale().asArcseconds()
688 diffRefractPix1 = diffRefractAmp1.asArcseconds()/wcs.getPixelScale().asArcseconds()
689 diffRefractArr = [diffRefractPix0*weight[0] + diffRefractPix1*weight[1],
690 diffRefractPix0*weight[1] + diffRefractPix1*weight[0]]
691 shiftX = [diffRefractPix*np.sin(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
692 shiftY = [diffRefractPix*np.cos(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
693 dcrShift.append(((shiftY[0], shiftX[0]), (shiftY[1], shiftX[1])))
695 diffRefractAmp = (diffRefractAmp0 + diffRefractAmp1)/2.
696 diffRefractPix = diffRefractAmp.asArcseconds()/wcs.getPixelScale().asArcseconds()
697 shiftX = diffRefractPix*np.sin(rotation.asRadians())
698 shiftY = diffRefractPix*np.cos(rotation.asRadians())
699 dcrShift.append((shiftY, shiftX))
704 """Calculate the total sky rotation angle of an exposure. 708 visitInfo : `lsst.afw.image.VisitInfo` 709 Metadata for the exposure. 710 wcs : `lsst.afw.geom.SkyWcs` 711 Coordinate system definition (wcs) for the exposure. 716 The rotation of the image axis, East from North. 717 Equal to the parallactic angle plus any additional rotation of the 719 A rotation angle of 0 degrees is defined with 720 North along the +y axis and East along the +x axis. 721 A rotation angle of 90 degrees is defined with 722 North along the +x axis and East along the -y axis. 724 parAngle = visitInfo.getBoresightParAngle().asRadians()
725 cd = wcs.getCdMatrix()
727 cdAngle = (np.arctan2(-cd[0, 1], cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
728 rotAngle = (cdAngle + parAngle)*geom.radians
730 cdAngle = (np.arctan2(cd[0, 1], -cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
731 rotAngle = (cdAngle - parAngle)*geom.radians
736 """Iterate over the wavelength endpoints of subfilters. 740 filterInfo : `lsst.afw.image.Filter` 741 The filter definition, set in the current instruments' obs package. 742 dcrNumSubfilters : `int` 743 Number of sub-filters used to model chromatic effects within a band. 747 `tuple` of two `float` 748 The next set of wavelength endpoints for a subfilter, in nm. 750 lambdaMin = filterInfo.getFilterProperty().getLambdaMin()
751 lambdaMax = filterInfo.getFilterProperty().getLambdaMax()
752 wlStep = (lambdaMax - lambdaMin)/dcrNumSubfilters
753 for wl
in np.linspace(lambdaMin, lambdaMax, dcrNumSubfilters, endpoint=
False):
754 yield (wl, wl + wlStep)
def fromImage(cls, maskedImage, dcrNumSubfilters, filterInfo=None, psf=None)
def __setitem__(self, subfilter, maskedImage)
def calculateImageParallacticAngle(visitInfo, wcs)
def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0., doPrefilter=True, order=3)
def regularizeModelIter(self, subfilter, newModel, bbox, regularizationFactor, regularizationWidth=2)
def __getitem__(self, subfilter)
def calculateNoiseCutoff(self, image, statsCtrl, bufferSize, convergenceMaskPlanes="DETECTED", mask=None, bbox=None)
def __init__(self, modelImages, filterInfo=None, psf=None, mask=None, variance=None)
def wavelengthGenerator(filterInfo, dcrNumSubfilters)
def applyImageThresholds(self, image, highThreshold=None, lowThreshold=None, regularizationWidth=2)
def buildMatchedExposure(self, exposure=None, visitInfo=None, bbox=None, wcs=None, mask=None)
def fromDataRef(cls, dataRef, datasetType="dcrCoadd", numSubfilters=None, kwargs)
def getReferenceImage(self, bbox=None)
def differentialRefraction(wavelength, wavelengthRef, elevation, observatory, weather=None)
def buildMatchedTemplate(self, exposure=None, order=3, visitInfo=None, bbox=None, wcs=None, mask=None, splitSubfilters=True, splitThreshold=0., amplifyModel=1.)
def assign(self, dcrSubModel, bbox=None)
def calculateDcr(visitInfo, wcs, filterInfo, dcrNumSubfilters, splitSubfilters=False)
def regularizeModelFreq(self, modelImages, bbox, statsCtrl, regularizationFactor, regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED")
def conditionDcrModel(self, modelImages, bbox, gain=1.)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
An integer coordinate rectangle.