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.
38 """Construct an ImageScaler
40 @param[in] scale: scale correction to apply (see scaleMaskedImage);
45 """Scale the specified image or masked image in place.
47 @param[in,out] maskedImage: masked image to scale
53 """Multiplicative image scaler using interpolation over a grid of points.
55 Contains the x, y positions in tract coordinates and the scale factors.
56 Interpolates only when scaleMaskedImage() or getInterpImage() is called.
58 Currently the only type of 'interpolation' implemented is CONSTANT which calculates the mean.
61 def __init__(self, interpStyle, xList, yList, scaleList):
64 @param[in] interpStyle: interpolation style (CONSTANT is only option)
65 @param[in] xList: list of X pixel positions
66 @param[in] yList: list of Y pixel positions
67 @param[in] scaleList: list of multiplicative scale factors at (x,y)
69 @raise RuntimeError if the lists have different lengths
71 if len(xList) != len(yList)
or len(xList) != len(scaleList):
73 "len(xList)=%s len(yList)=%s, len(scaleList)=%s but all lists must have the same length" %
74 (len(xList), len(yList), len(scaleList)))
82 """Apply scale correction to the specified masked image
84 @param[in,out] image to scale; scale is applied in place
90 """Return an image containing the scale correction with same bounding box as supplied.
92 @param[in] bbox: integer bounding box for image (afwGeom.Box2I)
97 raise RuntimeError(
"Cannot create scaling image. Found no fluxMag0s to interpolate")
99 image = afwImage.ImageF(bbox, numpy.mean(self.
_scaleList))
105 """Config for ScaleZeroPointTask
107 zeroPoint = pexConfig.Field(
109 doc =
"desired photometric zero point",
115 selectFluxMag0 = pexConfig.ConfigurableField(
116 doc =
"Task to select data to compute spatially varying photometric zeropoint",
117 target = BaseSelectImagesTask,
120 interpStyle = pexConfig.ChoiceField(
122 doc =
"Algorithm to interpolate the flux scalings;" \
123 "Currently only one choice implemented",
124 default =
"CONSTANT",
126 "CONSTANT" :
"Use a single constant value",
132 """Compute scale factor to scale exposures to a desired photometric zero point
134 This simple version assumes that the zero point is spatially invariant.
136 ConfigClass = ScaleZeroPointConfig
137 _DefaultName =
"scaleZeroPoint"
140 """Construct a ScaleZeroPointTask
142 pipeBase.Task.__init__(self, *args, **kwargs)
145 fluxMag0 = 10**(0.4 * self.config.zeroPoint)
147 self._calib.setFluxMag0(fluxMag0)
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
181 @return calibration (lsst.afw.image.Calib) with fluxMag0 set appropriately for config.zeroPoint
186 """Compute the scale for the specified Calib
188 Compute scale, such that if pixelCalib describes the photometric zeropoint of a pixel
189 then the following scales that pixel to the photometric zeropoint specified by config.zeroPoint:
190 scale = computeScale(pixelCalib)
193 @return a pipeBase.Struct containing:
194 - scale, as described above.
196 @note: returns a struct to leave room for scaleErr in a future implementation.
198 fluxAtZeroPoint = calib.getFlux(self.config.zeroPoint)
199 return pipeBase.Struct(
200 scale = 1.0 / fluxAtZeroPoint,
204 """Compute the scale for the specified fluxMag0
206 This is a wrapper around scaleFromCalib, which see for more information
209 @return a pipeBase.Struct containing:
210 - scale, as described in scaleFromCalib.
213 calib.setFluxMag0(fluxMag0)
218 """Compute spatially varying scale factor to scale exposures to a desired photometric zero point
220 ConfigClass = SpatialScaleZeroPointConfig
221 _DefaultName =
"scaleZeroPoint"
224 ScaleZeroPointTask.__init__(self, *args, **kwargs)
225 self.makeSubtask(
"selectFluxMag0")
227 def run(self, exposure, dataRef):
228 """Scale the specified exposure to the desired photometric zeropoint
230 @param[in,out] exposure: exposure to scale; masked image is scaled in place
231 @param[in] dataRef: dataRef for exposure
233 @return a pipeBase.Struct containing:
234 - imageScaler: the image scaling object used to scale exposure
237 mi = exposure.getMaskedImage()
238 imageScaler.scaleMaskedImage(mi)
239 return pipeBase.Struct(
240 imageScaler = imageScaler,
244 """Compute image scaling object for a given exposure.
246 @param[in] exposure: exposure for which scaling is desired. Only wcs and bbox are used.
247 @param[in] dataRef: dataRef of exposure
248 dataRef.dataId used to retrieve all applicable fluxMag0's from a database.
249 @return a SpatialImageScaler
252 wcs = exposure.getWcs()
254 fluxMagInfoList = self.selectFluxMag0.run(dataRef.dataId).fluxMagInfoList
260 for fluxMagInfo
in fluxMagInfoList:
262 if not fluxMagInfo.coordList:
263 raise RuntimeError(
"no x,y data for fluxMagInfo")
265 for coord
in fluxMagInfo.coordList:
270 xList.append(ctr.getX())
271 yList.append(ctr.getY())
274 self.log.info(
"Found %d flux scales for interpolation: %s"% (len(scaleList),
275 [
"%0.4f"%(s)
for s
in scaleList]))
277 interpStyle = self.config.interpStyle,
280 scaleList = scaleList,