23 __all__ = (
"SubtractBackgroundConfig",
"SubtractBackgroundTask")
29 from lsstDebug
import getDebugFrame
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", ],
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 r"""!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:
238 maskedImage = exposure.getMaskedImage()
240 maskedImage -= fitBg.getImageF(self.config.algorithm, self.config.undersampleStyle)
242 actrl = fitBg.getBackgroundControl().getApproximateControl()
244 fitBg.getAsUsedUndersampleStyle(), actrl.getStyle(),
245 actrl.getOrderX(), actrl.getOrderY(), actrl.getWeighting()))
248 self.
_addStats_addStats(exposure, background, statsKeys=statsKeys)
252 subDisp = afwDisplay.getDisplay(frame=subFrame)
253 subDisp.mtv(exposure, title=
"subtracted")
257 bgDisp = afwDisplay.getDisplay(frame=bgFrame)
258 bgImage = background.getImage()
259 bgDisp.mtv(bgImage, title=
"background")
261 return pipeBase.Struct(
262 background=background,
265 def _addStats(self, exposure, background, statsKeys=None):
266 """Add statistics about the background to the exposure's metadata
268 @param[in,out] exposure exposure whose background was subtracted
269 @param[in,out] background background model (an lsst.afw.math.BackgroundList)
270 @param[in] statsKeys key names used to store the mean and variance of the background
271 in the exposure's metadata (a pair of strings); if None then use ("BGMEAN", "BGVAR");
272 ignored if stats is false
274 netBgImg = background.getImage()
275 if statsKeys
is None:
276 statsKeys = (
"BGMEAN",
"BGVAR")
277 mnkey, varkey = statsKeys
278 meta = exposure.getMetadata()
280 bgmean = s.getValue(afwMath.MEAN)
281 bgvar = s.getValue(afwMath.VARIANCE)
282 meta.addDouble(mnkey, bgmean)
283 meta.addDouble(varkey, bgvar)
286 """!Estimate the background of a masked image
288 @param[in] maskedImage masked image whose background is to be computed
289 @param[in] nx number of x bands; if 0 compute from width and config.binSizeX
290 @param[in] ny number of y bands; if 0 compute from height and config.binSizeY
291 @param[in] algorithm name of interpolation algorithm; if None use self.config.algorithm
293 @return fit background as an lsst.afw.math.Background
295 @throw RuntimeError if lsst.afw.math.makeBackground returns None,
296 which is apparently one way it indicates failure
299 binSizeX = self.config.binSize
if self.config.binSizeX == 0
else self.config.binSizeX
300 binSizeY = self.config.binSize
if self.config.binSizeY == 0
else self.config.binSizeY
303 nx = maskedImage.getWidth()//binSizeX + 1
305 ny = maskedImage.getHeight()//binSizeY + 1
309 unsubDisp = afwDisplay.getDisplay(frame=unsubFrame)
310 unsubDisp.mtv(maskedImage, title=
"unsubtracted")
311 xPosts = numpy.rint(numpy.linspace(0, maskedImage.getWidth() + 1, num=nx, endpoint=
True))
312 yPosts = numpy.rint(numpy.linspace(0, maskedImage.getHeight() + 1, num=ny, endpoint=
True))
313 with unsubDisp.Buffering():
314 for (xMin, xMax), (yMin, yMax)
in itertools.product(zip(xPosts[:-1], xPosts[1:]),
315 zip(yPosts[:-1], yPosts[1:])):
316 unsubDisp.line([(xMin, yMin), (xMin, yMax), (xMax, yMax), (xMax, yMin), (xMin, yMin)])
319 badMask = maskedImage.mask.getPlaneBitMask(self.config.ignoredPixelMask)
321 sctrl.setAndMask(badMask)
322 sctrl.setNanSafe(self.config.isNanSafe)
324 self.log.
debug(
"Ignoring mask planes: %s" %
", ".join(self.config.ignoredPixelMask))
325 if (maskedImage.mask.getArray() & badMask).
all():
326 raise pipeBase.TaskError(
"All pixels masked. Cannot estimate background")
328 if algorithm
is None:
329 algorithm = self.config.algorithm
339 self.config.undersampleStyle, sctrl,
340 self.config.statisticsProperty)
354 if self.config.useApprox:
355 if self.config.approxOrderY
not in (self.config.approxOrderX, -1):
356 raise ValueError(
"Error: approxOrderY not in (approxOrderX, -1)")
357 order = self.config.approxOrderX
358 minNumberGridPoints = order + 1
359 if min(nx, ny) <= order:
360 self.log.
warn(
"Too few points in grid to constrain fit: min(nx, ny) < approxOrder) "
361 "[min(%d, %d) < %d]" % (nx, ny, order))
362 if self.config.undersampleStyle ==
"THROW_EXCEPTION":
363 raise ValueError(
"Too few points in grid (%d, %d) for order (%d) and binSize (%d, %d)" %
364 (nx, ny, order, binSizeX, binSizeY))
365 elif self.config.undersampleStyle ==
"REDUCE_INTERP_ORDER":
367 raise ValueError(
"Cannot reduce approxOrder below 0. "
368 "Try using undersampleStyle = \"INCREASE_NXNYSAMPLE\" instead?")
369 order =
min(nx, ny) - 1
370 self.log.
warn(
"Reducing approxOrder to %d" % order)
371 elif self.config.undersampleStyle ==
"INCREASE_NXNYSAMPLE":
373 newBinSize =
min(maskedImage.getWidth(), maskedImage.getHeight())//(minNumberGridPoints-1)
375 raise ValueError(
"Binsize must be greater than 0")
376 newNx = maskedImage.getWidth()//newBinSize + 1
377 newNy = maskedImage.getHeight()//newBinSize + 1
378 bctrl.setNxSample(newNx)
379 bctrl.setNySample(newNy)
380 self.log.
warn(
"Decreasing binSize from (%d, %d) to %d for a grid of (%d, %d)" %
381 (binSizeX, binSizeY, newBinSize, newNx, newNy))
384 self.config.weighting)
385 bctrl.setApproximateControl(actrl)
389 raise RuntimeError(
"lsst.afw.math.makeBackground failed to fit a background model")
Represent a 2-dimensional array of bitmask pixels.
Control how to make an approximation.
Pass parameters to a Background object.
Pass parameters to a Statistics object.
Config for SubtractBackgroundTask.
Subtract the background from an exposure.
def fitBackground(self, maskedImage, nx=0, ny=0, algorithm=None)
Estimate the background of a masked image.
def run(self, exposure, background=None, stats=True, statsKeys=None)
Fit and subtract the background of an exposure.
def _addStats(self, exposure, background, statsKeys=None)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
std::shared_ptr< Background > makeBackground(ImageT const &img, BackgroundControl const &bgCtrl)
A convenience function that uses function overloading to make the correct type of Background.
bool all(CoordinateExpr< N > const &expr) noexcept
Return true if all elements are true.
def suppress_deprecations(category=FutureWarning)
def getDebugFrame(debugDisplay, name)