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):
53 def __init__(self, modelImages, effectiveWavelength, bandwidth, filterLabel=None, psf=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)
68 def fromImage(cls, maskedImage, dcrNumSubfilters, effectiveWavelength, bandwidth,
…
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)
122 def fromQuantum(cls, availableCoaddRefs, effectiveWavelength, bandwidth, numSubfilters):
…
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 splitSubfilters=splitSubfilters, bbox=bbox)
408 templateImage = afwImage.ImageF(bbox)
410 for subfilter, dcr
in enumerate(dcrShift):
411 if self[subfilter]
is None:
413 self.log.debug(
"Skipping missing DCR model subfilter %d", subfilter)
420 model = (self[subfilter][bbox].array - refModel)*amplifyModel + refModel
422 model = self[subfilter][bbox].array
423 templateImage.array +=
applyDcr(model, dcr, splitSubfilters=splitSubfilters,
424 splitThreshold=splitThreshold, order=order)
428 visitInfo=None, bbox=None, mask=None):
429 """Wrapper to create an exposure from a template image.
433 exposure : `lsst.afw.image.Exposure`, optional
434 The input exposure to build a matched template for.
435 May be omitted if all of the metadata is supplied separately
436 visitInfo : `lsst.afw.image.VisitInfo`, optional
437 Metadata for the exposure. Ignored if ``exposure`` is set.
438 bbox : `lsst.afw.geom.Box2I`, optional
439 Sub-region of the coadd, or use the entire coadd if not supplied.
440 mask : `lsst.afw.image.Mask`, optional
441 reference mask to use for the template image.
445 templateExposure : `lsst.afw.image.exposureF`
446 The DCR-matched template
451 If no `photcCalib` is set.
456 bbox=bbox, mask=mask)
457 maskedImage = afwImage.MaskedImageF(bbox)
458 maskedImage.image = templateImage[bbox]
459 maskedImage.mask = self.
mask[bbox]
460 maskedImage.variance = self.
variance[bbox]
464 templateExposure = afwImage.ExposureF(bbox, self.
wcs)
465 templateExposure.setMaskedImage(maskedImage[bbox])
466 templateExposure.setPsf(self.
psf)
469 raise RuntimeError(
"No PhotoCalib set for the DcrModel. "
470 "If the DcrModel was created from a masked image"
471 " you must also specify the photoCalib.")
472 templateExposure.setPhotoCalib(self.
photoCalib)
473 return templateExposure
476 """Create in-memory butler dataset reference containing the DCR-matched
481 exposure : `lsst.afw.image.Exposure`, optional
482 The input exposure to build a matched template for.
483 May be omitted if all of the metadata is supplied separately
484 visitInfo : `lsst.afw.image.VisitInfo`, optional
485 Metadata for the exposure. Ignored if ``exposure`` is set.
486 bbox : `lsst.afw.geom.Box2I`, optional
487 Sub-region of the coadd, or use the entire coadd if not supplied.
488 mask : `lsst.afw.image.Mask`, optional
489 reference mask to use for the template image.
493 templateExposureHandle: `lsst.pipe.base.InMemoryDatasetHandle`
494 In-memory butler dataset reference containing the DCR-matched
500 If no `exposure` or `visitInfo` is set.
502 if exposure
is not None:
503 visitInfo = exposure.visitInfo
504 elif visitInfo
is None:
505 raise ValueError(
"Either exposure or visitInfo must be set.")
507 exposure=exposure, visitInfo=visitInfo, bbox=bbox, mask=mask
509 templateExposureHandle = pipeBase.InMemoryDatasetHandle(
511 storageClass=
"ExposureF",
515 return templateExposureHandle
518 """Average two iterations' solutions to reduce oscillations.
522 modelImages : `list` of `lsst.afw.image.Image`
523 The new DCR model images from the current iteration.
524 The values will be modified in place.
525 bbox : `lsst.afw.geom.Box2I`
526 Sub-region of the coadd
527 gain : `float`, optional
528 Relative weight to give the new solution when updating the model.
529 Defaults to 1.0, which gives equal weight to both solutions.
532 for model, newModel
in zip(self, modelImages):
534 newModel += model[bbox]
535 newModel /= 1. + gain
538 regularizationWidth=2):
539 """Restrict large variations in the model between iterations.
544 Index of the current subfilter within the full band.
545 newModel : `lsst.afw.image.Image`
546 The new DCR model for one subfilter from the current iteration.
547 Values in ``newModel`` that are extreme compared with the last
548 iteration are modified in place.
549 bbox : `lsst.afw.geom.Box2I`
551 regularizationFactor : `float`
552 Maximum relative change of the model allowed between iterations.
553 regularizationWidth : int, optional
554 Minimum radius of a region to include in regularization, in pixels.
556 refImage = self[subfilter][bbox].array
557 highThreshold = np.abs(refImage)*regularizationFactor
558 lowThreshold = refImage/regularizationFactor
559 newImage = newModel.array
561 regularizationWidth=regularizationWidth)
564 regularizationWidth=2, mask=None, convergenceMaskPlanes="DETECTED"):
565 """Restrict large variations in the model between subfilters.
569 modelImages : `list` of `lsst.afw.image.Image`
570 The new DCR model images from the current iteration.
571 The values will be modified in place.
572 bbox : `lsst.afw.geom.Box2I`
574 statsCtrl : `lsst.afw.math.StatisticsControl`
575 Statistics control object for coaddition.
576 regularizationFactor : `float`
577 Maximum relative change of the model allowed between subfilters.
578 regularizationWidth : `int`, optional
579 Minimum radius of a region to include in regularization, in pixels.
580 mask : `lsst.afw.image.Mask`, optional
581 Optional alternate mask
582 convergenceMaskPlanes : `list` of `str`, or `str`, optional
583 Mask planes to use to calculate convergence.
587 This implementation of frequency regularization restricts each
588 subfilter image to be a smoothly-varying function times a reference
594 maxDiff = np.sqrt(regularizationFactor)
595 noiseLevel = self.
calculateNoiseCutoff(modelImages[0], statsCtrl, bufferSize=5, mask=mask, bbox=bbox)
597 badPixels = np.isnan(referenceImage) | (referenceImage <= 0.)
598 if np.sum(~badPixels) == 0:
601 referenceImage[badPixels] = 0.
602 filterWidth = regularizationWidth
603 fwhm = 2.*filterWidth
607 smoothRef = ndimage.gaussian_filter(referenceImage, filterWidth, mode=
'constant')
611 smoothRef += 3.*noiseLevel
613 lowThreshold = smoothRef/maxDiff
614 highThreshold = smoothRef*maxDiff
615 for model
in modelImages:
617 highThreshold=highThreshold,
618 lowThreshold=lowThreshold,
619 regularizationWidth=regularizationWidth)
620 smoothModel = ndimage.gaussian_filter(model.array, filterWidth, mode=
'constant')
621 smoothModel += 3.*noiseLevel
622 relativeModel = smoothModel/smoothRef
625 relativeModel2 = ndimage.gaussian_filter(relativeModel, filterWidth/alpha)
626 relativeModel += alpha*(relativeModel - relativeModel2)
627 model.array = relativeModel*referenceImage
630 convergenceMaskPlanes="DETECTED", mask=None, bbox=None):
631 """Helper function to calculate the background noise level of an image.
635 image : `lsst.afw.image.Image`
636 The input image to evaluate the background noise properties.
637 statsCtrl : `lsst.afw.math.StatisticsControl`
638 Statistics control object for coaddition.
640 Number of additional pixels to exclude
641 from the edges of the bounding box.
642 convergenceMaskPlanes : `list` of `str`, or `str`
643 Mask planes to use to calculate convergence.
644 mask : `lsst.afw.image.Mask`, Optional
645 Optional alternate mask
646 bbox : `lsst.afw.geom.Box2I`, optional
647 Sub-region of the masked image to calculate the noise level over.
651 noiseCutoff : `float`
652 The threshold value to treat pixels as noise in an image..
657 mask = self.
mask[bbox]
659 bboxShrink.grow(-bufferSize)
660 convergeMask = mask.getPlaneBitMask(convergenceMaskPlanes)
662 backgroundPixels = mask[bboxShrink].array & (statsCtrl.getAndMask() | convergeMask) == 0
663 noiseCutoff = np.std(image[bboxShrink].array[backgroundPixels])
667 """Restrict image values to be between upper and lower limits.
669 This method flags all pixels in an image that are outside of the given
670 threshold values. The threshold values are taken from a reference
671 image, so noisy pixels are likely to get flagged. In order to exclude
672 those noisy pixels, the array of flags is eroded and dilated, which
673 removes isolated pixels outside of the thresholds from the list of
674 pixels to be modified. Pixels that remain flagged after this operation
675 have their values set to the appropriate upper or lower threshold
680 image : `numpy.ndarray`
681 The image to apply the thresholds to.
682 The values will be modified in place.
683 highThreshold : `numpy.ndarray`, optional
684 Array of upper limit values for each pixel of ``image``.
685 lowThreshold : `numpy.ndarray`, optional
686 Array of lower limit values for each pixel of ``image``.
687 regularizationWidth : `int`, optional
688 Minimum radius of a region to include in regularization, in pixels.
693 filterStructure = ndimage.iterate_structure(ndimage.generate_binary_structure(2, 1),
695 if highThreshold
is not None:
696 highPixels = image > highThreshold
697 if regularizationWidth > 0:
699 highPixels = ndimage.binary_opening(highPixels, structure=filterStructure)
700 image[highPixels] = highThreshold[highPixels]
701 if lowThreshold
is not None:
702 lowPixels = image < lowThreshold
703 if regularizationWidth > 0:
705 lowPixels = ndimage.binary_opening(lowPixels, structure=filterStructure)
706 image[lowPixels] = lowThreshold[lowPixels]
709def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
710 doPrefilter=True, order=3):
711 """Shift an image along the X and Y directions.
715 image : `numpy.ndarray`
716 The input image to shift.
718 Shift calculated with ``calculateDcr``.
719 Uses numpy axes ordering (Y, X).
720 If ``splitSubfilters`` is set, each element is itself a `tuple`
721 of two `float`, corresponding to the DCR shift at the two wavelengths.
722 Otherwise, each element is a `float` corresponding to the DCR shift at
723 the effective wavelength of the subfilter.
724 useInverse : `bool`, optional
725 Apply the shift in the opposite direction. Default: False
726 splitSubfilters : `bool`, optional
727 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
728 instead of at the midpoint. Default: False
729 splitThreshold : `float`, optional
730 Minimum DCR difference within a subfilter required to use
732 doPrefilter : `bool`, optional
733 Spline filter the image before shifting, if set. Filtering is required,
734 so only set to False if the image is already filtered.
735 Filtering takes ~20% of the time of shifting, so if `applyDcr` will be
736 called repeatedly on the same image it is more efficient to
737 precalculate the filter.
738 order : `int`, optional
739 The order of the spline interpolation, default is 3.
743 shiftedImage : `numpy.ndarray`
744 A copy of the input image with the specified shift applied.
746 if doPrefilter
and order > 1:
747 prefilteredImage = ndimage.spline_filter(image, order=order)
749 prefilteredImage = image
751 shiftAmp = np.max(np.abs([_dcr0 - _dcr1
for _dcr0, _dcr1
in zip(dcr[0], dcr[1])]))
752 if shiftAmp >= splitThreshold:
754 shift = [-1.*s
for s
in dcr[0]]
755 shift1 = [-1.*s
for s
in dcr[1]]
759 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
760 shiftedImage += ndimage.shift(prefilteredImage, shift1, prefilter=
False, order=order)
766 dcr = (np.mean(dcr[0]), np.mean(dcr[1]))
768 shift = [-1.*s
for s
in dcr]
771 shiftedImage = ndimage.shift(prefilteredImage, shift, prefilter=
False, order=order)
709def applyDcr(image, dcr, useInverse=False, splitSubfilters=False, splitThreshold=0.,
…
775def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False,
777 """Calculate the shift in pixels of an exposure due to DCR.
781 visitInfo : `lsst.afw.image.VisitInfo`
782 Metadata for the exposure.
783 wcs : `lsst.afw.geom.SkyWcs`
784 Coordinate system definition (wcs) for the exposure.
785 effectiveWavelength : `float`
786 The effective wavelengths of the current filter, in nanometers.
788 The bandwidth of the current filter, in nanometers.
789 dcrNumSubfilters : `int`
790 Number of sub-filters used to model chromatic effects within a band.
791 splitSubfilters : `bool`, optional
792 Calculate DCR for two evenly-spaced wavelengths in each subfilter,
793 instead of at the midpoint. Default: False
794 bbox : `lsst.afw.geom.Box2I`, optional
795 Bounding box for the region of interest for evaluating the local
796 pixelScale (defaults to the Sky Origin of the ``wcs`` provided if
801 dcrShift : `tuple` of two `float`
802 The 2D shift due to DCR, in pixels.
803 Uses numpy axes ordering (Y, X).
807 weight = [0.75, 0.25]
811 diffRefractAmp0 = differentialRefraction(wavelength=wl0, wavelengthRef=effectiveWavelength,
812 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
813 observatory=visitInfo.getObservatory(),
814 weather=visitInfo.getWeather())
815 diffRefractAmp1 = differentialRefraction(wavelength=wl1, wavelengthRef=effectiveWavelength,
816 elevation=visitInfo.getBoresightAzAlt().getLatitude(),
817 observatory=visitInfo.getObservatory(),
818 weather=visitInfo.getWeather())
820 pixelScale = wcs.getPixelScale(bbox.getCenter()).asArcseconds()
822 pixelScale = wcs.getPixelScale().asArcseconds()
825 diffRefractPix0 = diffRefractAmp0.asArcseconds()/pixelScale
826 diffRefractPix1 = diffRefractAmp1.asArcseconds()/pixelScale
827 diffRefractArr = [diffRefractPix0*weight[0] + diffRefractPix1*weight[1],
828 diffRefractPix0*weight[1] + diffRefractPix1*weight[0]]
829 shiftX = [diffRefractPix*np.sin(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
830 shiftY = [diffRefractPix*np.cos(rotation.asRadians())
for diffRefractPix
in diffRefractArr]
831 dcrShift.append(((shiftY[0], shiftX[0]), (shiftY[1], shiftX[1])))
833 diffRefractAmp = (diffRefractAmp0 + diffRefractAmp1)/2.
834 diffRefractPix = diffRefractAmp.asArcseconds()/pixelScale
835 shiftX = diffRefractPix*np.sin(rotation.asRadians())
836 shiftY = diffRefractPix*np.cos(rotation.asRadians())
837 dcrShift.append((shiftY, shiftX))
775def calculateDcr(visitInfo, wcs, effectiveWavelength, bandwidth, dcrNumSubfilters, splitSubfilters=False,
…
842 """Calculate the total sky rotation angle of an exposure.
846 visitInfo : `lsst.afw.image.VisitInfo`
847 Metadata for the exposure.
848 wcs : `lsst.afw.geom.SkyWcs`
849 Coordinate system definition (wcs) for the exposure.
854 The rotation of the image axis, East from North.
855 Equal to the parallactic angle plus any additional rotation of the
857 A rotation angle of 0 degrees is defined with
858 North along the +y axis and East along the +x axis.
859 A rotation angle of 90 degrees is defined with
860 North along the +x axis and East along the -y axis.
862 parAngle = visitInfo.getBoresightParAngle().asRadians()
863 cd = wcs.getCdMatrix()
865 cdAngle = (np.arctan2(-cd[0, 1], cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
866 rotAngle = (cdAngle + parAngle)*geom.radians
868 cdAngle = (np.arctan2(cd[0, 1], -cd[0, 0]) + np.arctan2(cd[1, 0], cd[1, 1]))/2.
869 rotAngle = (cdAngle - parAngle)*geom.radians
874 """Iterate over the wavelength endpoints of subfilters.
878 effectiveWavelength : `float`
879 The effective wavelength of the current filter, in nanometers.
881 The bandwidth of the current filter, in nanometers.
882 dcrNumSubfilters : `int`
883 Number of sub-filters used to model chromatic effects within a band.
887 `tuple` of two `float`
888 The next set of wavelength endpoints for a subfilter, in nanometers.
890 lambdaMin = effectiveWavelength - bandwidth/2
891 lambdaMax = effectiveWavelength + bandwidth/2
892 wlStep = bandwidth/dcrNumSubfilters
893 for wl
in np.linspace(lambdaMin, lambdaMax, dcrNumSubfilters, endpoint=
False):
894 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)