24from scipy
import ndimage
26import lsst.afw.image
as afwImage
30__all__ = [
"DcrModel",
"applyDcr",
"calculateDcr",
"calculateImageParallacticAngle"]
34 """A model of the true sky after correcting chromatic effects.
38 dcrNumSubfilters : `int`
39 Number of sub-filters used to model chromatic effects within a band.
40 modelImages : `list` of `lsst.afw.image.Image`
41 A list of masked images, each containing the model for one subfilter
45 The ``DcrModel`` contains an estimate of the true sky, at a higher
46 wavelength resolution than the input observations. It can be forward-
47 modeled to produce Differential Chromatic Refraction (DCR) matched
48 templates for a given ``Exposure``, and provides utilities for conditioning
49 the model in ``dcrAssembleCoadd`` to avoid oscillating solutions between
50 iterations of forward modeling or between the subfilters of the model.
53 def __init__(self, modelImages, effectiveWavelength, bandwidth, filterLabel=None, psf=None,
54 bbox=None, wcs=None, mask=None, variance=None, photoCalib=None):
68 def fromImage(cls, maskedImage, dcrNumSubfilters, effectiveWavelength, bandwidth,
69 wcs=None, filterLabel=None, psf=None, photoCalib=None):
70 """Initialize a DcrModel by dividing a coadd between the subfilters.
74 maskedImage : `lsst.afw.image.MaskedImage`
75 Input coadded image to divide equally between the subfilters.
76 dcrNumSubfilters : `int`
77 Number of sub-filters used to model chromatic effects within a
79 effectiveWavelength : `float`
80 The effective wavelengths of the current filter, in nanometers.
82 The bandwidth of the current filter, in nanometers.
83 wcs : `lsst.afw.geom.SkyWcs`
84 Coordinate system definition (wcs) for the exposure.
85 filterLabel : `lsst.afw.image.FilterLabel`, optional
86 The filter label, set in the current instruments' obs package.
87 Required for any calculation of DCR, including making matched
89 psf : `lsst.afw.detection.Psf`, optional
90 Point spread function (PSF) of the model.
91 Required if the ``DcrModel`` will be persisted.
92 photoCalib : `lsst.afw.image.PhotoCalib`, optional
93 Calibration to convert instrumental flux and
94 flux error to nanoJansky.
98 dcrModel : `lsst.pipe.tasks.DcrModel`
99 Best fit model of the true sky after correcting chromatic effects.
103 model = maskedImage.image.clone()
104 mask = maskedImage.mask.clone()
105 bbox = maskedImage.getBBox()
111 variance = maskedImage.variance.clone()
112 variance /= dcrNumSubfilters
113 model /= dcrNumSubfilters
114 modelImages = [model, ]
115 for subfilter
in range(1, dcrNumSubfilters):
116 modelImages.append(model.clone())
117 return cls(modelImages, effectiveWavelength, bandwidth,
118 filterLabel=filterLabel, psf=psf, bbox=bbox, wcs=wcs,
119 mask=mask, variance=variance, photoCalib=photoCalib)
122 def fromQuantum(cls, availableCoaddRefs, effectiveWavelength, bandwidth, numSubfilters):
123 """Load an existing DcrModel from a Gen 3 repository.
127 availableCoaddRefs : `dict` [`int`, `lsst.daf.butler.DeferredDatasetHandle`]
128 Dictionary of spatially relevant retrieved coadd patches,
129 indexed by their sequential patch number.
130 effectiveWavelength : `float`
131 The effective wavelengths of the current filter, in nanometers.
133 The bandwidth of the current filter, in nanometers.
134 numSubfilters : `int`
135 Number of subfilters in the DcrCoadd.
139 dcrModel : `lsst.pipe.tasks.DcrModel`
140 Best fit model of the true sky after correcting chromatic effects.
149 modelImages = [
None]*numSubfilters
151 for coaddRef
in availableCoaddRefs:
152 subfilter = coaddRef.dataId[
"subfilter"]
153 dcrCoadd = coaddRef.get()
154 if filterLabel
is None:
155 filterLabel = dcrCoadd.getFilter()
157 psf = dcrCoadd.getPsf()
159 bbox = dcrCoadd.getBBox()
165 variance = dcrCoadd.variance
166 if photoCalib
is None:
167 photoCalib = dcrCoadd.getPhotoCalib()
168 modelImages[subfilter] = dcrCoadd.image
169 return cls(modelImages, effectiveWavelength, bandwidth, filterLabel,
170 psf, bbox, wcs, mask, variance, photoCalib)
173 """Return the number of subfilters.
177 dcrNumSubfilters : `int`
178 The number of DCR subfilters in the model.
183 """Iterate over the subfilters of the DCR model.
188 Index of the current ``subfilter`` within the full band.
189 Negative indices are allowed, and count in reverse order
190 from the highest ``subfilter``.
194 modelImage : `lsst.afw.image.Image`
195 The DCR model for the given ``subfilter``.
200 If the requested ``subfilter`` is greater or equal to the number
201 of subfilters in the model.
203 if np.abs(subfilter) >= len(self):
204 raise IndexError(
"subfilter out of bounds.")
208 """Update the model image for one subfilter.
213 Index of the current subfilter within the full band.
214 maskedImage : `lsst.afw.image.Image`
215 The DCR model to set for the given ``subfilter``.
220 If the requested ``subfilter`` is greater or equal to the number
221 of subfilters in the model.
223 If the bounding box of the new image does not match.
225 if np.abs(subfilter) >= len(self):
226 raise IndexError(
"subfilter out of bounds.")
227 if maskedImage.getBBox() != self.
bbox:
228 raise ValueError(
"The bounding box of a subfilter must not change.")
233 """Return the effective wavelength of the model.
237 effectiveWavelength : `float`
238 The effective wavelength of the current filter, in nanometers.
244 """Return the filter label for the model.
248 filterLabel : `lsst.afw.image.FilterLabel`
249 The filter used for the input observations.
255 """Return the bandwidth of the model.
260 The bandwidth of the current filter, in nanometers.
266 """Return the psf of the model.
270 psf : `lsst.afw.detection.Psf`
271 Point spread function (PSF) of the model.
277 """Return the common bounding box of each subfilter image.
281 bbox : `lsst.afw.geom.Box2I`
282 Bounding box of the DCR model.
288 """Return the WCS of each subfilter image.
292 wcs : `lsst.afw.geom.SkyWcs`
293 Coordinate system definition (wcs) for the exposure.
299 """Return the common mask of each subfilter image.
303 mask : `lsst.afw.image.Mask`
304 Mask plane of the DCR model.
310 """Return the common variance of each subfilter image.
314 variance : `lsst.afw.image.Image`
315 Variance plane of the DCR model.
320 """Calculate a reference image from the average of the subfilter
325 bbox : `lsst.afw.geom.Box2I`, optional
326 Sub-region of the coadd. Returns the entire image if `None`.
330 refImage : `numpy.ndarray`
331 The reference image with no chromatic effects applied.
333 bbox = bbox
or self.
bbox
334 return np.mean([model[bbox].array
for model
in self], axis=0)
336 def assign(self, dcrSubModel, bbox=None):
337 """Update a sub-region of the ``DcrModel`` with new values.
341 dcrSubModel : `lsst.pipe.tasks.DcrModel`
342 New model of the true scene after correcting chromatic effects.
343 bbox : `lsst.afw.geom.Box2I`, optional
344 Sub-region of the coadd.
345 Defaults to the bounding box of ``dcrSubModel``.
350 If the new model has a different number of subfilters.
352 if len(dcrSubModel) != len(self):
353 raise ValueError(
"The number of DCR subfilters must be the same "
354 "between the old and new models.")
355 bbox = bbox
or self.
bbox
356 for model, subModel
in zip(self, dcrSubModel):
357 model.assign(subModel[bbox], bbox)
360 visitInfo=None, bbox=None, mask=None,
361 splitSubfilters=True, splitThreshold=0., amplifyModel=1.):
362 """Create a DCR-matched template image for an exposure.
366 exposure : `lsst.afw.image.Exposure`, optional
367 The input exposure to build a matched template for.
368 May be omitted if all of the metadata is supplied separately
369 order : `int`, optional
370 Interpolation order of the DCR shift.
371 visitInfo : `lsst.afw.image.VisitInfo`, optional
372 Metadata for the exposure. Ignored if ``exposure`` is set.
373 bbox : `lsst.afw.geom.Box2I`, optional
374 Sub-region of the coadd, or use the entire coadd if not supplied.
375 mask : `lsst.afw.image.Mask`, optional
376 reference mask to use for the template image.
377 splitSubfilters : `bool`, optional
378 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
379 instead of at the midpoint. Default: True
380 splitThreshold : `float`, optional
381 Minimum DCR difference within a subfilter required to use
383 amplifyModel : `float`, optional
384 Multiplication factor to amplify differences between model planes.
385 Used to speed convergence of iterative forward modeling.
389 templateImage : `lsst.afw.image.ImageF`
390 The DCR-matched template
395 If neither ``exposure`` or ``visitInfo`` are set.
398 raise ValueError(
"'effectiveWavelength' and 'bandwidth' must be set for the DcrModel in order "
400 if exposure
is not None:
401 visitInfo = exposure.getInfo().getVisitInfo()
402 elif visitInfo
is None:
403 raise ValueError(
"Either exposure or visitInfo must be set.")
407 bbox = bbox.clippedTo(self.
bbox)
409 splitSubfilters=splitSubfilters, bbox=bbox)
410 templateImage = afwImage.ImageF(bbox)
412 for subfilter, dcr
in enumerate(dcrShift):
413 if self[subfilter]
is None:
415 self.log.debug(
"Skipping missing DCR model subfilter %d", subfilter)
422 model = (self[subfilter][bbox].array - refModel)*amplifyModel + refModel
424 model = self[subfilter][bbox].array
425 templateImage.array +=
applyDcr(model, dcr, splitSubfilters=splitSubfilters,
426 splitThreshold=splitThreshold, order=order)
430 visitInfo=None, bbox=None, mask=None):
431 """Wrapper to create an exposure from a template image.
435 exposure : `lsst.afw.image.Exposure`, optional
436 The input exposure to build a matched template for.
437 May be omitted if all of the metadata is supplied separately
438 visitInfo : `lsst.afw.image.VisitInfo`, optional
439 Metadata for the exposure. Ignored if ``exposure`` is set.
440 bbox : `lsst.afw.geom.Box2I`, optional
441 Sub-region of the coadd, or use the entire coadd if not supplied.
442 mask : `lsst.afw.image.Mask`, optional
443 reference mask to use for the template image.
447 templateExposure : `lsst.afw.image.exposureF`
448 The DCR-matched template
453 If no `photcCalib` is set.
458 bbox=bbox, mask=mask)
459 maskedImage = afwImage.MaskedImageF(bbox)
460 maskedImage.image = templateImage[bbox]
461 maskedImage.mask = self.
mask[bbox]
462 maskedImage.variance = self.
variance[bbox]
466 templateExposure = afwImage.ExposureF(bbox, self.
wcs)
467 templateExposure.setMaskedImage(maskedImage[bbox])
468 templateExposure.setPsf(self.
psf)
471 raise RuntimeError(
"No PhotoCalib set for the DcrModel. "
472 "If the DcrModel was created from a masked image"
473 " you must also specify the photoCalib.")
474 templateExposure.setPhotoCalib(self.
photoCalib)
475 return templateExposure
478 """Create in-memory butler dataset reference containing the DCR-matched
483 exposure : `lsst.afw.image.Exposure`, optional
484 The input exposure to build a matched template for.
485 May be omitted if all of the metadata is supplied separately
486 visitInfo : `lsst.afw.image.VisitInfo`, optional
487 Metadata for the exposure. Ignored if ``exposure`` is set.
488 bbox : `lsst.afw.geom.Box2I`, optional
489 Sub-region of the coadd, or use the entire coadd if not supplied.
490 mask : `lsst.afw.image.Mask`, optional
491 reference mask to use for the template image.
495 templateExposureHandle: `lsst.pipe.base.InMemoryDatasetHandle`
496 In-memory butler dataset reference containing the DCR-matched
502 If no `exposure` or `visitInfo` is set.
504 if exposure
is not None:
505 visitInfo = exposure.visitInfo
506 elif visitInfo
is None:
507 raise ValueError(
"Either exposure or visitInfo must be set.")
509 exposure=exposure, visitInfo=visitInfo, bbox=bbox, mask=mask
511 templateExposureHandle = pipeBase.InMemoryDatasetHandle(
513 storageClass=
"ExposureF",
517 return templateExposureHandle
520 """Average two iterations' solutions to reduce oscillations.
524 modelImages : `list` of `lsst.afw.image.Image`
525 The new DCR model images from the current iteration.
526 The values will be modified in place.
527 bbox : `lsst.afw.geom.Box2I`
528 Sub-region of the coadd
529 gain : `float`, optional
530 Relative weight to give the new solution when updating the model.
531 Defaults to 1.0, which gives equal weight to both solutions.
534 for model, newModel
in zip(self, modelImages):
536 newModel += model[bbox]
537 newModel /= 1. + gain
540 regularizationWidth=2):
541 """Restrict large variations in the model between iterations.
546 Index of the current subfilter within the full band.
547 newModel : `lsst.afw.image.Image`
548 The new DCR model for one subfilter from the current iteration.
549 Values in ``newModel`` that are extreme compared with the last
550 iteration are modified in place.
551 bbox : `lsst.afw.geom.Box2I`
553 regularizationFactor : `float`
554 Maximum relative change of the model allowed between iterations.
555 regularizationWidth : int, optional
556 Minimum radius of a region to include in regularization, in pixels.
558 refImage = self[subfilter][bbox].array
559 highThreshold = np.abs(refImage)*regularizationFactor
560 lowThreshold = refImage/regularizationFactor
561 newImage = newModel.array
563 regularizationWidth=regularizationWidth)
566 regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED"):
567 """Restrict large variations in the model between subfilters.
571 modelImages : `list` of `lsst.afw.image.Image`
572 The new DCR model images from the current iteration.
573 The values will be modified in place.
574 bbox : `lsst.afw.geom.Box2I`
576 statsCtrl : `lsst.afw.math.StatisticsControl`
577 Statistics control object for coaddition.
578 regularizationFactor : `float`
579 Maximum relative change of the model allowed between subfilters.
580 regularizationWidth : `int`, optional
581 Minimum radius of a region to include in regularization, in pixels.
582 mask : `lsst.afw.image.Mask`, optional
583 Optional alternate mask
584 convergenceMaskPlanes : `list` of `str`, or `str`, optional
585 Mask planes to use to calculate convergence.
589 This implementation of frequency regularization restricts each
590 subfilter image to be a smoothly-varying function times a reference
596 maxDiff = np.sqrt(regularizationFactor)
597 noiseLevel = self.
calculateNoiseCutoff(modelImages[0], statsCtrl, bufferSize=5, mask=mask, bbox=bbox)
599 badPixels = np.isnan(referenceImage) | (referenceImage <= 0.)
600 if np.sum(~badPixels) == 0:
603 referenceImage[badPixels] = 0.
604 filterWidth = regularizationWidth
605 fwhm = 2.*filterWidth
609 smoothRef = ndimage.gaussian_filter(referenceImage, filterWidth, mode=
'constant')
613 smoothRef += 3.*noiseLevel
615 lowThreshold = smoothRef/maxDiff
616 highThreshold = smoothRef*maxDiff
617 for model
in modelImages:
619 highThreshold=highThreshold,
620 lowThreshold=lowThreshold,
621 regularizationWidth=regularizationWidth)
622 smoothModel = ndimage.gaussian_filter(model.array, filterWidth, mode=
'constant')
623 smoothModel += 3.*noiseLevel
624 relativeModel = smoothModel/smoothRef
627 relativeModel2 = ndimage.gaussian_filter(relativeModel, filterWidth/alpha)
628 relativeModel += alpha*(relativeModel - relativeModel2)
629 model.array = relativeModel*referenceImage
632 convergenceMaskPlanes="DETECTED", mask=None, bbox=None):
633 """Helper function to calculate the background noise level of an image.
637 image : `lsst.afw.image.Image`
638 The input image to evaluate the background noise properties.
639 statsCtrl : `lsst.afw.math.StatisticsControl`
640 Statistics control object for coaddition.
642 Number of additional pixels to exclude
643 from the edges of the bounding box.
644 convergenceMaskPlanes : `list` of `str`, or `str`
645 Mask planes to use to calculate convergence.
646 mask : `lsst.afw.image.Mask`, Optional
647 Optional alternate mask
648 bbox : `lsst.afw.geom.Box2I`, optional
649 Sub-region of the masked image to calculate the noise level over.
653 noiseCutoff : `float`
654 The threshold value to treat pixels as noise in an image..
659 mask = self.
mask[bbox]
661 bboxShrink.grow(-bufferSize)
662 convergeMask = mask.getPlaneBitMask(convergenceMaskPlanes)
664 backgroundPixels = mask[bboxShrink].array & (statsCtrl.getAndMask() | convergeMask) == 0
665 noiseCutoff = np.std(image[bboxShrink].array[backgroundPixels])
669 """Restrict image values to be between upper and lower limits.
671 This method flags all pixels in an image that are outside of the given
672 threshold values. The threshold values are taken from a reference
673 image, so noisy pixels are likely to get flagged. In order to exclude
674 those noisy pixels, the array of flags is eroded and dilated, which
675 removes isolated pixels outside of the thresholds from the list of
676 pixels to be modified. Pixels that remain flagged after this operation
677 have their values set to the appropriate upper or lower threshold
682 image : `numpy.ndarray`
683 The image to apply the thresholds to.
684 The values will be modified in place.
685 highThreshold : `numpy.ndarray`, optional
686 Array of upper limit values for each pixel of ``image``.
687 lowThreshold : `numpy.ndarray`, optional
688 Array of lower limit values for each pixel of ``image``.
689 regularizationWidth : `int`, optional
690 Minimum radius of a region to include in regularization, in pixels.
695 filterStructure = ndimage.iterate_structure(ndimage.generate_binary_structure(2, 1),
697 if highThreshold
is not None:
698 highPixels = image > highThreshold
699 if regularizationWidth > 0:
701 highPixels = ndimage.binary_opening(highPixels, structure=filterStructure)
702 image[highPixels] = highThreshold[highPixels]
703 if lowThreshold
is not None:
704 lowPixels = image < lowThreshold
705 if regularizationWidth > 0:
707 lowPixels = ndimage.binary_opening(lowPixels, structure=filterStructure)
708 image[lowPixels] = lowThreshold[lowPixels]
711def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
712 doPrefilter=True, order=3):
713 """Shift an image along the X and Y directions.
717 image : `numpy.ndarray`
718 The input image to shift.
720 Shift calculated with ``calculateDcr``.
721 Uses numpy axes ordering (Y, X).
722 If ``splitSubfilters`` is set, each element is itself a `tuple`
723 of two `float`, corresponding to the DCR shift at the two wavelengths.
724 Otherwise, each element is a `float` corresponding to the DCR shift at
725 the effective wavelength of the subfilter.
726 useInverse : `bool`, optional
727 Apply the shift in the opposite direction. Default: False
728 splitSubfilters : `bool`, optional
729 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
730 instead of at the midpoint. Default: False
731 splitThreshold : `float`, optional
732 Minimum DCR difference within a subfilter required to use
734 doPrefilter : `bool`, optional
735 Spline filter the image before shifting, if set. Filtering is required,
736 so only set to False if the image is already filtered.
737 Filtering takes ~20% of the time of shifting, so if `applyDcr` will be
738 called repeatedly on the same image it is more efficient to
739 precalculate the filter.
740 order : `int`, optional
741 The order of the spline interpolation, default is 3.
745 shiftedImage : `numpy.ndarray`
746 A copy of the input image with the specified shift applied.
748 if doPrefilter
and order > 1:
749 prefilteredImage = ndimage.spline_filter(image, order=order)
751 prefilteredImage = image
753 shiftAmp = np.max(np.abs([_dcr0 - _dcr1
for _dcr0, _dcr1
in zip(dcr[0], dcr[1])]))
754 if shiftAmp >= splitThreshold:
756 shift = [-1.*s
for s
in dcr[0]]
757 shift1 = [-1.*s
for s
in dcr[1]]
761 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
762 shiftedImage += ndimage.shift(prefilteredImage, shift1, prefilter=
False, order=order)
768 dcr = (np.mean(dcr[0]), np.mean(dcr[1]))
770 shift = [-1.*s
for s
in dcr]
773 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
777def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False,
779 """Calculate the shift in pixels of an exposure due to DCR.
783 visitInfo : `lsst.afw.image.VisitInfo`
784 Metadata for the exposure.
785 wcs : `lsst.afw.geom.SkyWcs`
786 Coordinate system definition (wcs) for the exposure.
787 effectiveWavelength : `float`
788 The effective wavelengths of the current filter, in nanometers.
790 The bandwidth of the current filter, in nanometers.
791 dcrNumSubfilters : `int`
792 Number of sub-filters used to model chromatic effects within a band.
793 splitSubfilters : `bool`, optional
794 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
795 instead of at the midpoint. Default: False
796 bbox : `lsst.afw.geom.Box2I`, optional
797 Bounding box for the region of interest for evaluating the local
798 pixelScale (defaults to the Sky Origin of the ``wcs`` provided if
803 dcrShift : `tuple` of two `float`
804 The 2D shift due to DCR, in pixels.
805 Uses numpy axes ordering (Y, X).
809 weight = [0.75, 0.25]
813 diffRefractAmp0 = differentialRefraction(wavelength=wl0, wavelengthRef=effectiveWavelength,
814 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
815 observatory=visitInfo.getObservatory(),
816 weather=visitInfo.getWeather())
817 diffRefractAmp1 = differentialRefraction(wavelength=wl1, wavelengthRef=effectiveWavelength,
818 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
819 observatory=visitInfo.getObservatory(),
820 weather=visitInfo.getWeather())
822 pixelScale = wcs.getPixelScale(bbox.getCenter()).asArcseconds()
824 pixelScale = wcs.getPixelScale().asArcseconds()
827 diffRefractPix0 = diffRefractAmp0.asArcseconds()/pixelScale
828 diffRefractPix1 = diffRefractAmp1.asArcseconds()/pixelScale
829 diffRefractArr = [diffRefractPix0*weight[0] + diffRefractPix1*weight[1],
830 diffRefractPix0*weight[1] + diffRefractPix1*weight[0]]
831 shiftX = [diffRefractPix*np.sin(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
832 shiftY = [diffRefractPix*np.cos(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
833 dcrShift.append(((shiftY[0], shiftX[0]), (shiftY[1], shiftX[1])))
835 diffRefractAmp = (diffRefractAmp0 + diffRefractAmp1)/2.
836 diffRefractPix = diffRefractAmp.asArcseconds()/pixelScale
837 shiftX = diffRefractPix*np.sin(rotation.asRadians())
838 shiftY = diffRefractPix*np.cos(rotation.asRadians())
839 dcrShift.append((shiftY, shiftX))
844 """Calculate the total sky rotation angle of an exposure.
848 visitInfo : `lsst.afw.image.VisitInfo`
849 Metadata for the exposure.
850 wcs : `lsst.afw.geom.SkyWcs`
851 Coordinate system definition (wcs) for the exposure.
856 The rotation of the image axis, East from North.
857 Equal to the parallactic angle plus any additional rotation of the
859 A rotation angle of 0 degrees is defined with
860 North along the +y axis and East along the +x axis.
861 A rotation angle of 90 degrees is defined with
862 North along the +x axis and East along the -y axis.
864 parAngle = visitInfo.getBoresightParAngle().asRadians()
865 cd = wcs.getCdMatrix()
867 cdAngle = (np.arctan2(-cd[0, 1], cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
868 rotAngle = (cdAngle + parAngle)*geom.radians
870 cdAngle = (np.arctan2(cd[0, 1], -cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
871 rotAngle = (cdAngle - parAngle)*geom.radians
876 """Iterate over the wavelength endpoints of subfilters.
880 effectiveWavelength : `float`
881 The effective wavelength of the current filter, in nanometers.
883 The bandwidth of the current filter, in nanometers.
884 dcrNumSubfilters : `int`
885 Number of sub-filters used to model chromatic effects within a band.
889 `tuple` of two `float`
890 The next set of wavelength endpoints for a subfilter, in nanometers.
892 lambdaMin = effectiveWavelength - bandwidth/2
893 lambdaMax = effectiveWavelength + bandwidth/2
894 wlStep = bandwidth/dcrNumSubfilters
895 for wl
in np.linspace(lambdaMin, lambdaMax, dcrNumSubfilters, endpoint=
False):
896 yield (wl, wl + wlStep)
An integer coordinate rectangle.
buildMatchedTemplate(self, exposure=None, order=3, visitInfo=None, bbox=None, mask=None, splitSubfilters=True, splitThreshold=0., amplifyModel=1.)
assign(self, dcrSubModel, bbox=None)
fromImage(cls, maskedImage, dcrNumSubfilters, effectiveWavelength, bandwidth, wcs=None, filterLabel=None, psf=None, photoCalib=None)
__init__(self, modelImages, effectiveWavelength, bandwidth, filterLabel=None, psf=None, bbox=None, wcs=None, mask=None, variance=None, photoCalib=None)
regularizeModelIter(self, subfilter, newModel, bbox, regularizationFactor, regularizationWidth=2)
regularizeModelFreq(self, modelImages, bbox, statsCtrl, regularizationFactor, regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED")
__setitem__(self, subfilter, maskedImage)
buildMatchedExposureHandle(self, exposure=None, visitInfo=None, bbox=None, mask=None)
calculateNoiseCutoff(self, image, statsCtrl, bufferSize, convergenceMaskPlanes="DETECTED", mask=None, bbox=None)
effectiveWavelength(self)
conditionDcrModel(self, modelImages, bbox, gain=1.)
buildMatchedExposure(self, exposure=None, visitInfo=None, bbox=None, mask=None)
fromQuantum(cls, availableCoaddRefs, effectiveWavelength, bandwidth, numSubfilters)
applyImageThresholds(self, image, highThreshold=None, lowThreshold=None, regularizationWidth=2)
__getitem__(self, subfilter)
getReferenceImage(self, bbox=None)
applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0., doPrefilter=True, order=3)
wavelengthGenerator(effectiveWavelength, bandwidth, dcrNumSubfilters)
calculateImageParallacticAngle(visitInfo, wcs)
calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False, bbox=None)