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` of
175 `int` : `lsst.daf.butler.DeferredDatasetHandle`
176 Dictionary of spatially relevant retrieved coadd patches,
177 indexed by their sequential patch number.
178 effectiveWavelength : `float`
179 The effective wavelengths of the current filter, in nanometers.
181 The bandwidth of the current filter, in nanometers.
185 dcrModel : `lsst.pipe.tasks.DcrModel`
186 Best fit model of the true sky after correcting chromatic effects.
193 modelImages = [
None]*len(availableCoaddRefs)
195 for coaddRef
in availableCoaddRefs:
196 subfilter = coaddRef.dataId[
"subfilter"]
197 dcrCoadd = coaddRef.get()
198 if filterLabel
is None:
199 filterLabel = dcrCoadd.getFilterLabel()
201 psf = dcrCoadd.getPsf()
205 variance = dcrCoadd.variance
206 if photoCalib
is None:
207 photoCalib = dcrCoadd.getPhotoCalib()
208 modelImages[subfilter] = dcrCoadd.image
209 return cls(modelImages, effectiveWavelength, bandwidth, filterLabel, psf, mask, variance, photoCalib)
212 """Return the number of subfilters.
216 dcrNumSubfilters : `int`
217 The number of DCR subfilters in the model.
222 """Iterate over the subfilters of the DCR model.
227 Index of the current ``subfilter`` within the full band.
228 Negative indices are allowed, and count in reverse order
229 from the highest ``subfilter``.
233 modelImage : `lsst.afw.image.Image`
234 The DCR model for the given ``subfilter``.
239 If the requested ``subfilter`` is greater or equal to the number
240 of subfilters in the model.
242 if np.abs(subfilter) >= len(self):
243 raise IndexError(
"subfilter out of bounds.")
247 """Update the model image for one subfilter.
252 Index of the current subfilter within the full band.
253 maskedImage : `lsst.afw.image.Image`
254 The DCR model to set for the given ``subfilter``.
259 If the requested ``subfilter`` is greater or equal to the number
260 of subfilters in the model.
262 If the bounding box of the new image does not match.
264 if np.abs(subfilter) >= len(self):
265 raise IndexError(
"subfilter out of bounds.")
266 if maskedImage.getBBox() != self.
bboxbbox:
267 raise ValueError(
"The bounding box of a subfilter must not change.")
268 self.
modelImagesmodelImages[subfilter] = maskedImage
272 """Return the effective wavelength of the model.
276 effectiveWavelength : `float`
277 The effective wavelength of the current filter, in nanometers.
283 """Return the filter label for the model.
287 filterLabel : `lsst.afw.image.FilterLabel`
288 The filter used for the input observations.
294 """Return the bandwidth of the model.
299 The bandwidth of the current filter, in nanometers.
305 """Return the psf of the model.
309 psf : `lsst.afw.detection.Psf`
310 Point spread function (PSF) of the model.
316 """Return the common bounding box of each subfilter image.
320 bbox : `lsst.afw.geom.Box2I`
321 Bounding box of the DCR model.
323 return self[0].getBBox()
327 """Return the common mask of each subfilter image.
331 mask : `lsst.afw.image.Mask`
332 Mask plane of the DCR model.
334 return self.
_mask_mask
338 """Return the common variance of each subfilter image.
342 variance : `lsst.afw.image.Image`
343 Variance plane of the DCR model.
348 """Calculate a reference image from the average of the subfilter
353 bbox : `lsst.afw.geom.Box2I`, optional
354 Sub-region of the coadd. Returns the entire image if `None`.
358 refImage : `numpy.ndarray`
359 The reference image with no chromatic effects applied.
361 bbox = bbox
or self.
bboxbbox
362 return np.mean([model[bbox].array
for model
in self], axis=0)
364 def assign(self, dcrSubModel, bbox=None):
365 """Update a sub-region of the ``DcrModel`` with new values.
369 dcrSubModel : `lsst.pipe.tasks.DcrModel`
370 New model of the true scene after correcting chromatic effects.
371 bbox : `lsst.afw.geom.Box2I`, optional
372 Sub-region of the coadd.
373 Defaults to the bounding box of ``dcrSubModel``.
378 If the new model has a different number of subfilters.
380 if len(dcrSubModel) != len(self):
381 raise ValueError(
"The number of DCR subfilters must be the same "
382 "between the old and new models.")
383 bbox = bbox
or self.
bboxbbox
384 for model, subModel
in zip(self, dcrSubModel):
385 model.assign(subModel[bbox], bbox)
388 visitInfo=None, bbox=None, wcs=None, mask=None,
389 splitSubfilters=True, splitThreshold=0., amplifyModel=1.):
390 """Create a DCR-matched template image for an exposure.
394 exposure : `lsst.afw.image.Exposure`, optional
395 The input exposure to build a matched template for.
396 May be omitted if all of the metadata is supplied separately
397 order : `int`, optional
398 Interpolation order of the DCR shift.
399 visitInfo : `lsst.afw.image.VisitInfo`, optional
400 Metadata for the exposure. Ignored if ``exposure`` is set.
401 bbox : `lsst.afw.geom.Box2I`, optional
402 Sub-region of the coadd. Ignored if ``exposure`` is set.
403 wcs : `lsst.afw.geom.SkyWcs`, optional
404 Coordinate system definition (wcs) for the exposure.
405 Ignored if ``exposure`` is set.
406 mask : `lsst.afw.image.Mask`, optional
407 reference mask to use for the template image.
408 splitSubfilters : `bool`, optional
409 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
410 instead of at the midpoint. Default: True
411 splitThreshold : `float`, optional
412 Minimum DCR difference within a subfilter required to use
414 amplifyModel : `float`, optional
415 Multiplication factor to amplify differences between model planes.
416 Used to speed convergence of iterative forward modeling.
420 templateImage : `lsst.afw.image.ImageF`
421 The DCR-matched template
426 If neither ``exposure`` or all of ``visitInfo``, ``bbox``, and
430 raise ValueError(
"'effectiveWavelength' and 'bandwidth' must be set for the DcrModel in order "
432 if exposure
is not None:
433 visitInfo = exposure.getInfo().getVisitInfo()
434 bbox = exposure.getBBox()
435 wcs = exposure.getInfo().getWcs()
436 elif visitInfo
is None or bbox
is None or wcs
is None:
437 raise ValueError(
"Either exposure or visitInfo, bbox, and wcs must be set.")
439 splitSubfilters=splitSubfilters)
440 templateImage = afwImage.ImageF(bbox)
442 for subfilter, dcr
in enumerate(dcrShift):
444 model = (self[subfilter][bbox].array - refModel)*amplifyModel + refModel
446 model = self[subfilter][bbox].array
447 templateImage.array +=
applyDcr(model, dcr, splitSubfilters=splitSubfilters,
448 splitThreshold=splitThreshold, order=order)
452 visitInfo=None, bbox=None, wcs=None, mask=None):
453 """Wrapper to create an exposure from a template image.
457 exposure : `lsst.afw.image.Exposure`, optional
458 The input exposure to build a matched template for.
459 May be omitted if all of the metadata is supplied separately
460 visitInfo : `lsst.afw.image.VisitInfo`, optional
461 Metadata for the exposure. Ignored if ``exposure`` is set.
462 bbox : `lsst.afw.geom.Box2I`, optional
463 Sub-region of the coadd. Ignored if ``exposure`` is set.
464 wcs : `lsst.afw.geom.SkyWcs`, optional
465 Coordinate system definition (wcs) for the exposure.
466 Ignored if ``exposure`` is set.
467 mask : `lsst.afw.image.Mask`, optional
468 reference mask to use for the template image.
472 templateExposure : `lsst.afw.image.exposureF`
473 The DCR-matched template
478 If no `photcCalib` is set.
481 bbox = exposure.getBBox()
482 templateImage = self.
buildMatchedTemplatebuildMatchedTemplate(exposure=exposure, visitInfo=visitInfo,
483 bbox=bbox, wcs=wcs, mask=mask)
484 maskedImage = afwImage.MaskedImageF(bbox)
485 maskedImage.image = templateImage[bbox]
486 maskedImage.mask = self.
maskmask[bbox]
487 maskedImage.variance = self.
variancevariance[bbox]
491 templateExposure = afwImage.ExposureF(bbox, wcs)
492 templateExposure.setMaskedImage(maskedImage[bbox])
493 templateExposure.setPsf(self.
psfpsf)
494 templateExposure.setFilterLabel(self.filterLabel)
496 raise RuntimeError(
"No PhotoCalib set for the DcrModel. "
497 "If the DcrModel was created from a masked image"
498 " you must also specify the photoCalib.")
499 templateExposure.setPhotoCalib(self.
photoCalibphotoCalib)
500 return templateExposure
503 """Average two iterations' solutions to reduce oscillations.
507 modelImages : `list` of `lsst.afw.image.Image`
508 The new DCR model images from the current iteration.
509 The values will be modified in place.
510 bbox : `lsst.afw.geom.Box2I`
511 Sub-region of the coadd
512 gain : `float`, optional
513 Relative weight to give the new solution when updating the model.
514 Defaults to 1.0, which gives equal weight to both solutions.
517 for model, newModel
in zip(self, modelImages):
519 newModel += model[bbox]
520 newModel /= 1. + gain
523 regularizationWidth=2):
524 """Restrict large variations in the model between iterations.
529 Index of the current subfilter within the full band.
530 newModel : `lsst.afw.image.Image`
531 The new DCR model for one subfilter from the current iteration.
532 Values in ``newModel`` that are extreme compared with the last
533 iteration are modified in place.
534 bbox : `lsst.afw.geom.Box2I`
536 regularizationFactor : `float`
537 Maximum relative change of the model allowed between iterations.
538 regularizationWidth : int, optional
539 Minimum radius of a region to include in regularization, in pixels.
541 refImage = self[subfilter][bbox].array
542 highThreshold = np.abs(refImage)*regularizationFactor
543 lowThreshold = refImage/regularizationFactor
544 newImage = newModel.array
545 self.
applyImageThresholdsapplyImageThresholds(newImage, highThreshold=highThreshold, lowThreshold=lowThreshold,
546 regularizationWidth=regularizationWidth)
549 regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED"):
550 """Restrict large variations in the model between subfilters.
554 modelImages : `list` of `lsst.afw.image.Image`
555 The new DCR model images from the current iteration.
556 The values will be modified in place.
557 bbox : `lsst.afw.geom.Box2I`
559 statsCtrl : `lsst.afw.math.StatisticsControl`
560 Statistics control object for coaddition.
561 regularizationFactor : `float`
562 Maximum relative change of the model allowed between subfilters.
563 regularizationWidth : `int`, optional
564 Minimum radius of a region to include in regularization, in pixels.
565 mask : `lsst.afw.image.Mask`, optional
566 Optional alternate mask
567 convergenceMaskPlanes : `list` of `str`, or `str`, optional
568 Mask planes to use to calculate convergence.
572 This implementation of frequency regularization restricts each
573 subfilter image to be a smoothly-varying function times a reference
579 maxDiff = np.sqrt(regularizationFactor)
580 noiseLevel = self.
calculateNoiseCutoffcalculateNoiseCutoff(modelImages[0], statsCtrl, bufferSize=5, mask=mask, bbox=bbox)
582 badPixels = np.isnan(referenceImage) | (referenceImage <= 0.)
583 if np.sum(~badPixels) == 0:
586 referenceImage[badPixels] = 0.
587 filterWidth = regularizationWidth
588 fwhm = 2.*filterWidth
592 smoothRef = ndimage.filters.gaussian_filter(referenceImage, filterWidth, mode=
'constant')
596 smoothRef += 3.*noiseLevel
598 lowThreshold = smoothRef/maxDiff
599 highThreshold = smoothRef*maxDiff
600 for model
in modelImages:
602 highThreshold=highThreshold,
603 lowThreshold=lowThreshold,
604 regularizationWidth=regularizationWidth)
605 smoothModel = ndimage.filters.gaussian_filter(model.array, filterWidth, mode=
'constant')
606 smoothModel += 3.*noiseLevel
607 relativeModel = smoothModel/smoothRef
610 relativeModel2 = ndimage.filters.gaussian_filter(relativeModel, filterWidth/alpha)
611 relativeModel += alpha*(relativeModel - relativeModel2)
612 model.array = relativeModel*referenceImage
615 convergenceMaskPlanes="DETECTED", mask=None, bbox=None):
616 """Helper function to calculate the background noise level of an image.
620 image : `lsst.afw.image.Image`
621 The input image to evaluate the background noise properties.
622 statsCtrl : `lsst.afw.math.StatisticsControl`
623 Statistics control object for coaddition.
625 Number of additional pixels to exclude
626 from the edges of the bounding box.
627 convergenceMaskPlanes : `list` of `str`, or `str`
628 Mask planes to use to calculate convergence.
629 mask : `lsst.afw.image.Mask`, Optional
630 Optional alternate mask
631 bbox : `lsst.afw.geom.Box2I`, optional
632 Sub-region of the masked image to calculate the noise level over.
636 noiseCutoff : `float`
637 The threshold value to treat pixels as noise in an image..
642 mask = self.
maskmask[bbox]
644 bboxShrink.grow(-bufferSize)
645 convergeMask = mask.getPlaneBitMask(convergenceMaskPlanes)
647 backgroundPixels = mask[bboxShrink].array & (statsCtrl.getAndMask() | convergeMask) == 0
648 noiseCutoff = np.std(image[bboxShrink].array[backgroundPixels])
652 """Restrict image values to be between upper and lower limits.
654 This method flags all pixels in an image that are outside of the given
655 threshold values. The threshold values are taken from a reference
656 image, so noisy pixels are likely to get flagged. In order to exclude
657 those noisy pixels, the array of flags is eroded and dilated, which
658 removes isolated pixels outside of the thresholds from the list of
659 pixels to be modified. Pixels that remain flagged after this operation
660 have their values set to the appropriate upper or lower threshold
665 image : `numpy.ndarray`
666 The image to apply the thresholds to.
667 The values will be modified in place.
668 highThreshold : `numpy.ndarray`, optional
669 Array of upper limit values for each pixel of ``image``.
670 lowThreshold : `numpy.ndarray`, optional
671 Array of lower limit values for each pixel of ``image``.
672 regularizationWidth : `int`, optional
673 Minimum radius of a region to include in regularization, in pixels.
678 filterStructure = ndimage.iterate_structure(ndimage.generate_binary_structure(2, 1),
680 if highThreshold
is not None:
681 highPixels = image > highThreshold
682 if regularizationWidth > 0:
684 highPixels = ndimage.morphology.binary_opening(highPixels, structure=filterStructure)
685 image[highPixels] = highThreshold[highPixels]
686 if lowThreshold
is not None:
687 lowPixels = image < lowThreshold
688 if regularizationWidth > 0:
690 lowPixels = ndimage.morphology.binary_opening(lowPixels, structure=filterStructure)
691 image[lowPixels] = lowThreshold[lowPixels]
694 def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
695 doPrefilter=True, order=3):
696 """Shift an image along the X and Y directions.
700 image : `numpy.ndarray`
701 The input image to shift.
703 Shift calculated with ``calculateDcr``.
704 Uses numpy axes ordering (Y, X).
705 If ``splitSubfilters`` is set, each element is itself a `tuple`
706 of two `float`, corresponding to the DCR shift at the two wavelengths.
707 Otherwise, each element is a `float` corresponding to the DCR shift at
708 the effective wavelength of the subfilter.
709 useInverse : `bool`, optional
710 Apply the shift in the opposite direction. Default: False
711 splitSubfilters : `bool`, optional
712 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
713 instead of at the midpoint. Default: False
714 splitThreshold : `float`, optional
715 Minimum DCR difference within a subfilter required to use
717 doPrefilter : `bool`, optional
718 Spline filter the image before shifting, if set. Filtering is required,
719 so only set to False if the image is already filtered.
720 Filtering takes ~20% of the time of shifting, so if `applyDcr` will be
721 called repeatedly on the same image it is more efficient to
722 precalculate the filter.
723 order : `int`, optional
724 The order of the spline interpolation, default is 3.
728 shiftedImage : `numpy.ndarray`
729 A copy of the input image with the specified shift applied.
732 prefilteredImage = ndimage.spline_filter(image, order=order)
734 prefilteredImage = image
736 shiftAmp = np.max(np.abs([_dcr0 - _dcr1
for _dcr0, _dcr1
in zip(dcr[0], dcr[1])]))
737 if shiftAmp >= splitThreshold:
739 shift = [-1.*s
for s
in dcr[0]]
740 shift1 = [-1.*s
for s
in dcr[1]]
744 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
745 shiftedImage += ndimage.shift(prefilteredImage, shift1, prefilter=
False, order=order)
751 dcr = (np.mean(dcr[0]), np.mean(dcr[1]))
753 shift = [-1.*s
for s
in dcr]
756 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
760 def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False):
761 """Calculate the shift in pixels of an exposure due to DCR.
765 visitInfo : `lsst.afw.image.VisitInfo`
766 Metadata for the exposure.
767 wcs : `lsst.afw.geom.SkyWcs`
768 Coordinate system definition (wcs) for the exposure.
769 effectiveWavelength : `float`
770 The effective wavelengths of the current filter, in nanometers.
772 The bandwidth of the current filter, in nanometers.
773 dcrNumSubfilters : `int`
774 Number of sub-filters used to model chromatic effects within a band.
775 splitSubfilters : `bool`, optional
776 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
777 instead of at the midpoint. Default: False
781 dcrShift : `tuple` of two `float`
782 The 2D shift due to DCR, in pixels.
783 Uses numpy axes ordering (Y, X).
787 weight = [0.75, 0.25]
792 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
793 observatory=visitInfo.getObservatory(),
794 weather=visitInfo.getWeather())
796 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
797 observatory=visitInfo.getObservatory(),
798 weather=visitInfo.getWeather())
800 diffRefractPix0 = diffRefractAmp0.asArcseconds()/wcs.getPixelScale().asArcseconds()
801 diffRefractPix1 = diffRefractAmp1.asArcseconds()/wcs.getPixelScale().asArcseconds()
802 diffRefractArr = [diffRefractPix0*weight[0] + diffRefractPix1*weight[1],
803 diffRefractPix0*weight[1] + diffRefractPix1*weight[0]]
804 shiftX = [diffRefractPix*np.sin(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
805 shiftY = [diffRefractPix*np.cos(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
806 dcrShift.append(((shiftY[0], shiftX[0]), (shiftY[1], shiftX[1])))
808 diffRefractAmp = (diffRefractAmp0 + diffRefractAmp1)/2.
809 diffRefractPix = diffRefractAmp.asArcseconds()/wcs.getPixelScale().asArcseconds()
810 shiftX = diffRefractPix*np.sin(rotation.asRadians())
811 shiftY = diffRefractPix*np.cos(rotation.asRadians())
812 dcrShift.append((shiftY, shiftX))
817 """Calculate the total sky rotation angle of an exposure.
821 visitInfo : `lsst.afw.image.VisitInfo`
822 Metadata for the exposure.
823 wcs : `lsst.afw.geom.SkyWcs`
824 Coordinate system definition (wcs) for the exposure.
829 The rotation of the image axis, East from North.
830 Equal to the parallactic angle plus any additional rotation of the
832 A rotation angle of 0 degrees is defined with
833 North along the +y axis and East along the +x axis.
834 A rotation angle of 90 degrees is defined with
835 North along the +x axis and East along the -y axis.
837 parAngle = visitInfo.getBoresightParAngle().asRadians()
838 cd = wcs.getCdMatrix()
840 cdAngle = (np.arctan2(-cd[0, 1], cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
841 rotAngle = (cdAngle + parAngle)*geom.radians
843 cdAngle = (np.arctan2(cd[0, 1], -cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
844 rotAngle = (cdAngle - parAngle)*geom.radians
849 """Iterate over the wavelength endpoints of subfilters.
853 effectiveWavelength : `float`
854 The effective wavelength of the current filter, in nanometers.
856 The bandwidth of the current filter, in nanometers.
857 dcrNumSubfilters : `int`
858 Number of sub-filters used to model chromatic effects within a band.
862 `tuple` of two `float`
863 The next set of wavelength endpoints for a subfilter, in nanometers.
865 lambdaMin = effectiveWavelength - bandwidth/2
866 lambdaMax = effectiveWavelength + bandwidth/2
867 wlStep = bandwidth/dcrNumSubfilters
868 for wl
in np.linspace(lambdaMin, lambdaMax, dcrNumSubfilters, endpoint=
False):
869 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)