178 def run(self, exposure, background=None, stats=True, statsKeys=None, backgroundToPhotometricRatio=None):
179 """Fit and subtract the background of an exposure.
183 exposure : `lsst.afw.image.Exposure`
184 Exposure whose background is to be subtracted.
185 background : `lsst.afw.math.BackgroundList`
186 Initial background model already subtracted. May be None if no background
189 If True then measure the mean and variance of the full background model and
190 record the results in the exposure's metadata.
192 Key names used to store the mean and variance of the background in the
193 exposure's metadata (another tuple); if None then use ("BGMEAN", "BGVAR");
194 ignored if stats is false.
195 backgroundToPhotometricRatio : `lsst.afw.image.Image`, optional
196 Image to multiply a photometrically-flattened image by to obtain a
197 background-flattened image.
198 Only used if config.doApplyFlatBackgroundRatio = True.
202 background : `lsst.afw.math.BackgroundList`
203 Full background model (initial model with changes), contained in an
204 `lsst.pipe.base.Struct`.
206 if background
is None:
209 maskedImage = exposure.maskedImage
213 self.config.doApplyFlatBackgroundRatio,
214 backgroundToPhotometricRatio=backgroundToPhotometricRatio,
217 maskedImage -= fitBg.getImageF(self.config.algorithm, self.config.undersampleStyle)
219 actrl = fitBg.getBackgroundControl().getApproximateControl()
221 fitBg.getAsUsedUndersampleStyle(), actrl.getStyle(),
222 actrl.getOrderX(), actrl.getOrderY(), actrl.getWeighting()))
225 self.
_addStats(exposure, background, statsKeys=statsKeys)
227 subFrame = getDebugFrame(self._display,
"subtracted")
229 subDisp = afwDisplay.getDisplay(frame=subFrame)
230 subDisp.mtv(exposure, title=
"subtracted")
232 bgFrame = getDebugFrame(self._display,
"background")
234 bgDisp = afwDisplay.getDisplay(frame=bgFrame)
235 bgImage = background.getImage()
236 bgDisp.mtv(bgImage, title=
"background")
238 return pipeBase.Struct(
239 background=background,
242 def _addStats(self, exposure, background, statsKeys=None):
243 """Add statistics about the background to the exposure's metadata
247 exposure : `lsst.afw.image.Exposure`
248 Exposure whose background was subtracted.
249 background : `lsst.afw.math.BackgroundList`
252 Key names used to store the mean and variance of the background in
253 the exposure's metadata (a tuple); if None then use
254 ("BGMEAN", "BGVAR"); ignored if stats is false.
256 netBgImg = background.getImage()
257 if statsKeys
is None:
258 statsKeys = (
"BGMEAN",
"BGVAR")
259 mnkey, varkey = statsKeys
260 meta = exposure.getMetadata()
262 bgmean = s.getValue(afwMath.MEAN)
263 bgvar = s.getValue(afwMath.VARIANCE)
264 meta.addDouble(mnkey, bgmean)
265 meta.addDouble(varkey, bgvar)
268 """Estimate the background of a masked image
272 maskedImage : `lsst.afw.image.maskedImage`
273 Masked image whose background is to be computed
275 Number of x bands; if 0 compute from width and `self.config.binSizeX`
277 Number of y bands; if 0 compute from height and `self.config.binSizeY`
279 Name of interpolation algorithm; if None use `self.config.algorithm`
283 bg : `lsst.afw.math.Background`
289 Raised if lsst.afw.math.makeBackground returns None, an indicator
293 binSizeX = self.config.binSize
if self.config.binSizeX == 0
else self.config.binSizeX
294 binSizeY = self.config.binSize
if self.config.binSizeY == 0
else self.config.binSizeY
297 nx = maskedImage.getWidth()//binSizeX + 1
299 ny = maskedImage.getHeight()//binSizeY + 1
301 unsubFrame = getDebugFrame(self._display,
"unsubtracted")
303 unsubDisp = afwDisplay.getDisplay(frame=unsubFrame)
304 unsubDisp.mtv(maskedImage, title=
"unsubtracted")
305 xPosts = numpy.rint(numpy.linspace(0, maskedImage.getWidth() + 1, num=nx, endpoint=
True))
306 yPosts = numpy.rint(numpy.linspace(0, maskedImage.getHeight() + 1, num=ny, endpoint=
True))
307 with unsubDisp.Buffering():
308 for (xMin, xMax), (yMin, yMax)
in itertools.product(zip(xPosts[:-1], xPosts[1:]),
309 zip(yPosts[:-1], yPosts[1:])):
310 unsubDisp.line([(xMin, yMin), (xMin, yMax), (xMax, yMax), (xMax, yMin), (xMin, yMin)])
313 badMask = maskedImage.mask.getPlaneBitMask(self.config.ignoredPixelMask)
315 sctrl.setAndMask(badMask)
316 sctrl.setNanSafe(self.config.isNanSafe)
318 self.log.debug(
"Ignoring mask planes: %s",
", ".join(self.config.ignoredPixelMask))
319 if (maskedImage.mask.getArray() & badMask).all():
320 raise pipeBase.TaskError(
"All pixels masked. Cannot estimate background")
322 if algorithm
is None:
323 algorithm = self.config.algorithm
331 with suppress_deprecations():
333 self.config.undersampleStyle, sctrl,
334 self.config.statisticsProperty)
348 if self.config.useApprox:
349 if self.config.approxOrderY
not in (self.config.approxOrderX, -1):
350 raise ValueError(
"Error: approxOrderY not in (approxOrderX, -1)")
351 order = self.config.approxOrderX
352 minNumberGridPoints = order + 1
353 if min(nx, ny) <= order:
354 self.log.warning(
"Too few points in grid to constrain fit: min(nx, ny) < approxOrder) "
355 "[min(%d, %d) < %d]", nx, ny, order)
356 if self.config.undersampleStyle ==
"THROW_EXCEPTION":
357 raise ValueError(
"Too few points in grid (%d, %d) for order (%d) and binSize (%d, %d)" %
358 (nx, ny, order, binSizeX, binSizeY))
359 elif self.config.undersampleStyle ==
"REDUCE_INTERP_ORDER":
361 raise ValueError(
"Cannot reduce approxOrder below 0. "
362 "Try using undersampleStyle = \"INCREASE_NXNYSAMPLE\" instead?")
363 order = min(nx, ny) - 1
364 self.log.warning(
"Reducing approxOrder to %d", order)
365 elif self.config.undersampleStyle ==
"INCREASE_NXNYSAMPLE":
367 newBinSize = min(maskedImage.getWidth(), maskedImage.getHeight())//(minNumberGridPoints-1)
369 raise ValueError(
"Binsize must be greater than 0")
370 newNx = maskedImage.getWidth()//newBinSize + 1
371 newNy = maskedImage.getHeight()//newBinSize + 1
372 bctrl.setNxSample(newNx)
373 bctrl.setNySample(newNy)
374 self.log.warning(
"Decreasing binSize from (%d, %d) to %d for a grid of (%d, %d)",
375 binSizeX, binSizeY, newBinSize, newNx, newNy)
378 self.config.weighting)
379 bctrl.setApproximateControl(actrl)
383 raise RuntimeError(
"lsst.afw.math.makeBackground failed to fit a background model")