LSSTApplications  17.0+124,17.0+14,17.0+73,18.0.0+37,18.0.0+80,18.0.0-4-g68ffd23+4,18.1.0-1-g0001055+12,18.1.0-1-g03d53ef+5,18.1.0-1-g1349e88+55,18.1.0-1-g2505f39+44,18.1.0-1-g5315e5e+4,18.1.0-1-g5e4b7ea+14,18.1.0-1-g7e8fceb+4,18.1.0-1-g85f8cd4+48,18.1.0-1-g8ff0b9f+4,18.1.0-1-ga2c679d+1,18.1.0-1-gd55f500+35,18.1.0-10-gb58edde+2,18.1.0-11-g0997b02+4,18.1.0-13-gfe4edf0b+12,18.1.0-14-g259bd21+21,18.1.0-19-gdb69f3f+2,18.1.0-2-g5f9922c+24,18.1.0-2-gd3b74e5+11,18.1.0-2-gfbf3545+32,18.1.0-26-g728bddb4+5,18.1.0-27-g6ff7ca9+2,18.1.0-3-g52aa583+25,18.1.0-3-g8ea57af+9,18.1.0-3-gb69f684+42,18.1.0-3-gfcaddf3+6,18.1.0-32-gd8786685a,18.1.0-4-gf3f9b77+6,18.1.0-5-g1dd662b+2,18.1.0-5-g6dbcb01+41,18.1.0-6-gae77429+3,18.1.0-7-g9d75d83+9,18.1.0-7-gae09a6d+30,18.1.0-9-gc381ef5+4,w.2019.45
LSSTDataManagementBasePackage
Classes | Functions
lsst.meas.deblender.plugins Namespace Reference

Classes

class  DeblenderPlugin
 

Functions

def clipFootprintToNonzeroImpl (foot, image)
 
def buildMultibandTemplates (debResult, log, useWeights=False, usePsf=False, sources=None, constraints=None, config=None, maxIter=100, bgScale=0.5, relativeError=1e-2, badMask=None)
 
def fitPsfs (debResult, log, psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, tinyFootprintSize=2)
 
def buildSymmetricTemplates (debResult, log, patchEdges=False, setOrigTemplate=True)
 
def rampFluxAtEdge (debResult, log, patchEdges=False)
 
def medianSmoothTemplates (debResult, log, medianFilterHalfsize=2)
 
def makeTemplatesMonotonic (debResult, log)
 
def clipFootprintsToNonzero (debResult, log)
 
def weightTemplates (debResult, log)
 
def reconstructTemplates (debResult, log, maxTempDotProd=0.5)
 
def apportionFlux (debResult, log, assignStrayFlux=True, strayFluxAssignment='r-to-peak', strayFluxToPointSources='necessary', clipStrayFluxFraction=0.001, getTemplateSum=False)
 

Function Documentation

◆ apportionFlux()

def lsst.meas.deblender.plugins.apportionFlux (   debResult,
  log,
  assignStrayFlux = True,
  strayFluxAssignment = 'r-to-peak',
  strayFluxToPointSources = 'necessary',
  clipStrayFluxFraction = 0.001,
  getTemplateSum = False 
)
Apportion flux to all of the peak templates in each filter

Divide the ``maskedImage`` flux amongst all of the templates based on the fraction of
flux assigned to each ``template``.
Leftover "stray flux" is assigned to peaks based on the other parameters.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
assignStrayFlux: `bool`, optional
    If True then flux in the parent footprint that is not covered by any of the
    template footprints is assigned to templates based on their 1/(1+r^2) distance.
    How the flux is apportioned is determined by ``strayFluxAssignment``.
strayFluxAssignment: `string`, optional
    Determines how stray flux is apportioned.
    * ``trim``: Trim stray flux and do not include in any footprints
    * ``r-to-peak`` (default): Stray flux is assigned based on (1/(1+r^2) from the peaks
    * ``r-to-footprint``: Stray flux is distributed to the footprints based on 1/(1+r^2) of the
      minimum distance from the stray flux to footprint
    * ``nearest-footprint``: Stray flux is assigned to the footprint with lowest L-1 (Manhattan)
      distance to the stray flux
strayFluxToPointSources: `string`, optional
    Determines how stray flux is apportioned to point sources
    * ``never``: never apportion stray flux to point sources
    * ``necessary`` (default): point sources are included only if there are no extended sources nearby
    * ``always``: point sources are always included in the 1/(1+r^2) splitting
clipStrayFluxFraction: `float`, optional
    Minimum stray-flux portion.
    Any stray-flux portion less than ``clipStrayFluxFraction`` is clipped to zero.
getTemplateSum: `bool`, optional
    As part of the flux calculation, the sum of the templates is calculated.
    If ``getTemplateSum==True`` then the sum of the templates is stored in the result
    (a `DeblendedFootprint`).

Returns
-------
modified: `bool`
    Apportion flux always modifies the templates, so ``modified`` is always ``True``.
    However, this should likely be the final step and it is unlikely that
    any deblender plugins will be re-run.

Definition at line 1399 of file plugins.py.

1399  getTemplateSum=False):
1400  """Apportion flux to all of the peak templates in each filter
1401 
1402  Divide the ``maskedImage`` flux amongst all of the templates based on the fraction of
1403  flux assigned to each ``template``.
1404  Leftover "stray flux" is assigned to peaks based on the other parameters.
1405 
1406  Parameters
1407  ----------
1408  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1409  Container for the final deblender results.
1410  log: `log.Log`
1411  LSST logger for logging purposes.
1412  assignStrayFlux: `bool`, optional
1413  If True then flux in the parent footprint that is not covered by any of the
1414  template footprints is assigned to templates based on their 1/(1+r^2) distance.
1415  How the flux is apportioned is determined by ``strayFluxAssignment``.
1416  strayFluxAssignment: `string`, optional
1417  Determines how stray flux is apportioned.
1418  * ``trim``: Trim stray flux and do not include in any footprints
1419  * ``r-to-peak`` (default): Stray flux is assigned based on (1/(1+r^2) from the peaks
1420  * ``r-to-footprint``: Stray flux is distributed to the footprints based on 1/(1+r^2) of the
1421  minimum distance from the stray flux to footprint
1422  * ``nearest-footprint``: Stray flux is assigned to the footprint with lowest L-1 (Manhattan)
1423  distance to the stray flux
1424  strayFluxToPointSources: `string`, optional
1425  Determines how stray flux is apportioned to point sources
1426  * ``never``: never apportion stray flux to point sources
1427  * ``necessary`` (default): point sources are included only if there are no extended sources nearby
1428  * ``always``: point sources are always included in the 1/(1+r^2) splitting
1429  clipStrayFluxFraction: `float`, optional
1430  Minimum stray-flux portion.
1431  Any stray-flux portion less than ``clipStrayFluxFraction`` is clipped to zero.
1432  getTemplateSum: `bool`, optional
1433  As part of the flux calculation, the sum of the templates is calculated.
1434  If ``getTemplateSum==True`` then the sum of the templates is stored in the result
1435  (a `DeblendedFootprint`).
1436 
1437  Returns
1438  -------
1439  modified: `bool`
1440  Apportion flux always modifies the templates, so ``modified`` is always ``True``.
1441  However, this should likely be the final step and it is unlikely that
1442  any deblender plugins will be re-run.
1443  """
1444  validStrayPtSrc = ['never', 'necessary', 'always']
1445  validStrayAssign = ['r-to-peak', 'r-to-footprint', 'nearest-footprint', 'trim']
1446  if strayFluxToPointSources not in validStrayPtSrc:
1447  raise ValueError((('strayFluxToPointSources: value \"%s\" not in the set of allowed values: ') %
1448  strayFluxToPointSources) + str(validStrayPtSrc))
1449  if strayFluxAssignment not in validStrayAssign:
1450  raise ValueError((('strayFluxAssignment: value \"%s\" not in the set of allowed values: ') %
1451  strayFluxAssignment) + str(validStrayAssign))
1452 
1453  for fidx in debResult.filters:
1454  dp = debResult.deblendedParents[fidx]
1455  # Prepare inputs to "apportionFlux" call.
1456  # template maskedImages
1457  tmimgs = []
1458  # template footprints
1459  tfoots = []
1460  # deblended as psf
1461  dpsf = []
1462  # peak x,y
1463  pkx = []
1464  pky = []
1465  # indices of valid templates
1466  ibi = []
1467  bb = dp.fp.getBBox()
1468 
1469  for peaki, pkres in enumerate(dp.peaks):
1470  if pkres.skip:
1471  continue
1472  tmimgs.append(pkres.templateImage)
1473  tfoots.append(pkres.templateFootprint)
1474  # for stray flux...
1475  dpsf.append(pkres.deblendedAsPsf)
1476  pk = pkres.peak
1477  pkx.append(pk.getIx())
1478  pky.append(pk.getIy())
1479  ibi.append(pkres.pki)
1480 
1481  # Now apportion flux according to the templates
1482  log.trace('Apportioning flux among %i templates', len(tmimgs))
1483  sumimg = afwImage.ImageF(bb)
1484  # .getDimensions())
1485  # sumimg.setXY0(bb.getMinX(), bb.getMinY())
1486 
1487  strayopts = 0
1488  if strayFluxAssignment == 'trim':
1489  assignStrayFlux = False
1490  strayopts |= bUtils.STRAYFLUX_TRIM
1491  if assignStrayFlux:
1492  strayopts |= bUtils.ASSIGN_STRAYFLUX
1493  if strayFluxToPointSources == 'necessary':
1494  strayopts |= bUtils.STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY
1495  elif strayFluxToPointSources == 'always':
1496  strayopts |= bUtils.STRAYFLUX_TO_POINT_SOURCES_ALWAYS
1497 
1498  if strayFluxAssignment == 'r-to-peak':
1499  # this is the default
1500  pass
1501  elif strayFluxAssignment == 'r-to-footprint':
1502  strayopts |= bUtils.STRAYFLUX_R_TO_FOOTPRINT
1503  elif strayFluxAssignment == 'nearest-footprint':
1504  strayopts |= bUtils.STRAYFLUX_NEAREST_FOOTPRINT
1505 
1506  portions, strayflux = bUtils.apportionFlux(dp.maskedImage, dp.fp, tmimgs, tfoots, sumimg, dpsf,
1507  pkx, pky, strayopts, clipStrayFluxFraction)
1508 
1509  # Shrink parent to union of children
1510  if strayFluxAssignment == 'trim':
1511  finalSpanSet = afwGeom.SpanSet()
1512  for foot in tfoots:
1513  finalSpanSet = finalSpanSet.union(foot.spans)
1514  dp.fp.setSpans(finalSpanSet)
1515 
1516  # Store the template sum in the deblender result
1517  if getTemplateSum:
1518  debResult.setTemplateSums(sumimg, fidx)
1519 
1520  # Save the apportioned fluxes
1521  ii = 0
1522  for j, (pk, pkres) in enumerate(zip(dp.fp.getPeaks(), dp.peaks)):
1523  if pkres.skip:
1524  continue
1525  pkres.setFluxPortion(portions[ii])
1526 
1527  if assignStrayFlux:
1528  # NOTE that due to a swig bug (https://github.com/swig/swig/issues/59)
1529  # we CANNOT iterate over "strayflux", but must index into it.
1530  stray = strayflux[ii]
1531  else:
1532  stray = None
1533  ii += 1
1534 
1535  pkres.setStrayFlux(stray)
1536 
1537  # Set child footprints to contain the right number of peaks.
1538  for j, (pk, pkres) in enumerate(zip(dp.fp.getPeaks(), dp.peaks)):
1539  if pkres.skip:
1540  continue
1541 
1542  for foot, add in [(pkres.templateFootprint, True), (pkres.origFootprint, True),
1543  (pkres.strayFlux, False)]:
1544  if foot is None:
1545  continue
1546  pks = foot.getPeaks()
1547  pks.clear()
1548  if add:
1549  pks.append(pk)
1550  return True
1551 
A compact representation of a collection of pixels.
Definition: SpanSet.h:77

◆ buildMultibandTemplates()

def lsst.meas.deblender.plugins.buildMultibandTemplates (   debResult,
  log,
  useWeights = False,
  usePsf = False,
  sources = None,
  constraints = None,
  config = None,
  maxIter = 100,
  bgScale = 0.5,
  relativeError = 1e-2,
  badMask = None 
)
Run the Multiband Deblender to build templates

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
useWeights: bool, default=False
    Whether or not to use the variance map in each filter for the fit.
usePsf: bool, default=False
    Whether or not to convolve the image with the PSF in each band.
    This is not yet implemented in an optimized algorithm, so it is recommended
    to leave this term off for now
sources: list of `scarlet.source.Source` objects, default=None
    List of sources to use in the blend. By default the
    `scarlet.source.ExtendedSource` class is used, which initializes each
    source as symmetric and monotonic about a peak in the footprint peak catalog.
constraints: `scarlet.constraint.Constraint`, default=None
    Constraint to be applied to each source. If sources require different constraints,
    a list of `sources` must be created instead, which ignores the `constraints` parameter.
    When `constraints` is `None` the default constraints are used.
config: `scarlet.config.Config`, default=None
    Configuration for the blend.
    If `config` is `None` then the default `Config` is used.
maxIter: int, default=100
    Maximum iterations for a single blend.
bgScale: float
    Amount to scale the background RMS to set the floor for deblender model sizes
relativeError: float, default=1e-2
    Relative error to reach for convergence
badMask: list of str, default=`None`
    List of mask plane names to mark bad pixels.
    If `badPixelKeys` is `None`, the default keywords used are
    `["BAD", "CR", "NO_DATA", "SAT", "SUSPECT"]`.

Returns
-------
modified: `bool`
    If any templates have been created then ``modified`` is ``True``,
    otherwise it is ``False`` (meaning all of the peaks were skipped).

Definition at line 158 of file plugins.py.

158  relativeError=1e-2, badMask=None):
159  """Run the Multiband Deblender to build templates
160 
161  Parameters
162  ----------
163  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
164  Container for the final deblender results.
165  log: `log.Log`
166  LSST logger for logging purposes.
167  useWeights: bool, default=False
168  Whether or not to use the variance map in each filter for the fit.
169  usePsf: bool, default=False
170  Whether or not to convolve the image with the PSF in each band.
171  This is not yet implemented in an optimized algorithm, so it is recommended
172  to leave this term off for now
173  sources: list of `scarlet.source.Source` objects, default=None
174  List of sources to use in the blend. By default the
175  `scarlet.source.ExtendedSource` class is used, which initializes each
176  source as symmetric and monotonic about a peak in the footprint peak catalog.
177  constraints: `scarlet.constraint.Constraint`, default=None
178  Constraint to be applied to each source. If sources require different constraints,
179  a list of `sources` must be created instead, which ignores the `constraints` parameter.
180  When `constraints` is `None` the default constraints are used.
181  config: `scarlet.config.Config`, default=None
182  Configuration for the blend.
183  If `config` is `None` then the default `Config` is used.
184  maxIter: int, default=100
185  Maximum iterations for a single blend.
186  bgScale: float
187  Amount to scale the background RMS to set the floor for deblender model sizes
188  relativeError: float, default=1e-2
189  Relative error to reach for convergence
190  badMask: list of str, default=`None`
191  List of mask plane names to mark bad pixels.
192  If `badPixelKeys` is `None`, the default keywords used are
193  `["BAD", "CR", "NO_DATA", "SAT", "SUSPECT"]`.
194 
195  Returns
196  -------
197  modified: `bool`
198  If any templates have been created then ``modified`` is ``True``,
199  otherwise it is ``False`` (meaning all of the peaks were skipped).
200  """
201  # Extract coordinates from each MultiColorPeak
202  bbox = debResult.footprint.getBBox()
203  peakSchema = debResult.footprint.peaks.getSchema()
204  xmin = bbox.getMinX()
205  ymin = bbox.getMinY()
206  peaks = [[pk.y-ymin, pk.x-xmin] for pk in debResult.peaks]
207  xy0 = bbox.getMin()
208 
209  # Create the data array from the masked images
210  mMaskedImage = debResult.mMaskedImage[:, debResult.footprint.getBBox()]
211  data = mMaskedImage.image.array
212 
213  # Use the inverse variance as the weights
214  if useWeights:
215  weights = 1/mMaskedImage.variance.array
216  else:
217  weights = np.ones_like(data)
218 
219  # Use the mask plane to mask bad pixels and
220  # the footprint to mask out pixels outside the footprint
221  if badMask is None:
222  badMask = ["BAD", "CR", "NO_DATA", "SAT", "SUSPECT"]
223  fpMask = afwImage.Mask(bbox)
224  debResult.footprint.spans.setMask(fpMask, 1)
225  fpMask = ~fpMask.getArray().astype(bool)
226  badPixels = mMaskedImage.mask.getPlaneBitMask(badMask)
227  mask = (mMaskedImage.mask.array & badPixels) | fpMask[None, :]
228  weights[mask > 0] = 0
229 
230  # Extract the PSF from each band for PSF convolution
231  if usePsf:
232  psfs = []
233  for psf in debResult.psfs:
234  psfs.append(psf.computeKernelImage().array)
235  psf = np.array(psfs)
236  else:
237  psf = None
238 
239  bg_rms = np.array([debResult.deblendedParents[f].avgNoise for f in debResult.filters])*bgScale
240  if sources is None:
241  # If only a single constraint was given, use it for all of the sources
242  if constraints is None or isinstance(constraints[0], scarlet.constraints.Constraint):
243  constraints = [constraints] * len(peaks)
244  sources = [
245  scarlet.source.ExtendedSource(center=peak,
246  img=data,
247  bg_rms=bg_rms,
248  constraints=constraints[pk],
249  psf=psf,
250  symmetric=True,
251  monotonic=True,
252  thresh=1.0,
253  config=config)
254  for pk, peak in enumerate(peaks)
255  ]
256 
257  # When a footprint includes only non-detections
258  # (peaks in the noise too low to deblend as a source)
259  # the deblender currently fails.
260  try:
261  blend = scarlet.blend.Blend(components=sources)
262  blend.set_data(img=data, weights=weights, bg_rms=bg_rms, config=config)
263  blend.fit(maxIter, e_rel=relativeError)
264  except scarlet.source.SourceInitError as e:
265  log.warn(e.args[0])
266  debResult.failed = True
267  return False
268  except np.linalg.LinAlgError:
269  log.warn("Deblend failed catastrophically, most likely due to no signal in the footprint")
270  debResult.failed = True
271  return False
272  debResult.blend = blend
273 
274  modified = False
275  # Create the Templates for each peak in each filter
276  for pk, source in enumerate(blend.sources):
277  src = source.components[0]
278  _cx = src.Nx >> 1
279  _cy = src.Ny >> 1
280 
281  if debResult.peaks[pk].skip:
282  continue
283  modified = True
284  cx = src.center[1]+xmin
285  cy = src.center[0]+ymin
286  icx = int(np.round(cx))
287  icy = int(np.round(cy))
288  imbb = debResult.deblendedParents[debResult.filters[0]].img.getBBox()
289 
290  # Footprint must be inside the image
291  if not imbb.contains(geom.Point2I(cx, cy)):
292  _setPeakError(debResult, log, pk, cx, cy, debResult.filters,
293  "peak center is not inside image", "setOutOfBounds")
294  continue
295  # Only save templates that have nonzero flux
296  if np.sum(src.morph) == 0:
297  _setPeakError(debResult, log, pk, cx, cy, debResult.filters,
298  "had no flux", "setFailedSymmetricTemplate")
299  continue
300 
301  # Temporary for initial testing: combine multiple components
302  model = blend.get_model(k=pk).astype(np.float32)
303 
304  # The peak in each band will have the same SpanSet
305  mask = afwImage.Mask(np.array(np.sum(model, axis=0) > 0, dtype=np.int32), xy0=xy0)
306  ss = afwGeom.SpanSet.fromMask(mask)
307 
308  if len(ss) == 0:
309  log.warn("No flux in parent footprint")
310  debResult.failed = True
311  return False
312 
313  # Add the template footprint and image to the deblender result for each peak
314  for fidx, f in enumerate(debResult.filters):
315  pkResult = debResult.deblendedParents[f].peaks[pk]
316  tfoot = afwDet.Footprint(ss, peakSchema=peakSchema)
317  # Add the peak with the intensity of the centered model,
318  # which might be slightly larger than the shifted model
319  peakFlux = np.sum(src.sed[fidx]*src.morph[_cy, _cx])
320  tfoot.addPeak(cx, cy, peakFlux)
321  timg = afwImage.ImageF(model[fidx], xy0=xy0)
322  timg = timg[tfoot.getBBox()]
323  pkResult.setOrigTemplate(timg, tfoot)
324  pkResult.setTemplate(timg, tfoot)
325  pkResult.setFluxPortion(afwImage.MaskedImageF(timg))
326  pkResult.multiColorPeak.x = cx
327  pkResult.multiColorPeak.y = cy
328  pkResult.peak.setFx(cx)
329  pkResult.peak.setFy(cy)
330  pkResult.peak.setIx(icx)
331  pkResult.peak.setIy(icy)
332  return modified
333 
334 
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:62

◆ buildSymmetricTemplates()

def lsst.meas.deblender.plugins.buildSymmetricTemplates (   debResult,
  log,
  patchEdges = False,
  setOrigTemplate = True 
)
Build a symmetric template for each peak in each filter

Given ``maskedImageF``, ``footprint``, and a ``DebldendedPeak``, creates a symmetric template
(``templateImage`` and ``templateFootprint``) around the peak for all peaks not flagged as
``skip`` or ``deblendedAsPsf``.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
patchEdges: `bool`, optional
    If True and if the parent Footprint touches pixels with the ``EDGE`` bit set,
    then grow the parent Footprint to include all symmetric templates.

Returns
-------
modified: `bool`
    If any peaks are not skipped or marked as point sources, ``modified`` is ``True.
    Otherwise ``modified`` is ``False``.

Definition at line 870 of file plugins.py.

870 def buildSymmetricTemplates(debResult, log, patchEdges=False, setOrigTemplate=True):
871  """Build a symmetric template for each peak in each filter
872 
873  Given ``maskedImageF``, ``footprint``, and a ``DebldendedPeak``, creates a symmetric template
874  (``templateImage`` and ``templateFootprint``) around the peak for all peaks not flagged as
875  ``skip`` or ``deblendedAsPsf``.
876 
877  Parameters
878  ----------
879  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
880  Container for the final deblender results.
881  log: `log.Log`
882  LSST logger for logging purposes.
883  patchEdges: `bool`, optional
884  If True and if the parent Footprint touches pixels with the ``EDGE`` bit set,
885  then grow the parent Footprint to include all symmetric templates.
886 
887  Returns
888  -------
889  modified: `bool`
890  If any peaks are not skipped or marked as point sources, ``modified`` is ``True.
891  Otherwise ``modified`` is ``False``.
892  """
893  modified = False
894  # Create the Templates for each peak in each filter
895  for fidx in debResult.filters:
896  dp = debResult.deblendedParents[fidx]
897  imbb = dp.img.getBBox()
898  log.trace('Creating templates for footprint at x0,y0,W,H = %i, %i, %i, %i)', dp.x0, dp.y0, dp.W, dp.H)
899 
900  for peaki, pkres in enumerate(dp.peaks):
901  log.trace('Deblending peak %i of %i', peaki, len(dp.peaks))
902  # TODO: Check debResult to see if the peak is deblended as a point source
903  # when comparing all bands, not just a single band
904  if pkres.skip or pkres.deblendedAsPsf:
905  continue
906  modified = True
907  pk = pkres.peak
908  cx, cy = pk.getIx(), pk.getIy()
909  if not imbb.contains(geom.Point2I(cx, cy)):
910  log.trace('Peak center is not inside image; skipping %i', pkres.pki)
911  pkres.setOutOfBounds()
912  continue
913  log.trace('computing template for peak %i at (%i, %i)', pkres.pki, cx, cy)
914  timg, tfoot, patched = bUtils.buildSymmetricTemplate(dp.maskedImage, dp.fp, pk, dp.avgNoise,
915  True, patchEdges)
916  if timg is None:
917  log.trace('Peak %i at (%i, %i): failed to build symmetric template', pkres.pki, cx, cy)
918  pkres.setFailedSymmetricTemplate()
919  continue
920 
921  if patched:
922  pkres.setPatched()
923 
924  # possibly save the original symmetric template
925  if setOrigTemplate:
926  pkres.setOrigTemplate(timg, tfoot)
927  pkres.setTemplate(timg, tfoot)
928  return modified
929 
930 
def buildSymmetricTemplates(debResult, log, patchEdges=False, setOrigTemplate=True)
Definition: plugins.py:870

◆ clipFootprintsToNonzero()

def lsst.meas.deblender.plugins.clipFootprintsToNonzero (   debResult,
  log 
)
Clip non-zero spans in the template footprints for every peak in each filter.

Peak ``Footprint``s are clipped to the region in the image containing non-zero values
by dropping spans that are completely zero and moving endpoints to non-zero pixels
(but does not split spans that have internal zeros).

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.

Returns
-------
modified: `bool`
    Whether or not any templates were modified.
    This will be ``True`` as long as there is at least one source that is not flagged as a PSF.

Definition at line 1194 of file plugins.py.

1194 def clipFootprintsToNonzero(debResult, log):
1195  """Clip non-zero spans in the template footprints for every peak in each filter.
1196 
1197  Peak ``Footprint``s are clipped to the region in the image containing non-zero values
1198  by dropping spans that are completely zero and moving endpoints to non-zero pixels
1199  (but does not split spans that have internal zeros).
1200 
1201  Parameters
1202  ----------
1203  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1204  Container for the final deblender results.
1205  log: `log.Log`
1206  LSST logger for logging purposes.
1207 
1208  Returns
1209  -------
1210  modified: `bool`
1211  Whether or not any templates were modified.
1212  This will be ``True`` as long as there is at least one source that is not flagged as a PSF.
1213  """
1214  # Loop over all filters
1215  for fidx in debResult.filters:
1216  dp = debResult.deblendedParents[fidx]
1217  for peaki, pkres in enumerate(dp.peaks):
1218  if pkres.skip or pkres.deblendedAsPsf:
1219  continue
1220  timg, tfoot = pkres.templateImage, pkres.templateFootprint
1221  clipFootprintToNonzeroImpl(tfoot, timg)
1222  if not tfoot.getBBox().isEmpty() and tfoot.getBBox() != timg.getBBox(afwImage.PARENT):
1223  timg = timg.Factory(timg, tfoot.getBBox(), afwImage.PARENT, True)
1224  pkres.setTemplate(timg, tfoot)
1225  return False
1226 
1227 
def clipFootprintToNonzeroImpl(foot, image)
Definition: plugins.py:36
def clipFootprintsToNonzero(debResult, log)
Definition: plugins.py:1194

◆ clipFootprintToNonzeroImpl()

def lsst.meas.deblender.plugins.clipFootprintToNonzeroImpl (   foot,
  image 
)
 Clips the given *Footprint* to the region in the *Image*
 containing non-zero values.  The clipping drops spans that are
 totally zero, and moves endpoints to non-zero; it does not
 split spans that have internal zeros.

Definition at line 36 of file plugins.py.

36 def clipFootprintToNonzeroImpl(foot, image):
37  '''
38  Clips the given *Footprint* to the region in the *Image*
39  containing non-zero values. The clipping drops spans that are
40  totally zero, and moves endpoints to non-zero; it does not
41  split spans that have internal zeros.
42  '''
43  x0 = image.getX0()
44  y0 = image.getY0()
45  xImMax = x0 + image.getDimensions().getX()
46  yImMax = y0 + image.getDimensions().getY()
47  newSpans = []
48  arr = image.getArray()
49  for span in foot.spans:
50  y = span.getY()
51  if y < y0 or y > yImMax:
52  continue
53  spanX0 = span.getX0()
54  spanX1 = span.getX1()
55  xMin = spanX0 if spanX0 >= x0 else x0
56  xMax = spanX1 if spanX1 <= xImMax else xImMax
57  xarray = np.arange(xMin, xMax+1)[arr[y-y0, xMin-x0:xMax-x0+1] != 0]
58  if len(xarray) > 0:
59  newSpans.append(afwGeom.Span(y, xarray[0], xarray[-1]))
60  # Time to update the SpanSet
61  foot.setSpans(afwGeom.SpanSet(newSpans, normalize=False))
62  foot.removeOrphanPeaks()
63 
64 
A compact representation of a collection of pixels.
Definition: SpanSet.h:77
A range of pixels within one row of an Image.
Definition: Span.h:47
def clipFootprintToNonzeroImpl(foot, image)
Definition: plugins.py:36

◆ fitPsfs()

def lsst.meas.deblender.plugins.fitPsfs (   debResult,
  log,
  psfChisqCut1 = 1.5,
  psfChisqCut2 = 1.5,
  psfChisqCut2b = 1.5,
  tinyFootprintSize = 2 
)
Fit a PSF + smooth background model (linear) to a small region around each peak

This function will iterate over all filters in deblender result but does not compare
results across filters.
DeblendedPeaks that pass the cuts have their templates modified to the PSF + background model
and their ``deblendedAsPsf`` property set to ``True``.

This will likely be replaced in the future with a function that compares the psf chi-squared cuts
so that peaks flagged as point sources will be considered point sources in all bands.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
psfChisqCut*: `float`, optional
    ``psfChisqCut1`` is the maximum chi-squared-per-degree-of-freedom allowed for a peak to
    be considered a PSF match without recentering.
    A fit is also made that includes terms to recenter the PSF.
    ``psfChisqCut2`` is the same as ``psfChisqCut1`` except it determines the restriction on the
    fit that includes recentering terms.
    If the peak is a match for a re-centered PSF, the PSF is repositioned at the new center and
    the peak footprint is fit again, this time to the new PSF.
    If the resulting chi-squared-per-degree-of-freedom is less than ``psfChisqCut2b`` then it
    passes the re-centering algorithm.
    If the peak passes both the re-centered and fixed position cuts, the better of the two is accepted,
    but parameters for all three psf fits are stored in the ``DebldendedPeak``.
    The default for ``psfChisqCut1``, ``psfChisqCut2``, and ``psfChisqCut2b`` is ``1.5``.
tinyFootprintSize: `float`, optional
    The PSF model is shrunk to the size that contains the original footprint.
    If the bbox of the clipped PSF model for a peak is smaller than ``max(tinyFootprintSize,2)``
    then ``tinyFootprint`` for the peak is set to ``True`` and the peak is not fit.
    The default is 2.

Returns
-------
modified: `bool`
    If any templates have been assigned to PSF point sources then ``modified`` is ``True``,
    otherwise it is ``False``.

Definition at line 335 of file plugins.py.

335 def fitPsfs(debResult, log, psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, tinyFootprintSize=2):
336  """Fit a PSF + smooth background model (linear) to a small region around each peak
337 
338  This function will iterate over all filters in deblender result but does not compare
339  results across filters.
340  DeblendedPeaks that pass the cuts have their templates modified to the PSF + background model
341  and their ``deblendedAsPsf`` property set to ``True``.
342 
343  This will likely be replaced in the future with a function that compares the psf chi-squared cuts
344  so that peaks flagged as point sources will be considered point sources in all bands.
345 
346  Parameters
347  ----------
348  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
349  Container for the final deblender results.
350  log: `log.Log`
351  LSST logger for logging purposes.
352  psfChisqCut*: `float`, optional
353  ``psfChisqCut1`` is the maximum chi-squared-per-degree-of-freedom allowed for a peak to
354  be considered a PSF match without recentering.
355  A fit is also made that includes terms to recenter the PSF.
356  ``psfChisqCut2`` is the same as ``psfChisqCut1`` except it determines the restriction on the
357  fit that includes recentering terms.
358  If the peak is a match for a re-centered PSF, the PSF is repositioned at the new center and
359  the peak footprint is fit again, this time to the new PSF.
360  If the resulting chi-squared-per-degree-of-freedom is less than ``psfChisqCut2b`` then it
361  passes the re-centering algorithm.
362  If the peak passes both the re-centered and fixed position cuts, the better of the two is accepted,
363  but parameters for all three psf fits are stored in the ``DebldendedPeak``.
364  The default for ``psfChisqCut1``, ``psfChisqCut2``, and ``psfChisqCut2b`` is ``1.5``.
365  tinyFootprintSize: `float`, optional
366  The PSF model is shrunk to the size that contains the original footprint.
367  If the bbox of the clipped PSF model for a peak is smaller than ``max(tinyFootprintSize,2)``
368  then ``tinyFootprint`` for the peak is set to ``True`` and the peak is not fit.
369  The default is 2.
370 
371  Returns
372  -------
373  modified: `bool`
374  If any templates have been assigned to PSF point sources then ``modified`` is ``True``,
375  otherwise it is ``False``.
376  """
377  from .baseline import CachingPsf
378  modified = False
379  # Loop over all of the filters to build the PSF
380  for fidx in debResult.filters:
381  dp = debResult.deblendedParents[fidx]
382  peaks = dp.fp.getPeaks()
383  cpsf = CachingPsf(dp.psf)
384 
385  # create mask image for pixels within the footprint
386  fmask = afwImage.Mask(dp.bb)
387  fmask.setXY0(dp.bb.getMinX(), dp.bb.getMinY())
388  dp.fp.spans.setMask(fmask, 1)
389 
390  # pk.getF() -- retrieving the floating-point location of the peak
391  # -- actually shows up in the profile if we do it in the loop, so
392  # grab them all here.
393  peakF = [pk.getF() for pk in peaks]
394 
395  for pki, (pk, pkres, pkF) in enumerate(zip(peaks, dp.peaks, peakF)):
396  log.trace('Filter %s, Peak %i', fidx, pki)
397  ispsf = _fitPsf(dp.fp, fmask, pk, pkF, pkres, dp.bb, peaks, peakF, log, cpsf, dp.psffwhm,
398  dp.img, dp.varimg, psfChisqCut1, psfChisqCut2, psfChisqCut2b, tinyFootprintSize)
399  modified = modified or ispsf
400  return modified
401 
402 
def fitPsfs(debResult, log, psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, tinyFootprintSize=2)
Definition: plugins.py:335
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77

◆ makeTemplatesMonotonic()

def lsst.meas.deblender.plugins.makeTemplatesMonotonic (   debResult,
  log 
)
Make the templates monotonic.

The pixels in the templates are modified such that pixels further from the peak will
have values smaller than those closer to the peak.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.

Returns
-------
modified: `bool`
    Whether or not any templates were modified.
    This will be ``True`` as long as there is at least one source that is not flagged as a PSF.

Definition at line 1159 of file plugins.py.

1159 def makeTemplatesMonotonic(debResult, log):
1160  """Make the templates monotonic.
1161 
1162  The pixels in the templates are modified such that pixels further from the peak will
1163  have values smaller than those closer to the peak.
1164 
1165  Parameters
1166  ----------
1167  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1168  Container for the final deblender results.
1169  log: `log.Log`
1170  LSST logger for logging purposes.
1171 
1172  Returns
1173  -------
1174  modified: `bool`
1175  Whether or not any templates were modified.
1176  This will be ``True`` as long as there is at least one source that is not flagged as a PSF.
1177  """
1178  modified = False
1179  # Loop over all filters
1180  for fidx in debResult.filters:
1181  dp = debResult.deblendedParents[fidx]
1182  for peaki, pkres in enumerate(dp.peaks):
1183  if pkres.skip or pkres.deblendedAsPsf:
1184  continue
1185  modified = True
1186  timg, tfoot = pkres.templateImage, pkres.templateFootprint
1187  pk = pkres.peak
1188  log.trace('Making template %i monotonic', pkres.pki)
1189  bUtils.makeMonotonic(timg, pk)
1190  pkres.setTemplate(timg, tfoot)
1191  return modified
1192 
1193 
def makeTemplatesMonotonic(debResult, log)
Definition: plugins.py:1159

◆ medianSmoothTemplates()

def lsst.meas.deblender.plugins.medianSmoothTemplates (   debResult,
  log,
  medianFilterHalfsize = 2 
)
Applying median smoothing filter to the template images for every peak in every filter.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
medianFilterHalfSize: `int`, optional
    Half the box size of the median filter, i.e. a ``medianFilterHalfSize`` of 50 means that
    each output pixel will be the median of  the pixels in a 101 x 101-pixel box in the input image.
    This parameter is only used when ``medianSmoothTemplate==True``, otherwise it is ignored.

Returns
-------
modified: `bool`
    Whether or not any templates were modified.
    This will be ``True`` as long as there is at least one source that is not flagged as a PSF.

Definition at line 1114 of file plugins.py.

1114 def medianSmoothTemplates(debResult, log, medianFilterHalfsize=2):
1115  """Applying median smoothing filter to the template images for every peak in every filter.
1116 
1117  Parameters
1118  ----------
1119  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1120  Container for the final deblender results.
1121  log: `log.Log`
1122  LSST logger for logging purposes.
1123  medianFilterHalfSize: `int`, optional
1124  Half the box size of the median filter, i.e. a ``medianFilterHalfSize`` of 50 means that
1125  each output pixel will be the median of the pixels in a 101 x 101-pixel box in the input image.
1126  This parameter is only used when ``medianSmoothTemplate==True``, otherwise it is ignored.
1127 
1128  Returns
1129  -------
1130  modified: `bool`
1131  Whether or not any templates were modified.
1132  This will be ``True`` as long as there is at least one source that is not flagged as a PSF.
1133  """
1134  modified = False
1135  # Loop over all filters
1136  for fidx in debResult.filters:
1137  dp = debResult.deblendedParents[fidx]
1138  for peaki, pkres in enumerate(dp.peaks):
1139  if pkres.skip or pkres.deblendedAsPsf:
1140  continue
1141  modified = True
1142  timg, tfoot = pkres.templateImage, pkres.templateFootprint
1143  filtsize = medianFilterHalfsize*2 + 1
1144  if timg.getWidth() >= filtsize and timg.getHeight() >= filtsize:
1145  log.trace('Median filtering template %i', pkres.pki)
1146  # We want the output to go in "t1", so copy it into
1147  # "inimg" for input
1148  inimg = timg.Factory(timg, True)
1149  bUtils.medianFilter(inimg, timg, medianFilterHalfsize)
1150  # possible save this median-filtered template
1151  pkres.setMedianFilteredTemplate(timg, tfoot)
1152  else:
1153  log.trace('Not median-filtering template %i: size %i x %i smaller than required %i x %i',
1154  pkres.pki, timg.getWidth(), timg.getHeight(), filtsize, filtsize)
1155  pkres.setTemplate(timg, tfoot)
1156  return modified
1157 
1158 
def medianSmoothTemplates(debResult, log, medianFilterHalfsize=2)
Definition: plugins.py:1114

◆ rampFluxAtEdge()

def lsst.meas.deblender.plugins.rampFluxAtEdge (   debResult,
  log,
  patchEdges = False 
)
Adjust flux on the edges of the template footprints.

Using the PSF, a peak ``Footprint`` with pixels on the edge of ``footprint``
is grown by the ``psffwhm``*1.5 and filled in with ramped pixels.
The result is a new symmetric footprint template for the peaks near the edge.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
patchEdges: `bool`, optional
    If True and if the parent Footprint touches pixels with the ``EDGE`` bit set,
    then grow the parent Footprint to include all symmetric templates.

Returns
-------
modified: `bool`
    If any peaks have their templates modified to include flux at the edges,
    ``modified`` is ``True``.

Definition at line 931 of file plugins.py.

931 def rampFluxAtEdge(debResult, log, patchEdges=False):
932  """Adjust flux on the edges of the template footprints.
933 
934  Using the PSF, a peak ``Footprint`` with pixels on the edge of ``footprint``
935  is grown by the ``psffwhm``*1.5 and filled in with ramped pixels.
936  The result is a new symmetric footprint template for the peaks near the edge.
937 
938  Parameters
939  ----------
940  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
941  Container for the final deblender results.
942  log: `log.Log`
943  LSST logger for logging purposes.
944  patchEdges: `bool`, optional
945  If True and if the parent Footprint touches pixels with the ``EDGE`` bit set,
946  then grow the parent Footprint to include all symmetric templates.
947 
948  Returns
949  -------
950  modified: `bool`
951  If any peaks have their templates modified to include flux at the edges,
952  ``modified`` is ``True``.
953  """
954  modified = False
955  # Loop over all filters
956  for fidx in debResult.filters:
957  dp = debResult.deblendedParents[fidx]
958  log.trace('Checking for significant flux at edge: sigma1=%g', dp.avgNoise)
959 
960  for peaki, pkres in enumerate(dp.peaks):
961  if pkres.skip or pkres.deblendedAsPsf:
962  continue
963  timg, tfoot = pkres.templateImage, pkres.templateFootprint
964  if bUtils.hasSignificantFluxAtEdge(timg, tfoot, 3*dp.avgNoise):
965  log.trace("Template %i has significant flux at edge: ramping", pkres.pki)
966  try:
967  (timg2, tfoot2, patched) = _handle_flux_at_edge(log, dp.psffwhm, timg, tfoot, dp.fp,
968  dp.maskedImage, dp.x0, dp.x1,
969  dp.y0, dp.y1, dp.psf, pkres.peak,
970  dp.avgNoise, patchEdges)
971  except lsst.pex.exceptions.Exception as exc:
972  if (isinstance(exc, lsst.pex.exceptions.InvalidParameterError) and
973  "CoaddPsf" in str(exc)):
974  pkres.setOutOfBounds()
975  continue
976  raise
977  pkres.setRampedTemplate(timg2, tfoot2)
978  if patched:
979  pkres.setPatched()
980  pkres.setTemplate(timg2, tfoot2)
981  modified = True
982  return modified
983 
984 
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
def rampFluxAtEdge(debResult, log, patchEdges=False)
Definition: plugins.py:931
Reports invalid arguments.
Definition: Runtime.h:66

◆ reconstructTemplates()

def lsst.meas.deblender.plugins.reconstructTemplates (   debResult,
  log,
  maxTempDotProd = 0.5 
)
Remove "degenerate templates"

If galaxies have substructure, such as face-on spirals, the process of identifying peaks can
"shred" the galaxy into many pieces. The templates of shredded galaxies are typically quite
similar because they represent the same galaxy, so we try to identify these "degenerate" peaks
by looking at the inner product (in pixel space) of pairs of templates.
If they are nearly parallel, we only keep one of the peaks and reject the other.
If only one of the peaks is a PSF template, the other template is used,
otherwise the one with the maximum template value is kept.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.
maxTempDotProd: `float`, optional
    All dot products between templates greater than ``maxTempDotProd`` will result in one
    of the templates removed.

Returns
-------
modified: `bool`
    If any degenerate templates are found, ``modified`` is ``True``.

Definition at line 1297 of file plugins.py.

1297 def reconstructTemplates(debResult, log, maxTempDotProd=0.5):
1298  """Remove "degenerate templates"
1299 
1300  If galaxies have substructure, such as face-on spirals, the process of identifying peaks can
1301  "shred" the galaxy into many pieces. The templates of shredded galaxies are typically quite
1302  similar because they represent the same galaxy, so we try to identify these "degenerate" peaks
1303  by looking at the inner product (in pixel space) of pairs of templates.
1304  If they are nearly parallel, we only keep one of the peaks and reject the other.
1305  If only one of the peaks is a PSF template, the other template is used,
1306  otherwise the one with the maximum template value is kept.
1307 
1308  Parameters
1309  ----------
1310  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1311  Container for the final deblender results.
1312  log: `log.Log`
1313  LSST logger for logging purposes.
1314  maxTempDotProd: `float`, optional
1315  All dot products between templates greater than ``maxTempDotProd`` will result in one
1316  of the templates removed.
1317 
1318  Returns
1319  -------
1320  modified: `bool`
1321  If any degenerate templates are found, ``modified`` is ``True``.
1322  """
1323  log.trace('Looking for degnerate templates')
1324 
1325  foundReject = False
1326  for fidx in debResult.filters:
1327  dp = debResult.deblendedParents[fidx]
1328  nchild = np.sum([pkres.skip is False for pkres in dp.peaks])
1329  indexes = [pkres.pki for pkres in dp.peaks if pkres.skip is False]
1330 
1331  # We build a matrix that stores the dot product between templates.
1332  # We convert the template images to HeavyFootprints because they already have a method
1333  # to compute the dot product.
1334  A = np.zeros((nchild, nchild))
1335  maxTemplate = []
1336  heavies = []
1337  for pkres in dp.peaks:
1338  if pkres.skip:
1339  continue
1340  heavies.append(afwDet.makeHeavyFootprint(pkres.templateFootprint,
1341  afwImage.MaskedImageF(pkres.templateImage)))
1342  maxTemplate.append(np.max(pkres.templateImage.getArray()))
1343 
1344  for i in range(nchild):
1345  for j in range(i + 1):
1346  A[i, j] = heavies[i].dot(heavies[j])
1347 
1348  # Normalize the dot products to get the cosine of the angle between templates
1349  for i in range(nchild):
1350  for j in range(i):
1351  norm = A[i, i]*A[j, j]
1352  if norm <= 0:
1353  A[i, j] = 0
1354  else:
1355  A[i, j] /= np.sqrt(norm)
1356 
1357  # Iterate over pairs of objects and find the maximum non-diagonal element of the matrix.
1358  # Exit the loop once we find a single degenerate pair greater than the threshold.
1359  rejectedIndex = -1
1360  for i in range(nchild):
1361  currentMax = 0.
1362  for j in range(i):
1363  if A[i, j] > currentMax:
1364  currentMax = A[i, j]
1365  if currentMax > maxTempDotProd:
1366  foundReject = True
1367  rejectedIndex = j
1368 
1369  if foundReject:
1370  break
1371 
1372  del A
1373 
1374  # If one of the objects is identified as a PSF keep the other one, otherwise keep the one
1375  # with the maximum template value
1376  if foundReject:
1377  keep = indexes[i]
1378  reject = indexes[rejectedIndex]
1379  if dp.peaks[keep].deblendedAsPsf and dp.peaks[reject].deblendedAsPsf is False:
1380  keep = indexes[rejectedIndex]
1381  reject = indexes[i]
1382  elif dp.peaks[keep].deblendedAsPsf is False and dp.peaks[reject].deblendedAsPsf:
1383  reject = indexes[rejectedIndex]
1384  keep = indexes[i]
1385  else:
1386  if maxTemplate[rejectedIndex] > maxTemplate[i]:
1387  keep = indexes[rejectedIndex]
1388  reject = indexes[i]
1389  log.trace('Removing object with index %d : %f. Degenerate with %d' % (reject, currentMax,
1390  keep))
1391  dp.peaks[reject].skip = True
1392  dp.peaks[reject].degenerate = True
1393 
1394  return foundReject
1395 
1396 
def dot(symb, c, r, frame=None, size=2, ctype=None, origin=afwImage.PARENT, args, kwargs)
Definition: ds9.py:101
def reconstructTemplates(debResult, log, maxTempDotProd=0.5)
Definition: plugins.py:1297
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=NULL)
Create a HeavyFootprint with footprint defined by the given Footprint and pixel values from the given...

◆ weightTemplates()

def lsst.meas.deblender.plugins.weightTemplates (   debResult,
  log 
)
Weight the templates to best fit the observed image in each filter

This function re-weights the templates so that their linear combination best represents
the observed image in that filter.
In the future it may be useful to simultaneously weight all of the filters together.

Parameters
----------
debResult: `lsst.meas.deblender.baseline.DeblenderResult`
    Container for the final deblender results.
log: `log.Log`
    LSST logger for logging purposes.

Returns
-------
modified: `bool`
    ``weightTemplates`` does not actually modify the ``Footprint`` templates other than
    to add a weight to them, so ``modified`` is always ``False``.

Definition at line 1228 of file plugins.py.

1228 def weightTemplates(debResult, log):
1229  """Weight the templates to best fit the observed image in each filter
1230 
1231  This function re-weights the templates so that their linear combination best represents
1232  the observed image in that filter.
1233  In the future it may be useful to simultaneously weight all of the filters together.
1234 
1235  Parameters
1236  ----------
1237  debResult: `lsst.meas.deblender.baseline.DeblenderResult`
1238  Container for the final deblender results.
1239  log: `log.Log`
1240  LSST logger for logging purposes.
1241 
1242  Returns
1243  -------
1244  modified: `bool`
1245  ``weightTemplates`` does not actually modify the ``Footprint`` templates other than
1246  to add a weight to them, so ``modified`` is always ``False``.
1247  """
1248  # Weight the templates by doing a least-squares fit to the image
1249  log.trace('Weighting templates')
1250  for fidx in debResult.filters:
1251  _weightTemplates(debResult.deblendedParents[fidx])
1252  return False
1253 
1254 
def weightTemplates(debResult, log)
Definition: plugins.py:1228