22 from __future__
import absolute_import, division, print_function
23 from builtins
import object
25 import lsst.afw.geom
as afwGeom
26 import lsst.afw.image
as afwImage
27 import lsst.pex.config
as pexConfig
28 import lsst.pipe.base
as pipeBase
31 __all__ = [
"ImageScaler",
"SpatialImageScaler",
"ScaleZeroPointTask"]
35 """A class that scales an image 37 This version uses a single scalar. Fancier versions may use a spatially varying scale. 41 """Construct an ImageScaler 43 @param[in] scale: scale correction to apply (see scaleMaskedImage); 48 """Scale the specified image or masked image in place. 50 @param[in,out] maskedImage: masked image to scale 56 """Multiplicative image scaler using interpolation over a grid of points. 58 Contains the x, y positions in tract coordinates and the scale factors. 59 Interpolates only when scaleMaskedImage() or getInterpImage() is called. 61 Currently the only type of 'interpolation' implemented is CONSTANT which calculates the mean. 64 def __init__(self, interpStyle, xList, yList, scaleList):
67 @param[in] interpStyle: interpolation style (CONSTANT is only option) 68 @param[in] xList: list of X pixel positions 69 @param[in] yList: list of Y pixel positions 70 @param[in] scaleList: list of multiplicative scale factors at (x,y) 72 @raise RuntimeError if the lists have different lengths 74 if len(xList) != len(yList)
or len(xList) != len(scaleList):
76 "len(xList)=%s len(yList)=%s, len(scaleList)=%s but all lists must have the same length" %
77 (len(xList), len(yList), len(scaleList)))
85 """Apply scale correction to the specified masked image 87 @param[in,out] image to scale; scale is applied in place 93 """Return an image containing the scale correction with same bounding box as supplied. 95 @param[in] bbox: integer bounding box for image (afwGeom.Box2I) 100 raise RuntimeError(
"Cannot create scaling image. Found no fluxMag0s to interpolate")
102 image = afwImage.ImageF(bbox, numpy.mean(self.
_scaleList))
108 """Config for ScaleZeroPointTask 110 zeroPoint = pexConfig.Field(
112 doc=
"desired photometric zero point",
118 selectFluxMag0 = pexConfig.ConfigurableField(
119 doc=
"Task to select data to compute spatially varying photometric zeropoint",
120 target=BaseSelectImagesTask,
123 interpStyle = pexConfig.ChoiceField(
125 doc=
"Algorithm to interpolate the flux scalings;" 126 "Currently only one choice implemented",
129 "CONSTANT":
"Use a single constant value",
135 """Compute scale factor to scale exposures to a desired photometric zero point 137 This simple version assumes that the zero point is spatially invariant. 139 ConfigClass = ScaleZeroPointConfig
140 _DefaultName =
"scaleZeroPoint" 143 """Construct a ScaleZeroPointTask 145 pipeBase.Task.__init__(self, *args, **kwargs)
148 fluxMag0 = 10**(0.4 * self.config.zeroPoint)
149 self.
_calib = afwImage.Calib()
150 self.
_calib.setFluxMag0(fluxMag0)
152 def run(self, exposure, dataRef=None):
153 """Scale the specified exposure to the desired photometric zeropoint 155 @param[in,out] exposure: exposure to scale; masked image is scaled in place 156 @param[in] dataRef: dataRef for exposure. 157 Not used, but in API so that users can switch between spatially variant 159 @return a pipeBase.Struct containing: 160 - imageScaler: the image scaling object used to scale exposure 163 mi = exposure.getMaskedImage()
164 imageScaler.scaleMaskedImage(mi)
165 return pipeBase.Struct(
166 imageScaler=imageScaler,
170 """Compute image scaling object for a given exposure. 172 @param[in] exposure: exposure for which scaling is desired 173 @param[in] dataRef: dataRef for exposure. 174 Not used, but in API so that users can switch between spatially variant 183 @return calibration (lsst.afw.image.Calib) with fluxMag0 set appropriately for config.zeroPoint 188 """Compute the scale for the specified Calib 190 Compute scale, such that if pixelCalib describes the photometric zeropoint of a pixel 191 then the following scales that pixel to the photometric zeropoint specified by config.zeroPoint: 192 scale = computeScale(pixelCalib) 195 @return a pipeBase.Struct containing: 196 - scale, as described above. 198 @note: returns a struct to leave room for scaleErr in a future implementation. 200 fluxAtZeroPoint = calib.getFlux(self.config.zeroPoint)
201 return pipeBase.Struct(
202 scale=1.0 / fluxAtZeroPoint,
206 """Compute the scale for the specified fluxMag0 208 This is a wrapper around scaleFromCalib, which see for more information 211 @return a pipeBase.Struct containing: 212 - scale, as described in scaleFromCalib. 214 calib = afwImage.Calib()
215 calib.setFluxMag0(fluxMag0)
220 """Compute spatially varying scale factor to scale exposures to a desired photometric zero point 222 ConfigClass = SpatialScaleZeroPointConfig
223 _DefaultName =
"scaleZeroPoint" 226 ScaleZeroPointTask.__init__(self, *args, **kwargs)
227 self.makeSubtask(
"selectFluxMag0")
229 def run(self, exposure, dataRef):
230 """Scale the specified exposure to the desired photometric zeropoint 232 @param[in,out] exposure: exposure to scale; masked image is scaled in place 233 @param[in] dataRef: dataRef for exposure 235 @return a pipeBase.Struct containing: 236 - imageScaler: the image scaling object used to scale exposure 239 mi = exposure.getMaskedImage()
240 imageScaler.scaleMaskedImage(mi)
241 return pipeBase.Struct(
242 imageScaler=imageScaler,
246 """Compute image scaling object for a given exposure. 248 @param[in] exposure: exposure for which scaling is desired. Only wcs and bbox are used. 249 @param[in] dataRef: dataRef of exposure 250 dataRef.dataId used to retrieve all applicable fluxMag0's from a database. 251 @return a SpatialImageScaler 254 wcs = exposure.getWcs()
256 fluxMagInfoList = self.selectFluxMag0.
run(dataRef.dataId).fluxMagInfoList
262 for fluxMagInfo
in fluxMagInfoList:
264 if not fluxMagInfo.coordList:
265 raise RuntimeError(
"no x,y data for fluxMagInfo")
266 ctr = afwGeom.Extent2D()
267 for coord
in fluxMagInfo.coordList:
269 ctr += afwGeom.Extent2D(wcs.skyToPixel(coord))
271 ctr = afwGeom.Point2D(ctr / len(fluxMagInfo.coordList))
272 xList.append(ctr.getX())
273 yList.append(ctr.getY())
276 self.log.info(
"Found %d flux scales for interpolation: %s" % (len(scaleList),
277 [
"%0.4f"%(s)
for s
in scaleList]))
279 interpStyle=self.config.interpStyle,
def computeImageScaler(self, exposure, dataRef=None)
def getInterpImage(self, bbox)
def scaleMaskedImage(self, maskedImage)
def run(self, exposure, dataRef=None)
def __init__(self, args, kwargs)
def scaleMaskedImage(self, maskedImage)
def run(self, exposure, dataRef)
def __init__(self, scale=1.0)
def computeImageScaler(self, exposure, dataRef)
def __init__(self, args, kwargs)
def scaleFromCalib(self, calib)
def scaleFromFluxMag0(self, fluxMag0)
def __init__(self, interpStyle, xList, yList, scaleList)