23from __future__
import annotations
25__all__ = [
"ImageScaler",
"SpatialImageScaler",
"ScaleZeroPointTask"]
31import lsst.pipe.base
as pipeBase
33from deprecated.sphinx
import deprecated
37 """A class that scales an image.
39 This version uses a single scalar. Fancier versions may use a spatially varying scale.
43 scale : `float`, optional
44 Scale correction to apply (see ``scaleMaskedImage``).
52 @deprecated("This property will be removed after v30.", version="v30", category=FutureWarning)
54 """Scale that it applies to a specified image."""
58 """Scale the specified image or masked image in place.
62 maskedImage : `lsst.afw.image.MaskedImage`
63 Masked image to scale.
69 """Multiplicative image scaler using interpolation over a grid of points.
71 Contains the x, y positions in tract coordinates and the scale factors.
72 Interpolates only when scaleMaskedImage() or getInterpImage() is called.
74 Currently the only type of 'interpolation' implemented is CONSTANT which calculates the mean.
78 interpStyle : `Unknown`
79 Interpolation style (`CONSTANT` is only option).
80 xList : `list` of `int`
81 List of X pixel positions.
82 yList : `list` of `int`
83 List of Y pixel positions.
85 List of multiplicative scale factors at (x,y).
90 Raised if the lists have different lengths.
93 def __init__(self, interpStyle, xList, yList, scaleList):
94 if len(xList) != len(yList)
or len(xList) != len(scaleList):
96 "len(xList)=%s len(yList)=%s, len(scaleList)=%s but all lists must have the same length" %
97 (len(xList), len(yList), len(scaleList)))
106 @deprecated("This property will be removed after v30.", version="v30", category=FutureWarning)
108 """Mean scale that it applies to a specified image."""
112 """Apply scale correction to the specified masked image.
116 maskedImage : `lsst.afw.image.MaskedImage`
117 Masked image to scale; scale is applied in place.
123 """Return an image containing the scale correction with same bounding box as supplied.
127 bbox : `lsst.geom.Box2I`
128 Integer bounding box for image.
133 Raised if there are no fluxMag0s to interpolate.
135 npoints = len(self.
_xList)
138 raise RuntimeError(
"Cannot create scaling image. Found no fluxMag0s to interpolate")
140 image = afwImage.ImageF(bbox, numpy.mean(self.
_scaleList))
146 """Config for ScaleZeroPointTask.
149 zeroPoint = pexConfig.Field(
151 doc=
"desired photometric zero point",
157 selectFluxMag0 = pexConfig.ConfigurableField(
158 doc=
"Task to select data to compute spatially varying photometric zeropoint",
159 target=BaseSelectImagesTask,
162 interpStyle = pexConfig.ChoiceField(
164 doc=
"Algorithm to interpolate the flux scalings;"
165 "Currently only one choice implemented",
168 "CONSTANT":
"Use a single constant value",
174 """Compute scale factor to scale exposures to a desired photometric zero point.
176 This simple version assumes that the zero point is spatially invariant.
179 ConfigClass = ScaleZeroPointConfig
180 _DefaultName =
"scaleZeroPoint"
183 pipeBase.Task.__init__(self, *args, **kwargs)
186 fluxMag0 = 10**(0.4 * self.config.zeroPoint)
187 self.
_photoCalib = afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)
189 def run(self, exposure, dataRef=None):
190 """Scale the specified exposure to the desired photometric zeropoint.
194 exposure : `lsst.afw.image.Exposure`
195 Exposure to scale; masked image is scaled in place.
196 dataRef : `Unknown`, optional
197 Data reference for exposure.
198 Not used, but in API so that users can switch between spatially variant
203 result : `~lsst.pipe.base.Struct`
204 Results as a struct with attributes:
207 The image scaling object used to scale exposure.
210 mi = exposure.getMaskedImage()
211 imageScaler.scaleMaskedImage(mi)
212 return pipeBase.Struct(
213 imageScaler=imageScaler,
217 """Compute image scaling object for a given exposure.
221 exposure : `lsst.afw.image.Exposure`
222 Exposure for which scaling is desired.
223 dataRef : `Unknown`, optional
224 Data reference for exposure.
225 Not used, but in API so that users can switch between spatially variant
232 """Get desired PhotoCalib.
236 calibration : `lsst.afw.image.PhotoCalib`
237 Calibration with ``fluxMag0`` set appropriately for config.zeroPoint.
242 """Compute the scale for the specified PhotoCalib.
246 calib : `lsst.afw.image.PhotoCalib`
247 PhotoCalib object to compute the scale from.
251 result : `lsst.pipe.base.Struct`
252 Results as a struct with attributes:
256 Scale, such that if pixelCalib describes the photometric
257 zeropoint of a pixel then the following scales that pixel to
258 the photometric zeropoint specified by config.zeroPoint:
259 ``scale = computeScale(pixelCalib) pixel *= scale``
263 Returns a struct to leave room for scaleErr in a future implementation.
265 fluxAtZeroPoint = calib.magnitudeToInstFlux(self.config.zeroPoint)
266 return pipeBase.Struct(
267 scale=1.0 / fluxAtZeroPoint,
271 """Compute the scale for the specified fluxMag0.
273 This is a wrapper around scaleFromPhotoCalib, which see for more information.
278 Flux at magnitude zero.
282 result : `lsst.pipe.base.Struct`
283 Results as a struct with attributes:
287 Scale, such that if pixelCalib describes the photometric zeropoint
288 of a pixel then the following scales that pixel to the photometric
289 zeropoint specified by config.zeroPoint:
290 ``scale = computeScale(pixelCalib)``
293 calib = afwImage.makePhotoCalibFromCalibZeroPoint(fluxMag0, 0.0)
298 """Compute spatially varying scale factor to scale exposures to a desired photometric zero point.
301 ConfigClass = SpatialScaleZeroPointConfig
302 _DefaultName =
"scaleZeroPoint"
305 ScaleZeroPointTask.__init__(self, *args, **kwargs)
306 self.makeSubtask(
"selectFluxMag0")
308 def run(self, exposure, dataRef):
309 """Scale the specified exposure to the desired photometric zeropoint.
313 exposure : `lsst.afw.image.Exposure`
314 Exposure to scale; masked image is scaled in place.
316 Data reference for exposure.
320 result : `lsst.pipe.base.Struct`
321 Results as a struct with attributes:
324 The image scaling object used to scale exposure.
327 mi = exposure.getMaskedImage()
328 imageScaler.scaleMaskedImage(mi)
329 return pipeBase.Struct(
330 imageScaler=imageScaler,
334 """Compute image scaling object for a given exposure.
338 exposure : `lsst.afw.image.Exposure`
339 Exposure for which scaling is desired. Only wcs and bbox are used.
341 Data reference of exposure.
342 dataRef.dataId used to retrieve all applicable fluxMag0's from a database.
346 result : `SpatialImageScaler`
348 wcs = exposure.getWcs()
350 fluxMagInfoList = self.selectFluxMag0.run(dataRef.dataId).fluxMagInfoList
356 for fluxMagInfo
in fluxMagInfoList:
358 if not fluxMagInfo.coordList:
359 raise RuntimeError(
"no x,y data for fluxMagInfo")
361 for coord
in fluxMagInfo.coordList:
366 xList.append(ctr.getX())
367 yList.append(ctr.getY())
370 self.log.info(
"Found %d flux scales for interpolation: %s",
371 len(scaleList), [f
"{s:%0.4f}" for s
in scaleList])
373 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)