439 ):
440 r"""Deblend a parent ``Footprint`` in a ``MaskedImageF``.
441
442 Deblending assumes that ``footprint`` has multiple peaks, as it will still create a
443 `PerFootprint` object with a list of peaks even if there is only one peak in the list.
444 It is recommended to first check that ``footprint`` has more than one peak, similar to the
445 execution of `lsst.meas.deblender.deblend.SourceDeblendTask`.
446
447 .. note::
448 This is the API for the old deblender, however the function builds the plugins necessary
449 to use the new deblender to perform identically to the old deblender.
450 To test out newer functionality use ``newDeblend`` instead.
451
452 Deblending involves several mandatory and optional steps:
453
454 # Optional: If ``fitPsfs`` is True, find all peaks that are well-fit by a PSF + background model
455
456 * Peaks that pass the cuts have their footprints modified to the PSF + background model
457 and their ``deblendedAsPsf`` property set to ``True``.
458 * Relevant parameters: ``psfChisqCut1``, ``psfChisqCut2``, ``psfChisqCut2b``,
459 ``tinyFootprintSize``.
460 * See the parameter descriptions for more.
461
462 # Build a symmetric template for each peak not well-fit by the PSF model
463
464 * Given ``maskedImageF``, ``footprint``, and a ``DeblendedPeak``, creates a symmetric
465 template (``templateImage`` and ``templateFootprint``) around the peak
466 for all peaks not flagged as ``skip`` or ``deblendedAsPsf``.
467 * If ``patchEdges=True`` and if ``footprint`` touches pixels with the
468 ``EDGE`` bit set, then ``footprint`` is grown to include spans whose
469 symmetric mirror is outside of the image.
470 * Relevant parameters: ``sigma1`` and ``patchEdges``.
471
472 # Optional: If ``rampFluxAtEdge`` is True, adjust flux on the edges of the template footprints
473
474 * Using the PSF, a peak ``Footprint`` with pixels on the edge of of ``footprint``
475 is grown by the psffwhm*1.5 and filled in with zeros.
476 * The result is a new symmetric footprint template for the peaks near the edge.
477 * Relevant parameter: ``patchEdges``.
478
479 # Optionally (``medianSmoothTemplate=True``) filter the template images
480
481 * Apply a median smoothing filter to all of the template images.
482 * Relevant parameters: ``medianFilterHalfSize``
483
484 # Optional: If ``monotonicTemplate`` is True, make the templates monotonic.
485
486 * The pixels in the templates are modified such that pixels
487 further from the peak will have values smaller than those closer to the peak.
488
489 # Optional: If ``clipFootprintToNonzero`` is True, clip non-zero spans in the template footprints
490
491 * Peak ``Footprint``\ s are clipped to the region in the image containing non-zero values
492 by dropping spans that are completely zero and moving endpoints to non-zero pixels
493 (but does not split spans that have internal zeros).
494
495 # Optional: If ``weightTemplates`` is True, weight the templates to best fit the observed image
496
497 * Re-weight the templates so that their linear combination
498 best represents the observed ``maskedImage``
499
500 # Optional: If ``removeDegenerateTempaltes`` is True, reconstruct shredded galaxies
501
502 * If galaxies have substructure, such as face-on spirals, the process of identifying peaks can
503 "shred" the galaxy into many pieces. The templates of shredded galaxies are typically quite
504 similar because they represent the same galaxy, so we try to identify these "degenerate" peaks
505 by looking at the inner product (in pixel space) of pairs of templates.
506 * If they are nearly parallel, we only keep one of the peaks and reject the other.
507 * If only one of the peaks is a PSF template, the other template is used,
508 otherwise the one with the maximum template value is kept.
509 * Relevant parameters: ``maxTempDotProduct``
510
511 # Apportion flux to all of the peak templates
512
513 * Divide the ``maskedImage`` flux amongst all of the templates based on the fraction of
514 flux assigned to each ``tempalteFootprint``.
515 * Leftover "stray flux" is assigned to peaks based on the other parameters.
516 * Relevant parameters: ``clipStrayFluxFraction``, ``strayFluxAssignment``,
517 ``strayFluxToPointSources``, ``assignStrayFlux``
518
519 Parameters
520 ----------
521 footprint: `afw.detection.Footprint`
522 Parent footprint to deblend
523 maskedImage: `afw.image.MaskedImageF`
524 Masked image containing the ``footprint``
525 psf: `afw.detection.Psf`
526 Psf of the ``maskedImage``
527 psffwhm: `float`
528 FWHM of the ``maskedImage``\'s ``psf``
529 psfChisqCut*: `float`, optional
530 If ``fitPsfs==True``, all of the peaks are fit to the image PSF.
531 ``psfChisqCut1`` is the maximum chi-squared-per-degree-of-freedom allowed for a peak to
532 be considered a PSF match without recentering.
533 A fit is also made that includes terms to recenter the PSF.
534 ``psfChisqCut2`` is the same as ``psfChisqCut1`` except it determines the restriction on the
535 fit that includes recentering terms.
536 If the peak is a match for a re-centered PSF, the PSF is repositioned at the new center and
537 the peak footprint is fit again, this time to the new PSF.
538 If the resulting chi-squared-per-degree-of-freedom is less than ``psfChisqCut2b`` then it
539 passes the re-centering algorithm.
540 If the peak passes both the re-centered and fixed position cuts, the better of the two is accepted,
541 but parameters for all three psf fits are stored in the ``DeblendedPeak``.
542 The default for ``psfChisqCut1``, ``psfChisqCut2``, and ``psfChisqCut2b`` is ``1.5``.
543 fitPsfs: `bool`, optional
544 If True then all of the peaks will be compared to the image PSF to
545 distinguish stars from galaxies.
546 medianSmoothTemplate: ``bool``, optional
547 If ``medianSmoothTemplate==True`` it a median smoothing filter is applied to the ``maskedImage``.
548 The default is ``True``.
549 medianFilterHalfSize: `int`, optional
550 Half the box size of the median filter, ie a ``medianFilterHalfSize`` of 50 means that
551 each output pixel will be the median of the pixels in a 101 x 101-pixel box in the input image.
552 This parameter is only used when ``medianSmoothTemplate==True``, otherwise it is ignored.
553 The default value is 2.
554 monotonicTempalte: `bool`, optional
555 If True then make the template monotonic.
556 The default is True.
557 weightTemplates: `bool`, optional
558 If True, re-weight the templates so that their linear combination best represents
559 the observed ``maskedImage``.
560 The default is False.
561 log: `log.Log`, optional
562 LSST logger for logging purposes.
563 The default is ``None`` (no logging).
564 verbose: `bool`, optional
565 Whether or not to show a more verbose output.
566 The default is ``False``.
567 sigma1: `float`, optional
568 Average noise level in ``maskedImage``.
569 The default is ``None``, which estimates the noise from the median value of ``maskedImage``.
570 maxNumberOfPeaks: `int`, optional
571 If nonzero, the maximum number of peaks to deblend.
572 If the total number of peaks is greater than ``maxNumberOfPeaks``,
573 then only the first ``maxNumberOfPeaks`` sources are deblended.
574 The default is 0, which deblends all of the peaks.
575 assignStrayFlux: `bool`, optional
576 If True then flux in the parent footprint that is not covered by any of the
577 template footprints is assigned to templates based on their 1/(1+r^2) distance.
578 How the flux is apportioned is determined by ``strayFluxAssignment``.
579 The default is True.
580 strayFluxToPointSources: `string`
581 Determines how stray flux is apportioned to point sources
582
583 * ``never``: never apportion stray flux to point sources
584 * ``necessary`` (default): point sources are included only if there are no extended sources nearby
585 * ``always``: point sources are always included in the 1/(1+r^2) splitting
586
587 strayFluxAssignment: `string`, optional
588 Determines how stray flux is apportioned.
589
590 * ``trim``: Trim stray flux and do not include in any footprints
591 * ``r-to-peak`` (default): Stray flux is assigned based on (1/(1+r^2) from the peaks
592 * ``r-to-footprint``: Stray flux is distributed to the footprints based on 1/(1+r^2) of the
593 minimum distance from the stray flux to footprint
594 * ``nearest-footprint``: Stray flux is assigned to the footprint with lowest L-1 (Manhattan)
595 distance to the stray flux
596
597 rampFluxAtEdge: `bool`, optional
598 If True then extend footprints with excessive flux on the edges as described above.
599 The default is False.
600 patchEdges: `bool`, optional
601 If True and if the footprint touches pixels with the ``EDGE`` bit set,
602 then grow the footprint to include all symmetric templates.
603 The default is ``False``.
604 tinyFootprintSize: `float`, optional
605 The PSF model is shrunk to the size that contains the original footprint.
606 If the bbox of the clipped PSF model for a peak is smaller than ``max(tinyFootprintSize,2)``
607 then ``tinyFootprint`` for the peak is set to ``True`` and the peak is not fit.
608 The default is 2.
609 getTemplateSum: `bool`, optional
610 As part of the flux calculation, the sum of the templates is calculated.
611 If ``getTemplateSum==True`` then the sum of the templates is stored in the result (a `PerFootprint`).
612 The default is False.
613 clipStrayFluxFraction: `float`, optional
614 Minimum stray-flux portion.
615 Any stray-flux portion less than ``clipStrayFluxFraction`` is clipped to zero.
616 The default is 0.001.
617 clipFootprintToNonzero: `bool`, optional
618 If True then clip non-zero spans in the template footprints. See above for more.
619 The default is True.
620 removeDegenerateTemplates: `bool`, optional
621 If True then we try to identify "degenerate" peaks by looking at the inner product
622 (in pixel space) of pairs of templates.
623 The default is False.
624 maxTempDotProduct: `float`, optional
625 All dot products between templates greater than ``maxTempDotProduct`` will result in one
626 of the templates removed. This parameter is only used when ``removeDegenerateTempaltes==True``.
627 The default is 0.5.
628
629 Returns
630 -------
631 res: `PerFootprint`
632 Deblender result that contains a list of ``DeblendedPeak``\ s for each peak and (optionally)
633 the template sum.
634 """
635 avgNoise = sigma1
636
637 debPlugins = []
638
639
640 if fitPsfs:
641 debPlugins.append(plugins.DeblenderPlugin(plugins.fitPsfs,
642 psfChisqCut1=psfChisqCut1,
643 psfChisqCut2=psfChisqCut2,
644 psfChisqCut2b=psfChisqCut2b,
645 tinyFootprintSize=tinyFootprintSize))
646 debPlugins.append(plugins.DeblenderPlugin(plugins.buildSymmetricTemplates, patchEdges=patchEdges))
647 if rampFluxAtEdge:
648 debPlugins.append(plugins.DeblenderPlugin(plugins.rampFluxAtEdge, patchEdges=patchEdges))
649 if medianSmoothTemplate:
650 debPlugins.append(plugins.DeblenderPlugin(plugins.medianSmoothTemplates,
651 medianFilterHalfsize=medianFilterHalfsize))
652 if monotonicTemplate:
653 debPlugins.append(plugins.DeblenderPlugin(plugins.makeTemplatesMonotonic))
654 if clipFootprintToNonzero:
655 debPlugins.append(plugins.DeblenderPlugin(plugins.clipFootprintsToNonzero))
656 if weightTemplates:
657 debPlugins.append(plugins.DeblenderPlugin(plugins.weightTemplates))
658 if removeDegenerateTemplates:
659 if weightTemplates:
660 onReset = len(debPlugins)-1
661 else:
662 onReset = len(debPlugins)
663 debPlugins.append(plugins.DeblenderPlugin(plugins.reconstructTemplates,
664 onReset=onReset,
665 maxTempDotProd=maxTempDotProd))
666 debPlugins.append(plugins.DeblenderPlugin(plugins.apportionFlux,
667 clipStrayFluxFraction=clipStrayFluxFraction,
668 assignStrayFlux=assignStrayFlux,
669 strayFluxAssignment=strayFluxAssignment,
670 strayFluxToPointSources=strayFluxToPointSources,
671 getTemplateSum=getTemplateSum))
672
673 debResult = newDeblend(debPlugins, footprint, maskedImage, psf, psffwhm, log, verbose, avgNoise)
674
675 return debResult
676
677