25 import lsst.pex.config
as pexConfig
29 __all__ = [
"ImageScaler",
"SpatialImageScaler",
"ScaleZeroPointTask"]
33 """A class that scales an image
35 This version uses a single scalar. Fancier versions may use a spatially varying scale.
39 """Construct an ImageScaler
41 @param[in] scale: scale correction to apply (see scaleMaskedImage);
46 """Scale the specified image or masked image in place.
48 @param[in,out] maskedImage: masked image to scale
54 """Multiplicative image scaler using interpolation over a grid of points.
56 Contains the x, y positions in tract coordinates and the scale factors.
57 Interpolates only when scaleMaskedImage() or getInterpImage() is called.
59 Currently the only type of 'interpolation' implemented is CONSTANT which calculates the mean.
62 def __init__(self, interpStyle, xList, yList, scaleList):
65 @param[in] interpStyle: interpolation style (CONSTANT is only option)
66 @param[in] xList: list of X pixel positions
67 @param[in] yList: list of Y pixel positions
68 @param[in] scaleList: list of multiplicative scale factors at (x,y)
70 @raise RuntimeError if the lists have different lengths
72 if len(xList) != len(yList)
or len(xList) != len(scaleList):
74 "len(xList)=%s len(yList)=%s, len(scaleList)=%s but all lists must have the same length" %
75 (len(xList), len(yList), len(scaleList)))
83 """Apply scale correction to the specified masked image
85 @param[in,out] image to scale; scale is applied in place
91 """Return an image containing the scale correction with same bounding box as supplied.
93 @param[in] bbox: integer bounding box for image (geom.Box2I)
98 raise RuntimeError(
"Cannot create scaling image. Found no fluxMag0s to interpolate")
100 image = afwImage.ImageF(bbox, numpy.mean(self.
_scaleList))
106 """Config for ScaleZeroPointTask
108 zeroPoint = pexConfig.Field(
110 doc=
"desired photometric zero point",
116 selectFluxMag0 = pexConfig.ConfigurableField(
117 doc=
"Task to select data to compute spatially varying photometric zeropoint",
118 target=BaseSelectImagesTask,
121 interpStyle = pexConfig.ChoiceField(
123 doc=
"Algorithm to interpolate the flux scalings;"
124 "Currently only one choice implemented",
127 "CONSTANT":
"Use a single constant value",
133 """Compute scale factor to scale exposures to a desired photometric zero point
135 This simple version assumes that the zero point is spatially invariant.
137 ConfigClass = ScaleZeroPointConfig
138 _DefaultName =
"scaleZeroPoint"
141 """Construct a ScaleZeroPointTask
143 pipeBase.Task.__init__(self, *args, **kwargs)
146 fluxMag0 = 10**(0.4 * self.config.zeroPoint)
149 def run(self, exposure, dataRef=None):
150 """Scale the specified exposure to the desired photometric zeropoint
152 @param[in,out] exposure: exposure to scale; masked image is scaled in place
153 @param[in] dataRef: dataRef for exposure.
154 Not used, but in API so that users can switch between spatially variant
156 @return a pipeBase.Struct containing:
157 - imageScaler: the image scaling object used to scale exposure
160 mi = exposure.getMaskedImage()
161 imageScaler.scaleMaskedImage(mi)
162 return pipeBase.Struct(
163 imageScaler=imageScaler,
167 """Compute image scaling object for a given exposure.
169 @param[in] exposure: exposure for which scaling is desired
170 @param[in] dataRef: dataRef for exposure.
171 Not used, but in API so that users can switch between spatially variant
178 """Get desired PhotoCalib
180 @return calibration (lsst.afw.image.PhotoCalib) with fluxMag0 set appropriately for config.zeroPoint
185 """Compute the scale for the specified PhotoCalib
187 Compute scale, such that if pixelCalib describes the photometric zeropoint of a pixel
188 then the following scales that pixel to the photometric zeropoint specified by config.zeroPoint:
189 scale = computeScale(pixelCalib)
192 @return a pipeBase.Struct containing:
193 - scale, as described above.
195 @note: returns a struct to leave room for scaleErr in a future implementation.
197 fluxAtZeroPoint = calib.magnitudeToInstFlux(self.config.zeroPoint)
198 return pipeBase.Struct(
199 scale=1.0 / fluxAtZeroPoint,
203 """Compute the scale for the specified fluxMag0
205 This is a wrapper around scaleFromPhotoCalib, which see for more information
208 @return a pipeBase.Struct containing:
209 - scale, as described in scaleFromPhotoCalib.
216 """Compute spatially varying scale factor to scale exposures to a desired photometric zero point
218 ConfigClass = SpatialScaleZeroPointConfig
219 _DefaultName =
"scaleZeroPoint"
222 ScaleZeroPointTask.__init__(self, *args, **kwargs)
223 self.makeSubtask(
"selectFluxMag0")
225 def run(self, exposure, dataRef):
226 """Scale the specified exposure to the desired photometric zeropoint
228 @param[in,out] exposure: exposure to scale; masked image is scaled in place
229 @param[in] dataRef: dataRef for exposure
231 @return a pipeBase.Struct containing:
232 - imageScaler: the image scaling object used to scale exposure
235 mi = exposure.getMaskedImage()
236 imageScaler.scaleMaskedImage(mi)
237 return pipeBase.Struct(
238 imageScaler=imageScaler,
242 """Compute image scaling object for a given exposure.
244 @param[in] exposure: exposure for which scaling is desired. Only wcs and bbox are used.
245 @param[in] dataRef: dataRef of exposure
246 dataRef.dataId used to retrieve all applicable fluxMag0's from a database.
247 @return a SpatialImageScaler
250 wcs = exposure.getWcs()
252 fluxMagInfoList = self.selectFluxMag0.
run(dataRef.dataId).fluxMagInfoList
258 for fluxMagInfo
in fluxMagInfoList:
260 if not fluxMagInfo.coordList:
261 raise RuntimeError(
"no x,y data for fluxMagInfo")
263 for coord
in fluxMagInfo.coordList:
268 xList.append(ctr.getX())
269 yList.append(ctr.getY())
272 self.log.
info(
"Found %d flux scales for interpolation: %s" % (len(scaleList),
273 [
"%0.4f"%(s)
for s
in scaleList]))
275 interpStyle=self.config.interpStyle,