23 __all__ = (
"SubtractBackgroundConfig",
"SubtractBackgroundTask")
25 from builtins
import zip
30 from lsstDebug
import getDebugFrame
36 from functools
import reduce
40 """!Config for SubtractBackgroundTask 42 @note Many of these fields match fields in lsst.afw.math.BackgroundControl, 43 the control class for lsst.afw.math.makeBackground 45 statisticsProperty = pexConfig.ChoiceField(
46 doc=
"type of statistic to use for grid points",
47 dtype=str, default=
"MEANCLIP",
49 "MEANCLIP":
"clipped mean",
50 "MEAN":
"unclipped mean",
54 undersampleStyle = pexConfig.ChoiceField(
55 doc=
"behaviour if there are too few points in grid for requested interpolation style",
56 dtype=str, default=
"REDUCE_INTERP_ORDER",
58 "THROW_EXCEPTION":
"throw an exception if there are too few points",
59 "REDUCE_INTERP_ORDER":
"use an interpolation style with a lower order.",
60 "INCREASE_NXNYSAMPLE":
"Increase the number of samples used to make the interpolation grid.",
63 binSize = pexConfig.RangeField(
64 doc=
"how large a region of the sky should be used for each background point",
65 dtype=int, default=128, min=1,
67 binSizeX = pexConfig.RangeField(
68 doc=(
"Sky region size to be used for each background point in X direction. " 69 "If 0, the binSize config is used."),
70 dtype=int, default=0, min=0,
72 binSizeY = pexConfig.RangeField(
73 doc=(
"Sky region size to be used for each background point in Y direction. " 74 "If 0, the binSize config is used."),
75 dtype=int, default=0, min=0,
77 algorithm = pexConfig.ChoiceField(
78 doc=
"how to interpolate the background values. This maps to an enum; see afw::math::Background",
79 dtype=str, default=
"AKIMA_SPLINE", optional=
True,
81 "CONSTANT":
"Use a single constant value",
82 "LINEAR":
"Use linear interpolation",
83 "NATURAL_SPLINE":
"cubic spline with zero second derivative at endpoints",
84 "AKIMA_SPLINE":
"higher-level nonlinear spline that is more robust to outliers",
85 "NONE":
"No background estimation is to be attempted",
88 ignoredPixelMask = pexConfig.ListField(
89 doc=
"Names of mask planes to ignore while estimating the background",
90 dtype=str, default=[
"BAD",
"EDGE",
"DETECTED",
"DETECTED_NEGATIVE",
"NO_DATA", ],
91 itemCheck=
lambda x: x
in afwImage.Mask().getMaskPlaneDict().keys(),
93 isNanSafe = pexConfig.Field(
94 doc=
"Ignore NaNs when estimating the background",
95 dtype=bool, default=
False,
98 useApprox = pexConfig.Field(
99 doc=
"Use Approximate (Chebyshev) to model background.",
100 dtype=bool, default=
True,
102 approxOrderX = pexConfig.Field(
103 doc=
"Approximation order in X for background Chebyshev (valid only with useApprox=True)",
104 dtype=int, default=6,
109 approxOrderY = pexConfig.Field(
110 doc=
"Approximation order in Y for background Chebyshev (valid only with useApprox=True)",
111 dtype=int, default=-1,
113 weighting = pexConfig.Field(
114 doc=
"Use inverse variance weighting in calculation (valid only with useApprox=True)",
115 dtype=bool, default=
True,
127 """!Subtract the background from an exposure 129 @anchor SubtractBackgroundTask_ 131 @section meas_algorithms_subtractBackground_Contents Contents 133 - @ref meas_algorithms_subtractBackground_Purpose 134 - @ref meas_algorithms_subtractBackground_Initialize 135 - @ref meas_algorithms_subtractBackground_IO 136 - @ref meas_algorithms_subtractBackground_Config 137 - @ref meas_algorithms_subtractBackground_Metadata 138 - @ref meas_algorithms_subtractBackground_Debug 139 - @ref meas_algorithms_subtractBackground_Example 141 @section meas_algorithms_subtractBackground_Purpose Description 143 Fit a model of the background of an exposure and subtract it. 145 @section meas_algorithms_subtractBackground_Initialize Task initialisation 147 @copydoc \_\_init\_\_ 149 @section meas_algorithms_subtractBackground_IO Invoking the Task 151 Call `run` to fit the background and subtract it. 153 Call `fitBackground` to fit the background without subtracting it. 155 @section meas_algorithms_subtractBackground_Config Configuration parameters 157 See @ref SubtractBackgroundConfig 159 @section meas_algorithms_subtractBackground_Metadata Quantities set in exposure Metadata 161 The `run` method will optionally set the following items of exposure metadata; 162 the names may be overridden; the defaults are shown: 164 <dt>BGMEAN <dd>mean value of background 165 <dt>BGVAR <dd>standard deviation of background 168 @section meas_algorithms_subtractBackground_Debug Debug variables 170 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag 171 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`. 173 SubtractBackgroundTask has a debug dictionary containing three integer keys: 176 <dd>If >0: `fitBackground` displays the unsubtracted masked image overlaid with the grid of cells 177 used to fit the background in the specified frame 179 <dd>If >0: `run` displays the background-subtracted exposure is the specified frame 181 <dd>If >0: `run` displays the background image in the specified frame 184 For example, put something like: 188 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 189 if name == "lsst.meas.algorithms.subtractBackground": 198 lsstDebug.Info = DebugInfo 200 into your `debug.py` file and run your task with the `--debug` flag. 202 @section meas_algorithms_subtractBackground_Example A complete example of using SubtractBackgroundTask 204 This code is in @link subtractBackgroundExample.py@endlink in the examples directory, and can be run as: 206 python examples/subtractBackgroundExample.py 208 @dontinclude subtractBackgroundExample.py 210 Import the task (there are some other standard imports; read the file if you're curious) 211 @skipline import SubtractBackgroundTask 213 Create the task, run it, and report mean and variance of background. 214 @skip create the task 217 ConfigClass = SubtractBackgroundConfig
218 _DefaultName =
"subtractBackground" 220 def run(self, exposure, background=None, stats=True, statsKeys=None):
221 """!Fit and subtract the background of an exposure 223 @param[in,out] exposure exposure whose background is to be subtracted 224 @param[in,out] background initial background model already subtracted from exposure 225 (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted. 226 @param[in] stats if True then measure the mean and variance of the full background model 227 and record the results in the exposure's metadata 228 @param[in] statsKeys key names used to store the mean and variance of the background 229 in the exposure's metadata (a pair of strings); if None then use ("BGMEAN", "BGVAR"); 230 ignored if stats is false 232 @return an lsst.pipe.base.Struct containing: 233 - background full background model (initial model with changes), an lsst.afw.math.BackgroundList 235 if background
is None:
236 background = afwMath.BackgroundList()
238 maskedImage = exposure.getMaskedImage()
240 maskedImage -= fitBg.getImageF()
241 background.append(fitBg)
244 self.
_addStats(exposure, background, statsKeys=statsKeys)
246 subFrame = getDebugFrame(self._display,
"subtracted")
248 subDisp = afwDisplay.getDisplay(frame=subFrame)
249 subDisp.mtv(exposure, title=
"subtracted")
251 bgFrame = getDebugFrame(self._display,
"background")
253 bgDisp = afwDisplay.getDisplay(frame=bgFrame)
254 bgImage = background.getImage()
255 bgDisp.mtv(bgImage, title=
"background")
257 return pipeBase.Struct(
258 background=background,
261 def _addStats(self, exposure, background, statsKeys=None):
262 """Add statistics about the background to the exposure's metadata 264 @param[in,out] exposure exposure whose background was subtracted 265 @param[in,out] background background model (an lsst.afw.math.BackgroundList) 266 @param[in] statsKeys key names used to store the mean and variance of the background 267 in the exposure's metadata (a pair of strings); if None then use ("BGMEAN", "BGVAR"); 268 ignored if stats is false 270 netBgImg = background.getImage()
271 if statsKeys
is None:
272 statsKeys = (
"BGMEAN",
"BGVAR")
273 mnkey, varkey = statsKeys
274 meta = exposure.getMetadata()
276 bgmean = s.getValue(afwMath.MEAN)
277 bgvar = s.getValue(afwMath.VARIANCE)
278 meta.addDouble(mnkey, bgmean)
279 meta.addDouble(varkey, bgvar)
282 """!Estimate the background of a masked image 284 @param[in] maskedImage masked image whose background is to be computed 285 @param[in] nx number of x bands; if 0 compute from width and config.binSizeX 286 @param[in] ny number of y bands; if 0 compute from height and config.binSizeY 287 @param[in] algorithm name of interpolation algorithm; if None use self.config.algorithm 289 @return fit background as an lsst.afw.math.Background 291 @throw RuntimeError if lsst.afw.math.makeBackground returns None, 292 which is apparently one way it indicates failure 295 binSizeX = self.config.binSize
if self.config.binSizeX == 0
else self.config.binSizeX
296 binSizeY = self.config.binSize
if self.config.binSizeY == 0
else self.config.binSizeY
299 nx = maskedImage.getWidth()//binSizeX + 1
301 ny = maskedImage.getHeight()//binSizeY + 1
303 unsubFrame = getDebugFrame(self._display,
"unsubtracted")
305 unsubDisp = afwDisplay.getDisplay(frame=unsubFrame)
306 unsubDisp.mtv(maskedImage, title=
"unsubtracted")
307 xPosts = numpy.rint(numpy.linspace(0, maskedImage.getWidth() + 1, num=nx, endpoint=
True))
308 yPosts = numpy.rint(numpy.linspace(0, maskedImage.getHeight() + 1, num=ny, endpoint=
True))
309 with unsubDisp.Buffering():
310 for (xMin, xMax), (yMin, yMax)
in itertools.product(zip(xPosts[:-1], xPosts[1:]),
311 zip(yPosts[:-1], yPosts[1:])):
312 unsubDisp.line([(xMin, yMin), (xMin, yMax), (xMax, yMax), (xMax, yMin), (xMin, yMin)])
315 sctrl.setAndMask(reduce(
lambda x, y: x | maskedImage.getMask().getPlaneBitMask(y),
316 self.config.ignoredPixelMask, 0x0))
317 sctrl.setNanSafe(self.config.isNanSafe)
319 self.log.debug(
"Ignoring mask planes: %s" %
", ".join(self.config.ignoredPixelMask))
321 if algorithm
is None:
322 algorithm = self.config.algorithm
325 self.config.undersampleStyle, sctrl,
326 self.config.statisticsProperty)
340 if self.config.useApprox:
341 if self.config.approxOrderY
not in (self.config.approxOrderX, -1):
342 raise ValueError(
"Error: approxOrderY not in (approxOrderX, -1)")
343 order = self.config.approxOrderX
344 minNumberGridPoints = order + 1
345 if min(nx, ny) <= order:
346 self.log.warn(
"Too few points in grid to constrain fit: min(nx, ny) < approxOrder) " 347 "[min(%d, %d) < %d]" % (nx, ny, order))
348 if self.config.undersampleStyle ==
"THROW_EXCEPTION":
349 raise ValueError(
"Too few points in grid (%d, %d) for order (%d) and binSize (%d, %d)" %
350 (nx, ny, order, binSizeX, binSizeY))
351 elif self.config.undersampleStyle ==
"REDUCE_INTERP_ORDER":
353 raise ValueError(
"Cannot reduce approxOrder below 0. " +
354 "Try using undersampleStyle = \"INCREASE_NXNYSAMPLE\" instead?")
355 order = min(nx, ny) - 1
356 self.log.warn(
"Reducing approxOrder to %d" % order)
357 elif self.config.undersampleStyle ==
"INCREASE_NXNYSAMPLE":
359 newBinSize = min(maskedImage.getWidth(), maskedImage.getHeight())//(minNumberGridPoints-1)
361 raise ValueError(
"Binsize must be greater than 0")
362 newNx = maskedImage.getWidth()//newBinSize + 1
363 newNy = maskedImage.getHeight()//newBinSize + 1
364 bctrl.setNxSample(newNx)
365 bctrl.setNySample(newNy)
366 self.log.warn(
"Decreasing binSize from (%d, %d) to %d for a grid of (%d, %d)" %
367 (binSizeX, binSizeY, newBinSize, newNx, newNy))
370 self.config.weighting)
371 bctrl.setApproximateControl(actrl)
375 raise RuntimeError(
"lsst.afw.math.makeBackground failed to fit a background model")
def _addStats(self, exposure, background, statsKeys=None)
def fitBackground(self, maskedImage, nx=0, ny=0, algorithm=None)
Estimate the background of a masked image.
std::shared_ptr< Background > makeBackground(ImageT const &img, BackgroundControl const &bgCtrl)
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Config for SubtractBackgroundTask.
Subtract the background from an exposure.
def run(self, exposure, background=None, stats=True, statsKeys=None)
Fit and subtract the background of an exposure.