1 from builtins
import zip
27 from lsstDebug
import getDebugFrame
33 from functools
import reduce
35 __all__ = (
"SubtractBackgroundConfig",
"SubtractBackgroundTask")
39 """!Config for SubtractBackgroundTask
41 @note Many of these fields match fields in lsst.afw.math.BackgroundControl,
42 the control class for lsst.afw.math.makeBackground
44 statisticsProperty = pexConfig.ChoiceField(
45 doc=
"type of statistic to use for grid points",
46 dtype=str, default=
"MEANCLIP",
48 "MEANCLIP":
"clipped mean",
49 "MEAN":
"unclipped mean",
53 undersampleStyle = pexConfig.ChoiceField(
54 doc=
"behaviour if there are too few points in grid for requested interpolation style",
55 dtype=str, default=
"REDUCE_INTERP_ORDER",
57 "THROW_EXCEPTION":
"throw an exception if there are too few points",
58 "REDUCE_INTERP_ORDER":
"use an interpolation style with a lower order.",
59 "INCREASE_NXNYSAMPLE":
"Increase the number of samples used to make the interpolation grid.",
62 binSize = pexConfig.RangeField(
63 doc=
"how large a region of the sky should be used for each background point",
64 dtype=int, default=128, min=1,
66 algorithm = pexConfig.ChoiceField(
67 doc=
"how to interpolate the background values. This maps to an enum; see afw::math::Background",
68 dtype=str, default=
"NATURAL_SPLINE", optional=
True,
70 "CONSTANT":
"Use a single constant value",
71 "LINEAR":
"Use linear interpolation",
72 "NATURAL_SPLINE":
"cubic spline with zero second derivative at endpoints",
73 "AKIMA_SPLINE":
"higher-level nonlinear spline that is more robust to outliers",
74 "NONE":
"No background estimation is to be attempted",
77 ignoredPixelMask = pexConfig.ListField(
78 doc=
"Names of mask planes to ignore while estimating the background",
79 dtype=str, default=[
"BAD",
"EDGE",
"DETECTED",
"DETECTED_NEGATIVE",
"NO_DATA", ],
80 itemCheck=
lambda x: x
in afwImage.MaskU().getMaskPlaneDict().keys(),
82 isNanSafe = pexConfig.Field(
83 doc=
"Ignore NaNs when estimating the background",
84 dtype=bool, default=
False,
87 useApprox = pexConfig.Field(
88 doc=
"Use Approximate (Chebyshev) to model background.",
89 dtype=bool, default=
True,
91 approxOrderX = pexConfig.Field(
92 doc=
"Approximation order in X for background Chebyshev (valid only with useApprox=True)",
98 approxOrderY = pexConfig.Field(
99 doc=
"Approximation order in Y for background Chebyshev (valid only with useApprox=True)",
100 dtype=int, default=-1,
102 weighting = pexConfig.Field(
103 doc=
"Use inverse variance weighting in calculation (valid only with useApprox=True)",
104 dtype=bool, default=
True,
116 """!Subtract the background from an exposure
118 @anchor SubtractBackgroundTask_
120 @section meas_algorithms_subtractBackground_Contents Contents
122 - @ref meas_algorithms_subtractBackground_Purpose
123 - @ref meas_algorithms_subtractBackground_Initialize
124 - @ref meas_algorithms_subtractBackground_IO
125 - @ref meas_algorithms_subtractBackground_Config
126 - @ref meas_algorithms_subtractBackground_Metadata
127 - @ref meas_algorithms_subtractBackground_Debug
128 - @ref meas_algorithms_subtractBackground_Example
130 @section meas_algorithms_subtractBackground_Purpose Description
132 Fit a model of the background of an exposure and subtract it.
134 @section meas_algorithms_subtractBackground_Initialize Task initialisation
136 @copydoc \_\_init\_\_
138 @section meas_algorithms_subtractBackground_IO Invoking the Task
140 Call `run` to fit the background and subtract it.
142 Call `fitBackground` to fit the background without subtracting it.
144 @section meas_algorithms_subtractBackground_Config Configuration parameters
146 See @ref SubtractBackgroundConfig
148 @section meas_algorithms_subtractBackground_Metadata Quantities set in exposure Metadata
150 The `run` method will optionally set the following items of exposure metadata;
151 the names may be overridden; the defaults are shown:
153 <dt>BGMEAN <dd>mean value of background
154 <dt>BGVAR <dd>standard deviation of background
157 @section meas_algorithms_subtractBackground_Debug Debug variables
159 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag
160 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`.
162 SubtractBackgroundTask has a debug dictionary containing three integer keys:
165 <dd>If >0: `fitBackground` displays the unsubtracted masked image overlaid with the grid of cells
166 used to fit the background in the specified frame
168 <dd>If >0: `run` displays the background-subtracted exposure is the specified frame
170 <dd>If >0: `run` displays the background image in the specified frame
173 For example, put something like:
177 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
178 if name == "lsst.meas.algorithms.subtractBackground":
187 lsstDebug.Info = DebugInfo
189 into your `debug.py` file and run your task with the `--debug` flag.
191 @section meas_algorithms_subtractBackground_Example A complete example of using SubtractBackgroundTask
193 This code is in @link subtractBackgroundExample.py@endlink in the examples directory, and can be run as:
195 python examples/subtractBackgroundExample.py
197 @dontinclude subtractBackgroundExample.py
199 Import the task (there are some other standard imports; read the file if you're curious)
200 @skipline import SubtractBackgroundTask
202 Create the task, run it, and report mean and variance of background.
203 @skip create the task
206 ConfigClass = SubtractBackgroundConfig
207 _DefaultName =
"subtractBackground"
209 def run(self, exposure, background=None, stats=True, statsKeys=None):
210 """!Fit and subtract the background of an exposure
212 @param[in,out] exposure exposure whose background is to be subtracted
213 @param[in,out] background initial background model already subtracted from exposure
214 (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted.
215 @param[in] stats if True then measure the mean and variance of the full background model
216 and record the results in the exposure's metadata
217 @param[in] statsKeys key names used to store the mean and variance of the background
218 in the exposure's metadata (a pair of strings); if None then use ("BGMEAN", "BGVAR");
219 ignored if stats is false
221 @return an lsst.pipe.base.Struct containing:
222 - background full background model (initial model with changes), an lsst.afw.math.BackgroundList
224 if background
is None:
225 background = afwMath.BackgroundList()
227 maskedImage = exposure.getMaskedImage()
229 maskedImage -= fitBg.getImageF()
230 background.append(fitBg)
233 self.
_addStats(exposure, background, statsKeys=statsKeys)
237 subDisp = afwDisplay.getDisplay(frame=subFrame)
238 subDisp.mtv(exposure, title=
"subtracted")
242 bgDisp = afwDisplay.getDisplay(frame=bgFrame)
243 bgImage = background.getImage()
244 bgDisp.mtv(bgImage, title=
"background")
246 return pipeBase.Struct(
247 background=background,
250 def _addStats(self, exposure, background, statsKeys=None):
251 """Add statistics about the background to the exposure's metadata
253 @param[in,out] exposure exposure whose background was subtracted
254 @param[in,out] background background model (an lsst.afw.math.BackgroundList)
255 @param[in] statsKeys key names used to store the mean and variance of the background
256 in the exposure's metadata (a pair of strings); if None then use ("BGMEAN", "BGVAR");
257 ignored if stats is false
259 netBgImg = background.getImage()
260 if statsKeys
is None:
261 statsKeys = (
"BGMEAN",
"BGVAR")
262 mnkey, varkey = statsKeys
263 meta = exposure.getMetadata()
265 bgmean = s.getValue(afwMath.MEAN)
266 bgvar = s.getValue(afwMath.VARIANCE)
267 meta.addDouble(mnkey, bgmean)
268 meta.addDouble(varkey, bgvar)
271 """!Estimate the background of a masked image
273 @param[in] maskedImage masked image whose background is to be computed
274 @param[in] nx number of x bands; if 0 compute from width and config.binSize
275 @param[in] ny number of y bands; if 0 compute from height and config.binSize
276 @param[in] algorithm name of interpolation algorithm; if None use self.config.algorithm
278 @return fit background as an lsst.afw.math.Background
280 @throw RuntimeError if lsst.afw.math.makeBackground returns None,
281 which is apparently one way it indicates failure
284 nx = maskedImage.getWidth()//self.config.binSize + 1
286 ny = maskedImage.getHeight()//self.config.binSize + 1
290 unsubDisp = afwDisplay.getDisplay(frame=unsubFrame)
291 unsubDisp.mtv(maskedImage, title=
"unsubtracted")
292 xPosts = numpy.rint(numpy.linspace(0, maskedImage.getWidth() + 1, num=nx, endpoint=
True))
293 yPosts = numpy.rint(numpy.linspace(0, maskedImage.getHeight() + 1, num=ny, endpoint=
True))
294 with unsubDisp.Buffering():
295 for (xMin, xMax), (yMin, yMax)
in itertools.product(zip(xPosts[:-1], xPosts[1:]),
296 zip(yPosts[:-1], yPosts[1:])):
297 unsubDisp.line([(xMin, yMin), (xMin, yMax), (xMax, yMax), (xMax, yMin), (xMin, yMin)])
300 sctrl.setAndMask(reduce(
lambda x, y: x | maskedImage.getMask().getPlaneBitMask(y),
301 self.config.ignoredPixelMask, 0x0))
302 sctrl.setNanSafe(self.config.isNanSafe)
304 self.log.debug(
"Ignoring mask planes: %s" %
", ".join(self.config.ignoredPixelMask))
306 if algorithm
is None:
307 algorithm = self.config.algorithm
310 self.config.undersampleStyle, sctrl,
311 self.config.statisticsProperty)
325 if self.config.useApprox:
326 if self.config.approxOrderY
not in (self.config.approxOrderX, -1):
327 raise ValueError(
"Error: approxOrderY not in (approxOrderX, -1)")
328 order = self.config.approxOrderX
329 minNumberGridPoints = self.config.approxOrderX + 1
330 if min(nx, ny) <= self.config.approxOrderX:
331 self.log.warn(
"Too few points in grid to constrain fit: min(nx, ny) < approxOrder) "
332 "[min(%d, %d) < %d]" % (nx, ny, self.config.approxOrderX))
333 if self.config.undersampleStyle ==
"THROW_EXCEPTION":
334 raise ValueError(
"Too few points in grid (%d, %d) for order (%d) and binsize (%d)" % (
335 nx, ny, self.config.approxOrderX, self.config.binSize))
336 elif self.config.undersampleStyle ==
"REDUCE_INTERP_ORDER":
338 raise ValueError(
"Cannot reduce approxOrder below 0. " +
339 "Try using undersampleStyle = \"INCREASE_NXNYSAMPLE\" instead?")
340 order = min(nx, ny) - 1
341 self.log.warn(
"Reducing approxOrder to %d" % order)
342 elif self.config.undersampleStyle ==
"INCREASE_NXNYSAMPLE":
343 newBinSize = min(maskedImage.getWidth(), maskedImage.getHeight())//(minNumberGridPoints-1)
345 raise ValueError(
"Binsize must be greater than 0")
346 newNx = maskedImage.getWidth()//newBinSize + 1
347 newNy = maskedImage.getHeight()//newBinSize + 1
348 bctrl.setNxSample(newNx)
349 bctrl.setNySample(newNy)
350 self.log.warn(
"Decreasing binSize from %d to %d for a grid of (%d, %d)" %
351 (self.config.binSize, newBinSize, newNx, newNy))
354 self.config.weighting)
355 bctrl.setApproximateControl(actrl)
359 raise RuntimeError(
"lsst.afw.math.makeBackground failed to fit a background model")
boost::shared_ptr< Background > makeBackground(ImageT const &img, BackgroundControl const &bgCtrl)
A convenience function that uses function overloading to make the correct type of Background...
Pass parameters to a Background object.
Control how to make an approximation.
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Config for SubtractBackgroundTask.
def run
Fit and subtract the background of an exposure.
Subtract the background from an exposure.
def fitBackground
Estimate the background of a masked image.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.