22__all__ = [
"ImageScaler",
"SpatialImageScaler",
"ScaleZeroPointTask"]
28import lsst.pipe.base
as pipeBase
33 """A class that scales an image.
35 This version uses a single scalar. Fancier versions may use a spatially varying scale.
39 scale : `float`, optional
40 Scale correction to apply (see ``scaleMaskedImage``).
47 """Scale the specified image or masked image in place.
51 maskedImage : `lsst.afw.image.MaskedImage`
52 Masked image to scale.
58 """Multiplicative image scaler using interpolation over a grid of points.
60 Contains the x, y positions in tract coordinates and the scale factors.
61 Interpolates only when scaleMaskedImage() or getInterpImage() is called.
63 Currently the only type of 'interpolation' implemented is CONSTANT which calculates the mean.
67 interpStyle : `Unknown`
68 Interpolation style (`CONSTANT` is only option).
69 xList : `list` of `int`
70 List of X pixel positions.
71 yList : `list` of `int`
72 List of Y pixel positions.
74 List of multiplicative scale factors at (x,y).
79 Raised if the lists have different lengths.
82 def __init__(self, interpStyle, xList, yList, scaleList):
83 if len(xList) != len(yList)
or len(xList) != len(scaleList):
85 "len(xList)=%s len(yList)=%s, len(scaleList)=%s but all lists must have the same length" %
86 (len(xList), len(yList), len(scaleList)))
94 """Apply scale correction to the specified masked image.
98 image : `lsst.afw.image.MaskedImage`
99 To scale; scale is applied in place.
105 """Return an image containing the scale correction with same bounding box as supplied.
109 bbox : `lsst.geom.Box2I`
110 Integer bounding box for image.
115 Raised if there are no fluxMag0s to interpolate.
117 npoints = len(self.
_xList)
120 raise RuntimeError(
"Cannot create scaling image. Found no fluxMag0s to interpolate")
122 image = afwImage.ImageF(bbox, numpy.mean(self.
_scaleList))
128 """Config for ScaleZeroPointTask.
131 zeroPoint = pexConfig.Field(
133 doc=
"desired photometric zero point",
139 selectFluxMag0 = pexConfig.ConfigurableField(
140 doc=
"Task to select data to compute spatially varying photometric zeropoint",
141 target=BaseSelectImagesTask,
144 interpStyle = pexConfig.ChoiceField(
146 doc=
"Algorithm to interpolate the flux scalings;"
147 "Currently only one choice implemented",
150 "CONSTANT":
"Use a single constant value",
156 """Compute scale factor to scale exposures to a desired photometric zero point.
158 This simple version assumes that the zero point is spatially invariant.
161 ConfigClass = ScaleZeroPointConfig
162 _DefaultName =
"scaleZeroPoint"
165 pipeBase.Task.__init__(self, *args, **kwargs)
168 fluxMag0 = 10**(0.4 * self.config.zeroPoint)
169 self.
_photoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)
171 def run(self, exposure, dataRef=None):
172 """Scale the specified exposure to the desired photometric zeropoint.
176 exposure : `lsst.afw.image.Exposure`
177 Exposure to scale; masked image is scaled in place.
179 Data reference for exposure.
180 Not used, but in API so that users can switch between spatially variant
185 result : `lsst.pipe.base.Struct`
186 Results as a struct with attributes:
189 The image scaling object used to scale exposure.
192 mi = exposure.getMaskedImage()
193 imageScaler.scaleMaskedImage(mi)
194 return pipeBase.Struct(
195 imageScaler=imageScaler,
199 """Compute image scaling object for a given exposure.
203 exposure : `lsst.afw.image.Exposure`
204 Exposure for which scaling is desired.
205 dataRef : `Unknown`, optional
206 Data reference for exposure.
207 Not used, but in API so that users can switch between spatially variant
214 """Get desired PhotoCalib.
218 calibration : `lsst.afw.image.PhotoCalib`
219 Calibration with ``fluxMag0`` set appropriately for config.zeroPoint.
224 """Compute the scale for the specified PhotoCalib.
228 result : `lsst.pipe.base.Struct`
229 Results as a struct with attributes:
233 Scale, such that if pixelCalib describes the photometric
234 zeropoint of a pixel then the following scales that pixel to
235 the photometric zeropoint specified by config.zeroPoint:
236 ``scale = computeScale(pixelCalib) pixel *= scale``
240 Returns a struct to leave room for scaleErr in a future implementation.
242 fluxAtZeroPoint = calib.magnitudeToInstFlux(self.config.zeroPoint)
243 return pipeBase.Struct(
244 scale=1.0 / fluxAtZeroPoint,
248 """Compute the scale for the specified fluxMag0.
250 This is a wrapper around scaleFromPhotoCalib, which see for more information.
255 Flux at magnitude zero.
259 result : `lsst.pipe.base.Struct`
260 Results as a struct with attributes:
264 Scale, such that if pixelCalib describes the photometric zeropoint
265 of a pixel then the following scales that pixel to the photometric
266 zeropoint specified by config.zeroPoint:
267 ``scale = computeScale(pixelCalib)``
270 calib = afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)
275 """Compute spatially varying scale factor to scale exposures to a desired photometric zero point.
278 ConfigClass = SpatialScaleZeroPointConfig
279 _DefaultName =
"scaleZeroPoint"
282 ScaleZeroPointTask.__init__(self, *args, **kwargs)
283 self.makeSubtask(
"selectFluxMag0")
285 def run(self, exposure, dataRef):
286 """Scale the specified exposure to the desired photometric zeropoint.
290 exposure : `lsst.afw.image.Exposure`
291 Exposure to scale; masked image is scaled in place.
293 Data reference for exposure.
297 result : `lsst.pipe.base.Struct`
298 Results as a struct with attributes:
301 The image scaling object used to scale exposure.
304 mi = exposure.getMaskedImage()
305 imageScaler.scaleMaskedImage(mi)
306 return pipeBase.Struct(
307 imageScaler=imageScaler,
311 """Compute image scaling object for a given exposure.
315 exposure : `lsst.afw.image.Exposure`
316 Exposure for which scaling is desired. Only wcs and bbox are used.
318 Data reference of exposure.
319 dataRef.dataId used to retrieve all applicable fluxMag0's from a database.
323 result : `SpatialImageScaler`
325 wcs = exposure.getWcs()
327 fluxMagInfoList = self.selectFluxMag0.run(dataRef.dataId).fluxMagInfoList
333 for fluxMagInfo
in fluxMagInfoList:
335 if not fluxMagInfo.coordList:
336 raise RuntimeError(
"no x,y data for fluxMagInfo")
338 for coord
in fluxMagInfo.coordList:
343 xList.append(ctr.getX())
344 yList.append(ctr.getY())
347 self.log.info(
"Found %d flux scales for interpolation: %s",
348 len(scaleList), [f
"{s:%0.4f}" for s
in scaleList])
350 interpStyle=self.config.interpStyle,
scaleMaskedImage(self, maskedImage)
__init__(self, scale=1.0)
scaleFromFluxMag0(self, fluxMag0)
run(self, exposure, dataRef=None)
computeImageScaler(self, exposure, dataRef=None)
scaleFromPhotoCalib(self, calib)
__init__(self, *args, **kwargs)
scaleMaskedImage(self, maskedImage)
__init__(self, interpStyle, xList, yList, scaleList)
getInterpImage(self, bbox)
run(self, exposure, dataRef)
__init__(self, *args, **kwargs)
computeImageScaler(self, exposure, dataRef)