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, effectiveWavelength, bandwidth, filterLabel=None, psf=None,
53 mask=None, variance=None, photoCalib=None):
60 self.
_mask_mask = mask
65 def fromImage(cls, maskedImage, dcrNumSubfilters, effectiveWavelength, bandwidth,
66 filterLabel=None, psf=None, photoCalib=None):
67 """Initialize a DcrModel by dividing a coadd between the subfilters.
71 maskedImage : `lsst.afw.image.MaskedImage`
72 Input coadded image to divide equally between the subfilters.
73 dcrNumSubfilters : `int`
74 Number of sub-filters used to model chromatic effects within a
76 effectiveWavelength : `float`
77 The effective wavelengths of the current filter, in nanometers.
79 The bandwidth of the current filter, in nanometers.
80 filterLabel : `lsst.afw.image.FilterLabel`, optional
81 The filter label, set in the current instruments' obs package.
82 Required for any calculation of DCR, including making matched
84 psf : `lsst.afw.detection.Psf`, optional
85 Point spread function (PSF) of the model.
86 Required if the ``DcrModel`` will be persisted.
87 photoCalib : `lsst.afw.image.PhotoCalib`, optional
88 Calibration to convert instrumental flux and
89 flux error to nanoJansky.
93 dcrModel : `lsst.pipe.tasks.DcrModel`
94 Best fit model of the true sky after correcting chromatic effects.
98 model = maskedImage.image.clone()
99 mask = maskedImage.mask.clone()
105 variance = maskedImage.variance.clone()
106 variance /= dcrNumSubfilters
107 model /= dcrNumSubfilters
108 modelImages = [model, ]
109 for subfilter
in range(1, dcrNumSubfilters):
110 modelImages.append(model.clone())
111 return cls(modelImages, effectiveWavelength, bandwidth,
112 filterLabel=filterLabel, psf=psf, mask=mask, variance=variance, photoCalib=photoCalib)
115 def fromDataRef(cls, dataRef, effectiveWavelength, bandwidth, datasetType="dcrCoadd", numSubfilters=None,
117 """Load an existing DcrModel from a Gen 2 repository.
121 dataRef : `lsst.daf.persistence.ButlerDataRef`
122 Data reference defining the patch for coaddition and the
124 effectiveWavelength : `float`
125 The effective wavelengths of the current filter, in nanometers.
127 The bandwidth of the current filter, in nanometers.
128 datasetType : `str`, optional
129 Name of the DcrModel in the registry {"dcrCoadd", "dcrCoadd_sub"}
130 numSubfilters : `int`
131 Number of sub-filters used to model chromatic effects within a
134 Additional keyword arguments to pass to look up the model in the
136 Common keywords and their types include: ``tract``:`str`,
137 ``patch``:`str`, ``bbox``:`lsst.afw.geom.Box2I`
141 dcrModel : `lsst.pipe.tasks.DcrModel`
142 Best fit model of the true sky after correcting chromatic effects.
150 if "subfilter" in kwargs:
151 kwargs.pop(
"subfilter")
152 for subfilter
in range(numSubfilters):
153 dcrCoadd = dataRef.get(datasetType, subfilter=subfilter,
154 numSubfilters=numSubfilters, **kwargs)
155 if filterLabel
is None:
156 filterLabel = dcrCoadd.getFilterLabel()
158 psf = dcrCoadd.getPsf()
162 variance = dcrCoadd.variance
163 if photoCalib
is None:
164 photoCalib = dcrCoadd.getPhotoCalib()
165 modelImages.append(dcrCoadd.image)
166 return cls(modelImages, effectiveWavelength, bandwidth, filterLabel, psf, mask, variance, photoCalib)
169 def fromQuantum(cls, availableCoaddRefs, effectiveWavelength, bandwidth):
170 """Load an existing DcrModel from a Gen 3 repository.
174 availableCoaddRefs : `dict` [`int`, `lsst.daf.butler.DeferredDatasetHandle`]
175 Dictionary of spatially relevant retrieved coadd patches,
176 indexed by their sequential patch number.
177 effectiveWavelength : `float`
178 The effective wavelengths of the current filter, in nanometers.
180 The bandwidth of the current filter, in nanometers.
184 dcrModel : `lsst.pipe.tasks.DcrModel`
185 Best fit model of the true sky after correcting chromatic effects.
192 modelImages = [
None]*len(availableCoaddRefs)
194 for coaddRef
in availableCoaddRefs:
195 subfilter = coaddRef.dataId[
"subfilter"]
196 dcrCoadd = coaddRef.get()
197 if filterLabel
is None:
198 filterLabel = dcrCoadd.getFilterLabel()
200 psf = dcrCoadd.getPsf()
204 variance = dcrCoadd.variance
205 if photoCalib
is None:
206 photoCalib = dcrCoadd.getPhotoCalib()
207 modelImages[subfilter] = dcrCoadd.image
208 return cls(modelImages, effectiveWavelength, bandwidth, filterLabel, psf, mask, variance, photoCalib)
211 """Return the number of subfilters.
215 dcrNumSubfilters : `int`
216 The number of DCR subfilters in the model.
221 """Iterate over the subfilters of the DCR model.
226 Index of the current ``subfilter`` within the full band.
227 Negative indices are allowed, and count in reverse order
228 from the highest ``subfilter``.
232 modelImage : `lsst.afw.image.Image`
233 The DCR model for the given ``subfilter``.
238 If the requested ``subfilter`` is greater or equal to the number
239 of subfilters in the model.
241 if np.abs(subfilter) >= len(self):
242 raise IndexError(
"subfilter out of bounds.")
246 """Update the model image for one subfilter.
251 Index of the current subfilter within the full band.
252 maskedImage : `lsst.afw.image.Image`
253 The DCR model to set for the given ``subfilter``.
258 If the requested ``subfilter`` is greater or equal to the number
259 of subfilters in the model.
261 If the bounding box of the new image does not match.
263 if np.abs(subfilter) >= len(self):
264 raise IndexError(
"subfilter out of bounds.")
265 if maskedImage.getBBox() != self.
bboxbbox:
266 raise ValueError(
"The bounding box of a subfilter must not change.")
267 self.
modelImagesmodelImages[subfilter] = maskedImage
271 """Return the effective wavelength of the model.
275 effectiveWavelength : `float`
276 The effective wavelength of the current filter, in nanometers.
282 """Return the filter label for the model.
286 filterLabel : `lsst.afw.image.FilterLabel`
287 The filter used for the input observations.
293 """Return the bandwidth of the model.
298 The bandwidth of the current filter, in nanometers.
304 """Return the psf of the model.
308 psf : `lsst.afw.detection.Psf`
309 Point spread function (PSF) of the model.
315 """Return the common bounding box of each subfilter image.
319 bbox : `lsst.afw.geom.Box2I`
320 Bounding box of the DCR model.
322 return self[0].getBBox()
326 """Return the common mask of each subfilter image.
330 mask : `lsst.afw.image.Mask`
331 Mask plane of the DCR model.
333 return self.
_mask_mask
337 """Return the common variance of each subfilter image.
341 variance : `lsst.afw.image.Image`
342 Variance plane of the DCR model.
347 """Calculate a reference image from the average of the subfilter
352 bbox : `lsst.afw.geom.Box2I`, optional
353 Sub-region of the coadd. Returns the entire image if `None`.
357 refImage : `numpy.ndarray`
358 The reference image with no chromatic effects applied.
360 bbox = bbox
or self.
bboxbbox
361 return np.mean([model[bbox].array
for model
in self], axis=0)
363 def assign(self, dcrSubModel, bbox=None):
364 """Update a sub-region of the ``DcrModel`` with new values.
368 dcrSubModel : `lsst.pipe.tasks.DcrModel`
369 New model of the true scene after correcting chromatic effects.
370 bbox : `lsst.afw.geom.Box2I`, optional
371 Sub-region of the coadd.
372 Defaults to the bounding box of ``dcrSubModel``.
377 If the new model has a different number of subfilters.
379 if len(dcrSubModel) != len(self):
380 raise ValueError(
"The number of DCR subfilters must be the same "
381 "between the old and new models.")
382 bbox = bbox
or self.
bboxbbox
383 for model, subModel
in zip(self, dcrSubModel):
384 model.assign(subModel[bbox], bbox)
387 visitInfo=None, bbox=None, wcs=None, mask=None,
388 splitSubfilters=True, splitThreshold=0., amplifyModel=1.):
389 """Create a DCR-matched template image for an exposure.
393 exposure : `lsst.afw.image.Exposure`, optional
394 The input exposure to build a matched template for.
395 May be omitted if all of the metadata is supplied separately
396 order : `int`, optional
397 Interpolation order of the DCR shift.
398 visitInfo : `lsst.afw.image.VisitInfo`, optional
399 Metadata for the exposure. Ignored if ``exposure`` is set.
400 bbox : `lsst.afw.geom.Box2I`, optional
401 Sub-region of the coadd. Ignored if ``exposure`` is set.
402 wcs : `lsst.afw.geom.SkyWcs`, optional
403 Coordinate system definition (wcs) for the exposure.
404 Ignored if ``exposure`` is set.
405 mask : `lsst.afw.image.Mask`, optional
406 reference mask to use for the template image.
407 splitSubfilters : `bool`, optional
408 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
409 instead of at the midpoint. Default: True
410 splitThreshold : `float`, optional
411 Minimum DCR difference within a subfilter required to use
413 amplifyModel : `float`, optional
414 Multiplication factor to amplify differences between model planes.
415 Used to speed convergence of iterative forward modeling.
419 templateImage : `lsst.afw.image.ImageF`
420 The DCR-matched template
425 If neither ``exposure`` or all of ``visitInfo``, ``bbox``, and
429 raise ValueError(
"'effectiveWavelength' and 'bandwidth' must be set for the DcrModel in order "
431 if exposure
is not None:
432 visitInfo = exposure.getInfo().getVisitInfo()
433 bbox = exposure.getBBox()
434 wcs = exposure.getInfo().getWcs()
435 elif visitInfo
is None or bbox
is None or wcs
is None:
436 raise ValueError(
"Either exposure or visitInfo, bbox, and wcs must be set.")
438 splitSubfilters=splitSubfilters)
439 templateImage = afwImage.ImageF(bbox)
441 for subfilter, dcr
in enumerate(dcrShift):
443 model = (self[subfilter][bbox].array - refModel)*amplifyModel + refModel
445 model = self[subfilter][bbox].array
446 templateImage.array +=
applyDcr(model, dcr, splitSubfilters=splitSubfilters,
447 splitThreshold=splitThreshold, order=order)
451 visitInfo=None, bbox=None, wcs=None, mask=None):
452 """Wrapper to create an exposure from a template image.
456 exposure : `lsst.afw.image.Exposure`, optional
457 The input exposure to build a matched template for.
458 May be omitted if all of the metadata is supplied separately
459 visitInfo : `lsst.afw.image.VisitInfo`, optional
460 Metadata for the exposure. Ignored if ``exposure`` is set.
461 bbox : `lsst.afw.geom.Box2I`, optional
462 Sub-region of the coadd. Ignored if ``exposure`` is set.
463 wcs : `lsst.afw.geom.SkyWcs`, optional
464 Coordinate system definition (wcs) for the exposure.
465 Ignored if ``exposure`` is set.
466 mask : `lsst.afw.image.Mask`, optional
467 reference mask to use for the template image.
471 templateExposure : `lsst.afw.image.exposureF`
472 The DCR-matched template
477 If no `photcCalib` is set.
480 bbox = exposure.getBBox()
481 templateImage = self.
buildMatchedTemplatebuildMatchedTemplate(exposure=exposure, visitInfo=visitInfo,
482 bbox=bbox, wcs=wcs, mask=mask)
483 maskedImage = afwImage.MaskedImageF(bbox)
484 maskedImage.image = templateImage[bbox]
485 maskedImage.mask = self.
maskmask[bbox]
486 maskedImage.variance = self.
variancevariance[bbox]
490 templateExposure = afwImage.ExposureF(bbox, wcs)
491 templateExposure.setMaskedImage(maskedImage[bbox])
492 templateExposure.setPsf(self.
psfpsf)
493 templateExposure.setFilterLabel(self.filterLabel)
495 raise RuntimeError(
"No PhotoCalib set for the DcrModel. "
496 "If the DcrModel was created from a masked image"
497 " you must also specify the photoCalib.")
498 templateExposure.setPhotoCalib(self.
photoCalibphotoCalib)
499 return templateExposure
502 """Average two iterations' solutions to reduce oscillations.
506 modelImages : `list` of `lsst.afw.image.Image`
507 The new DCR model images from the current iteration.
508 The values will be modified in place.
509 bbox : `lsst.afw.geom.Box2I`
510 Sub-region of the coadd
511 gain : `float`, optional
512 Relative weight to give the new solution when updating the model.
513 Defaults to 1.0, which gives equal weight to both solutions.
516 for model, newModel
in zip(self, modelImages):
518 newModel += model[bbox]
519 newModel /= 1. + gain
522 regularizationWidth=2):
523 """Restrict large variations in the model between iterations.
528 Index of the current subfilter within the full band.
529 newModel : `lsst.afw.image.Image`
530 The new DCR model for one subfilter from the current iteration.
531 Values in ``newModel`` that are extreme compared with the last
532 iteration are modified in place.
533 bbox : `lsst.afw.geom.Box2I`
535 regularizationFactor : `float`
536 Maximum relative change of the model allowed between iterations.
537 regularizationWidth : int, optional
538 Minimum radius of a region to include in regularization, in pixels.
540 refImage = self[subfilter][bbox].array
541 highThreshold = np.abs(refImage)*regularizationFactor
542 lowThreshold = refImage/regularizationFactor
543 newImage = newModel.array
544 self.
applyImageThresholdsapplyImageThresholds(newImage, highThreshold=highThreshold, lowThreshold=lowThreshold,
545 regularizationWidth=regularizationWidth)
548 regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED"):
549 """Restrict large variations in the model between subfilters.
553 modelImages : `list` of `lsst.afw.image.Image`
554 The new DCR model images from the current iteration.
555 The values will be modified in place.
556 bbox : `lsst.afw.geom.Box2I`
558 statsCtrl : `lsst.afw.math.StatisticsControl`
559 Statistics control object for coaddition.
560 regularizationFactor : `float`
561 Maximum relative change of the model allowed between subfilters.
562 regularizationWidth : `int`, optional
563 Minimum radius of a region to include in regularization, in pixels.
564 mask : `lsst.afw.image.Mask`, optional
565 Optional alternate mask
566 convergenceMaskPlanes : `list` of `str`, or `str`, optional
567 Mask planes to use to calculate convergence.
571 This implementation of frequency regularization restricts each
572 subfilter image to be a smoothly-varying function times a reference
578 maxDiff = np.sqrt(regularizationFactor)
579 noiseLevel = self.
calculateNoiseCutoffcalculateNoiseCutoff(modelImages[0], statsCtrl, bufferSize=5, mask=mask, bbox=bbox)
581 badPixels = np.isnan(referenceImage) | (referenceImage <= 0.)
582 if np.sum(~badPixels) == 0:
585 referenceImage[badPixels] = 0.
586 filterWidth = regularizationWidth
587 fwhm = 2.*filterWidth
591 smoothRef = ndimage.filters.gaussian_filter(referenceImage, filterWidth, mode=
'constant')
595 smoothRef += 3.*noiseLevel
597 lowThreshold = smoothRef/maxDiff
598 highThreshold = smoothRef*maxDiff
599 for model
in modelImages:
601 highThreshold=highThreshold,
602 lowThreshold=lowThreshold,
603 regularizationWidth=regularizationWidth)
604 smoothModel = ndimage.filters.gaussian_filter(model.array, filterWidth, mode=
'constant')
605 smoothModel += 3.*noiseLevel
606 relativeModel = smoothModel/smoothRef
609 relativeModel2 = ndimage.filters.gaussian_filter(relativeModel, filterWidth/alpha)
610 relativeModel += alpha*(relativeModel - relativeModel2)
611 model.array = relativeModel*referenceImage
614 convergenceMaskPlanes="DETECTED", mask=None, bbox=None):
615 """Helper function to calculate the background noise level of an image.
619 image : `lsst.afw.image.Image`
620 The input image to evaluate the background noise properties.
621 statsCtrl : `lsst.afw.math.StatisticsControl`
622 Statistics control object for coaddition.
624 Number of additional pixels to exclude
625 from the edges of the bounding box.
626 convergenceMaskPlanes : `list` of `str`, or `str`
627 Mask planes to use to calculate convergence.
628 mask : `lsst.afw.image.Mask`, Optional
629 Optional alternate mask
630 bbox : `lsst.afw.geom.Box2I`, optional
631 Sub-region of the masked image to calculate the noise level over.
635 noiseCutoff : `float`
636 The threshold value to treat pixels as noise in an image..
641 mask = self.
maskmask[bbox]
643 bboxShrink.grow(-bufferSize)
644 convergeMask = mask.getPlaneBitMask(convergenceMaskPlanes)
646 backgroundPixels = mask[bboxShrink].array & (statsCtrl.getAndMask() | convergeMask) == 0
647 noiseCutoff = np.std(image[bboxShrink].array[backgroundPixels])
651 """Restrict image values to be between upper and lower limits.
653 This method flags all pixels in an image that are outside of the given
654 threshold values. The threshold values are taken from a reference
655 image, so noisy pixels are likely to get flagged. In order to exclude
656 those noisy pixels, the array of flags is eroded and dilated, which
657 removes isolated pixels outside of the thresholds from the list of
658 pixels to be modified. Pixels that remain flagged after this operation
659 have their values set to the appropriate upper or lower threshold
664 image : `numpy.ndarray`
665 The image to apply the thresholds to.
666 The values will be modified in place.
667 highThreshold : `numpy.ndarray`, optional
668 Array of upper limit values for each pixel of ``image``.
669 lowThreshold : `numpy.ndarray`, optional
670 Array of lower limit values for each pixel of ``image``.
671 regularizationWidth : `int`, optional
672 Minimum radius of a region to include in regularization, in pixels.
677 filterStructure = ndimage.iterate_structure(ndimage.generate_binary_structure(2, 1),
679 if highThreshold
is not None:
680 highPixels = image > highThreshold
681 if regularizationWidth > 0:
683 highPixels = ndimage.morphology.binary_opening(highPixels, structure=filterStructure)
684 image[highPixels] = highThreshold[highPixels]
685 if lowThreshold
is not None:
686 lowPixels = image < lowThreshold
687 if regularizationWidth > 0:
689 lowPixels = ndimage.morphology.binary_opening(lowPixels, structure=filterStructure)
690 image[lowPixels] = lowThreshold[lowPixels]
693 def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
694 doPrefilter=True, order=3):
695 """Shift an image along the X and Y directions.
699 image : `numpy.ndarray`
700 The input image to shift.
702 Shift calculated with ``calculateDcr``.
703 Uses numpy axes ordering (Y, X).
704 If ``splitSubfilters`` is set, each element is itself a `tuple`
705 of two `float`, corresponding to the DCR shift at the two wavelengths.
706 Otherwise, each element is a `float` corresponding to the DCR shift at
707 the effective wavelength of the subfilter.
708 useInverse : `bool`, optional
709 Apply the shift in the opposite direction. Default: False
710 splitSubfilters : `bool`, optional
711 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
712 instead of at the midpoint. Default: False
713 splitThreshold : `float`, optional
714 Minimum DCR difference within a subfilter required to use
716 doPrefilter : `bool`, optional
717 Spline filter the image before shifting, if set. Filtering is required,
718 so only set to False if the image is already filtered.
719 Filtering takes ~20% of the time of shifting, so if `applyDcr` will be
720 called repeatedly on the same image it is more efficient to
721 precalculate the filter.
722 order : `int`, optional
723 The order of the spline interpolation, default is 3.
727 shiftedImage : `numpy.ndarray`
728 A copy of the input image with the specified shift applied.
731 prefilteredImage = ndimage.spline_filter(image, order=order)
733 prefilteredImage = image
735 shiftAmp = np.max(np.abs([_dcr0 - _dcr1
for _dcr0, _dcr1
in zip(dcr[0], dcr[1])]))
736 if shiftAmp >= splitThreshold:
738 shift = [-1.*s
for s
in dcr[0]]
739 shift1 = [-1.*s
for s
in dcr[1]]
743 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
744 shiftedImage += ndimage.shift(prefilteredImage, shift1, prefilter=
False, order=order)
750 dcr = (np.mean(dcr[0]), np.mean(dcr[1]))
752 shift = [-1.*s
for s
in dcr]
755 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
759 def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False):
760 """Calculate the shift in pixels of an exposure due to DCR.
764 visitInfo : `lsst.afw.image.VisitInfo`
765 Metadata for the exposure.
766 wcs : `lsst.afw.geom.SkyWcs`
767 Coordinate system definition (wcs) for the exposure.
768 effectiveWavelength : `float`
769 The effective wavelengths of the current filter, in nanometers.
771 The bandwidth of the current filter, in nanometers.
772 dcrNumSubfilters : `int`
773 Number of sub-filters used to model chromatic effects within a band.
774 splitSubfilters : `bool`, optional
775 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
776 instead of at the midpoint. Default: False
780 dcrShift : `tuple` of two `float`
781 The 2D shift due to DCR, in pixels.
782 Uses numpy axes ordering (Y, X).
786 weight = [0.75, 0.25]
791 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
792 observatory=visitInfo.getObservatory(),
793 weather=visitInfo.getWeather())
795 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
796 observatory=visitInfo.getObservatory(),
797 weather=visitInfo.getWeather())
799 diffRefractPix0 = diffRefractAmp0.asArcseconds()/wcs.getPixelScale().asArcseconds()
800 diffRefractPix1 = diffRefractAmp1.asArcseconds()/wcs.getPixelScale().asArcseconds()
801 diffRefractArr = [diffRefractPix0*weight[0] + diffRefractPix1*weight[1],
802 diffRefractPix0*weight[1] + diffRefractPix1*weight[0]]
803 shiftX = [diffRefractPix*np.sin(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
804 shiftY = [diffRefractPix*np.cos(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
805 dcrShift.append(((shiftY[0], shiftX[0]), (shiftY[1], shiftX[1])))
807 diffRefractAmp = (diffRefractAmp0 + diffRefractAmp1)/2.
808 diffRefractPix = diffRefractAmp.asArcseconds()/wcs.getPixelScale().asArcseconds()
809 shiftX = diffRefractPix*np.sin(rotation.asRadians())
810 shiftY = diffRefractPix*np.cos(rotation.asRadians())
811 dcrShift.append((shiftY, shiftX))
816 """Calculate the total sky rotation angle of an exposure.
820 visitInfo : `lsst.afw.image.VisitInfo`
821 Metadata for the exposure.
822 wcs : `lsst.afw.geom.SkyWcs`
823 Coordinate system definition (wcs) for the exposure.
828 The rotation of the image axis, East from North.
829 Equal to the parallactic angle plus any additional rotation of the
831 A rotation angle of 0 degrees is defined with
832 North along the +y axis and East along the +x axis.
833 A rotation angle of 90 degrees is defined with
834 North along the +x axis and East along the -y axis.
836 parAngle = visitInfo.getBoresightParAngle().asRadians()
837 cd = wcs.getCdMatrix()
839 cdAngle = (np.arctan2(-cd[0, 1], cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
840 rotAngle = (cdAngle + parAngle)*geom.radians
842 cdAngle = (np.arctan2(cd[0, 1], -cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
843 rotAngle = (cdAngle - parAngle)*geom.radians
848 """Iterate over the wavelength endpoints of subfilters.
852 effectiveWavelength : `float`
853 The effective wavelength of the current filter, in nanometers.
855 The bandwidth of the current filter, in nanometers.
856 dcrNumSubfilters : `int`
857 Number of sub-filters used to model chromatic effects within a band.
861 `tuple` of two `float`
862 The next set of wavelength endpoints for a subfilter, in nanometers.
864 lambdaMin = effectiveWavelength - bandwidth/2
865 lambdaMax = effectiveWavelength + bandwidth/2
866 wlStep = bandwidth/dcrNumSubfilters
867 for wl
in np.linspace(lambdaMin, lambdaMax, dcrNumSubfilters, endpoint=
False):
868 yield (wl, wl + wlStep)
An integer coordinate rectangle.
def calculateNoiseCutoff(self, image, statsCtrl, bufferSize, convergenceMaskPlanes="DETECTED", mask=None, bbox=None)
def buildMatchedTemplate(self, exposure=None, order=3, visitInfo=None, bbox=None, wcs=None, mask=None, splitSubfilters=True, splitThreshold=0., amplifyModel=1.)
def applyImageThresholds(self, image, highThreshold=None, lowThreshold=None, regularizationWidth=2)
def buildMatchedExposure(self, exposure=None, visitInfo=None, bbox=None, wcs=None, mask=None)
def getReferenceImage(self, bbox=None)
def conditionDcrModel(self, modelImages, bbox, gain=1.)
def regularizeModelIter(self, subfilter, newModel, bbox, regularizationFactor, regularizationWidth=2)
def fromDataRef(cls, dataRef, effectiveWavelength, bandwidth, datasetType="dcrCoadd", numSubfilters=None, **kwargs)
def assign(self, dcrSubModel, bbox=None)
def regularizeModelFreq(self, modelImages, bbox, statsCtrl, regularizationFactor, regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED")
def __setitem__(self, subfilter, maskedImage)
def __getitem__(self, subfilter)
def fromQuantum(cls, availableCoaddRefs, effectiveWavelength, bandwidth)
def fromImage(cls, maskedImage, dcrNumSubfilters, effectiveWavelength, bandwidth, filterLabel=None, psf=None, photoCalib=None)
def __init__(self, modelImages, effectiveWavelength, bandwidth, filterLabel=None, psf=None, mask=None, variance=None, photoCalib=None)
def effectiveWavelength(self)
def differentialRefraction(wavelength, wavelengthRef, elevation, observatory, weather=None)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0., doPrefilter=True, order=3)
def wavelengthGenerator(effectiveWavelength, bandwidth, dcrNumSubfilters)
def calculateImageParallacticAngle(visitInfo, wcs)
def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False)