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
Public Types | Static Public Member Functions | Static Public Attributes | List of all members
lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT > Class Template Reference

#include <BaselineUtils.h>

Public Types

typedef lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > MaskedImageT
 
typedef boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT > MaskedImagePtrT
 
typedef lsst::afw::image::Image< ImagePixelT > ImageT
 
typedef boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
 
typedef lsst::afw::image::Mask< MaskPixelT > MaskT
 
typedef boost::shared_ptr< lsst::afw::image::Mask< MaskPixelT > > MaskPtrT
 
typedef lsst::afw::detection::Footprint FootprintT
 
typedef boost::shared_ptr< lsst::afw::detection::FootprintFootprintPtrT
 
typedef lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > HeavyFootprintT
 
typedef boost::shared_ptr< lsst::afw::detection::HeavyFootprint< ImagePixelT > MaskPixelT, VariancePixelT > HeavyFootprintPtrT
 

Static Public Member Functions

static boost::shared_ptr< lsst::afw::detection::FootprintsymmetrizeFootprint (lsst::afw::detection::Footprint const &foot, int cx, int cy)
 Given a Footprint foot and peak cx,cy, returns a Footprint that is symmetric around the peak (with twofold rotational symmetry) – the AND of the two symmetric halves. More...
 
static std::pair< ImagePtrT, FootprintPtrTbuildSymmetricTemplate (MaskedImageT const &img, lsst::afw::detection::Footprint const &foot, lsst::afw::detection::PeakRecord const &pk, double sigma1, bool minZero, bool patchEdges, bool *patchedEdges)
 Given an img, footprint foot, and peak, creates a symmetric template around the peak; produce a MaskedImage and Footprint describing a footprint where: output pixels (cx + dx, cy + dy) and (cx - dx, cy - dy) = min(input pixels (cx + dx, cy + dy) and (cx - dx, cy - dy)) More...
 
static void medianFilter (ImageT const &img, ImageT &outimg, int halfsize)
 Run a spatial median filter over the given input img, writing the results to out. More...
 
static void makeMonotonic (ImageT &img, lsst::afw::detection::PeakRecord const &pk)
 Given an image mimg and Peak location peak, overwrite mimg so that pixels further from the peak have values smaller than those close to the peak; make the profile monotonic-decreasing. More...
 
static std::vector< typename boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT >)> apportionFlux (MaskedImageT const &img, lsst::afw::detection::Footprint const &foot, std::vector< typename boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > >> templates, std::vector< std::shared_ptr< lsst::afw::detection::Footprint > > templ_footprints, ImagePtrT templ_sum, std::vector< bool > const &ispsf, std::vector< int > const &pkx, std::vector< int > const &pky, std::vector< std::shared_ptr< typename lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > > &strays, int strayFluxOptions, double clipStrayFluxFraction)
 Splits flux in a given image img, within a given footprint foot, among a number of templates timgs,tfoots. More...
 
static bool hasSignificantFluxAtEdge (ImagePtrT, std::shared_ptr< lsst::afw::detection::Footprint >, ImagePixelT threshold)
 Returns true if the given Footprint sfoot in image img has flux above value thresh at its edge. More...
 
static std::shared_ptr< lsst::afw::detection::FootprintgetSignificantEdgePixels (ImagePtrT, std::shared_ptr< lsst::afw::detection::Footprint >, ImagePixelT threshold)
 Returns a list of pixels that are on the edge of the given Footprint sfoot* in image img, above threshold thresh. More...
 
static void _sum_templates (std::vector< ImagePtrT > timgs, ImagePtrT tsum)
 
static void _find_stray_flux (lsst::afw::detection::Footprint const &foot, ImagePtrT tsum, MaskedImageT const &img, int strayFluxOptions, std::vector< std::shared_ptr< lsst::afw::detection::Footprint > > tfoots, std::vector< bool > const &ispsf, std::vector< int > const &pkx, std::vector< int > const &pky, double clipStrayFluxFraction, std::vector< std::shared_ptr< typename lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > > &strays)
 

Static Public Attributes

static const int ASSIGN_STRAYFLUX = 0x1
 
static const int STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY = 0x2
 
static const int STRAYFLUX_TO_POINT_SOURCES_ALWAYS = 0x4
 
static const int STRAYFLUX_R_TO_FOOTPRINT = 0x8
 
static const int STRAYFLUX_NEAREST_FOOTPRINT = 0x10
 
static const int STRAYFLUX_TRIM = 0x20
 

Detailed Description

template<typename ImagePixelT, typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
class lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >

Definition at line 22 of file BaselineUtils.h.

Member Typedef Documentation

◆ FootprintPtrT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef boost::shared_ptr< lsst::afw::detection::Footprint > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::FootprintPtrT

Definition at line 33 of file BaselineUtils.h.

◆ FootprintT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef lsst::afw::detection::Footprint lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::FootprintT

Definition at line 32 of file BaselineUtils.h.

◆ HeavyFootprintPtrT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef boost::shared_ptr< lsst::afw::detection::HeavyFootprint<ImagePixelT > MaskPixelT, VariancePixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::HeavyFootprintPtrT

Definition at line 36 of file BaselineUtils.h.

◆ HeavyFootprintT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef lsst::afw::detection::HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::HeavyFootprintT

Definition at line 34 of file BaselineUtils.h.

◆ ImagePtrT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef boost::shared_ptr< lsst::afw::image::Image<ImagePixelT> > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::ImagePtrT

Definition at line 28 of file BaselineUtils.h.

◆ ImageT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef lsst::afw::image::Image<ImagePixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::ImageT

Definition at line 27 of file BaselineUtils.h.

◆ MaskedImagePtrT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef boost::shared_ptr< lsst::afw::image::MaskedImage<ImagePixelT > MaskPixelT, VariancePixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::MaskedImagePtrT

Definition at line 26 of file BaselineUtils.h.

◆ MaskedImageT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef lsst::afw::image::MaskedImage<ImagePixelT, MaskPixelT, VariancePixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::MaskedImageT

Definition at line 25 of file BaselineUtils.h.

◆ MaskPtrT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef boost::shared_ptr< lsst::afw::image::Mask<MaskPixelT> > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::MaskPtrT

Definition at line 30 of file BaselineUtils.h.

◆ MaskT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
typedef lsst::afw::image::Mask<MaskPixelT> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::MaskT

Definition at line 29 of file BaselineUtils.h.

Member Function Documentation

◆ _find_stray_flux()

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
void lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::_find_stray_flux ( lsst::afw::detection::Footprint const &  foot,
ImagePtrT  tsum,
MaskedImageT const &  img,
int  strayFluxOptions,
std::vector< std::shared_ptr< lsst::afw::detection::Footprint > >  tfoots,
std::vector< bool > const &  ispsf,
std::vector< int > const &  pkx,
std::vector< int > const &  pky,
double  clipStrayFluxFraction,
std::vector< std::shared_ptr< typename lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > > &  strays 
)
static

Hmm, this is a little bit dangerous: we're assuming that the HeavyFootprint stores its pixels in the same order that we iterate over them above (ie, lexicographic).

Definition at line 395 of file BaselineUtils.cc.

405  {
406 
407  typedef typename det::HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT> HeavyFootprint;
409 
410  // when doing stray flux: the footprints and pixels, which we'll
411  // combine into the return 'strays' HeavyFootprint at the end.
413  std::vector<std::vector<afwGeom::Span>> straySpans(tfoots.size());
417 
418  int ix0 = img.getX0();
419  int iy0 = img.getY0();
420  geom::Box2I sumbb = tsum->getBBox();
421  int sumx0 = sumbb.getMinX();
422  int sumy0 = sumbb.getMinY();
423 
424  for (size_t i=0; i<tfoots.size(); ++i) {
425  strayfoot.push_back(PTR(det::Footprint)());
427  straymask.push_back(std::vector<MaskPixelT>());
429  }
430 
431  bool always = (strayFluxOptions & STRAYFLUX_TO_POINT_SOURCES_ALWAYS);
432 
433  typedef std::uint16_t itype;
434  PTR(image::Image<itype>) nearest;
435 
436  if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
437  // Compute the map of which footprint is closest to each
438  // pixel in the bbox.
439  typedef std::uint16_t dtype;
440  PTR(image::Image<dtype>) dist(new image::Image<dtype>(sumbb));
441  nearest = PTR(image::Image<itype>)(new image::Image<itype>(sumbb));
442 
444  std::vector<PTR(det::Footprint)>* footlist = &tfoots;
445 
446  if (!always && ispsf.size()) {
447  // create a temp list that has empty footprints in place
448  // of all the point sources.
449  auto empty = std::make_shared<det::Footprint>();
450  empty->setPeakSchema(foot.getPeaks().getSchema());
451  for (size_t i=0; i<tfoots.size(); ++i) {
452  if (ispsf[i]) {
453  templist.push_back(empty);
454  } else {
455  templist.push_back(tfoots[i]);
456  }
457  }
458  footlist = &templist;
459  }
460  nearestFootprint(*footlist, nearest, dist);
461  }
462 
463  // Go through the (parent) Footprint looking for stray flux:
464  // pixels that are not claimed by any template, and positive.
465  for (afwGeom::Span const & s : *foot.getSpans()) {
466  int y = s.getY();
467  int x0 = s.getX0();
468  int x1 = s.getX1();
469  typename ImageT::x_iterator tsum_it =
470  tsum->row_begin(y - sumy0) + (x0 - sumx0);
471  typename MaskedImageT::x_iterator in_it =
472  img.row_begin(y - iy0) + (x0 - ix0);
473  double contrib[tfoots.size()];
474 
475  for (int x = x0; x <= x1; ++x, ++tsum_it, ++in_it) {
476  // Skip pixels that are covered by at least one
477  // template (*tsum_it > 0) or the input is not
478  // positive (*in_it <= 0).
479  if ((*tsum_it > 0) || (*in_it).image() <= 0) {
480  continue;
481  }
482 
483  if (strayFluxOptions & STRAYFLUX_R_TO_FOOTPRINT) {
484  // we'll compute these just-in-time
485  for (size_t i=0; i<tfoots.size(); ++i) {
486  contrib[i] = -1.0;
487  }
488  } else if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
489  for (size_t i=0; i<tfoots.size(); ++i) {
490  contrib[i] = 0.0;
491  }
492  int i = nearest->get0(x, y);
493  contrib[i] = 1.0;
494  } else {
495  // R_TO_PEAK
496  for (size_t i=0; i<tfoots.size(); ++i) {
497  // Split the stray flux by 1/(1+r^2) to peaks
498  int dx, dy;
499  dx = pkx[i] - x;
500  dy = pky[i] - y;
501  contrib[i] = 1. / (1. + dx*dx + dy*dy);
502  }
503  }
504 
505  // Round 1: skip point sources unless STRAYFLUX_TO_POINT_SOURCES_ALWAYS
506  // are we going to assign stray flux to ptsrcs?
507  bool ptsrcs = always;
508  double csum = 0.;
509  for (size_t i=0; i<tfoots.size(); ++i) {
510  // if we're skipping point sources and this is a point source...
511  if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
512  continue;
513  }
514  if (contrib[i] == -1.0) {
515  contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
516  }
517  csum += contrib[i];
518  }
519  if ((csum == 0.) &&
520  (strayFluxOptions &
522  // No extended sources -- assign to pt sources
523  //LOGL_DEBUG(_log, "necessary to assign stray flux to point sources");
524  ptsrcs = true;
525  for (size_t i=0; i<tfoots.size(); ++i) {
526  if (contrib[i] == -1.0) {
527  contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
528  }
529  csum += contrib[i];
530  }
531  }
532 
533  // Drop small contributions...
534  double strayclip = (clipStrayFluxFraction * csum);
535  csum = 0.;
536  for (size_t i=0; i<tfoots.size(); ++i) {
537  // skip ptsrcs?
538  if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
539  contrib[i] = 0.;
540  continue;
541  }
542  // skip small contributions
543  if (contrib[i] < strayclip) {
544  contrib[i] = 0.;
545  continue;
546  }
547  csum += contrib[i];
548  }
549 
550  for (size_t i=0; i<tfoots.size(); ++i) {
551  if (contrib[i] == 0.) {
552  continue;
553  }
554  // the stray flux to give to template i
555  double p = (contrib[i] / csum) * (*in_it).image();
556 
557  if (!strayfoot[i]) {
558  strayfoot[i] = std::make_shared<det::Footprint>();
559  strayfoot[i]->setPeakSchema(foot.getPeaks().getSchema());
560  }
561  straySpans[i].push_back(afwGeom::Span(y, x, x));
562  straypix[i].push_back(p);
563  straymask[i].push_back((*in_it).mask());
564  strayvar[i].push_back((*in_it).variance());
565  }
566  }
567  }
568 
569  // Store the stray flux in HeavyFootprints
570  for (size_t i=0; i<tfoots.size(); ++i) {
571  if (strayfoot[i]) {
572  strayfoot[i]->setSpans(std::make_shared<afwGeom::SpanSet>(straySpans[i]));
573  }
574  if (!strayfoot[i]) {
575  strays.push_back(HeavyFootprintPtrT());
576  } else {
580  HeavyFootprintPtrT heavy(new HeavyFootprint(*strayfoot[i]));
581  ndarray::Array<ImagePixelT,1,1> himg = heavy->getImageArray();
588 
589  assert((size_t)strayfoot[i]->getArea() == straypix[i].size());
590 
591  for (spix = straypix[i].begin(),
592  smask = straymask[i].begin(),
593  svar = strayvar [i].begin(),
594  hpix = himg.begin(),
595  mpix = heavy->getMaskArray().begin(),
596  vpix = heavy->getVarianceArray().begin();
597  spix != straypix[i].end();
598  ++spix, ++smask, ++svar, ++hpix, ++mpix, ++vpix) {
599  *hpix = *spix;
600  *mpix = *smask;
601  *vpix = *svar;
602  }
603  strays.push_back(heavy);
604  }
605  }
606 }
A range of pixels within one row of an Image.
Definition: Span.h:47
static const int STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY
Definition: BaselineUtils.h:63
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
int y
Definition: SpanSet.cc:49
MaskedImageIterator< typename Image::x_iterator, typename Mask::x_iterator, typename Variance::x_iterator > x_iterator
An iterator to a row of a MaskedImage.
Definition: MaskedImage.h:556
T end(T... args)
A set of pixels in an Image, including those pixels&#39; actual values.
FastFinder::Iterator Iterator
Definition: FastFinder.cc:179
T push_back(T... args)
static const int STRAYFLUX_NEAREST_FOOTPRINT
Definition: BaselineUtils.h:68
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:62
double x
int getMinX() const noexcept
Definition: Box.h:157
T size(T... args)
STL class.
T begin(T... args)
static const int STRAYFLUX_TO_POINT_SOURCES_ALWAYS
Definition: BaselineUtils.h:64
An integer coordinate rectangle.
Definition: Box.h:55
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:58
int getMinY() const noexcept
Definition: Box.h:158
boost::shared_ptr< lsst::afw::detection::HeavyFootprint< ImagePixelT > MaskPixelT, VariancePixelT > HeavyFootprintPtrT
Definition: BaselineUtils.h:36
#define PTR(...)
Definition: base.h:41

◆ _sum_templates()

template<typename ImagePixelT , typename MaskPixelT , typename VariancePixelT >
void lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::_sum_templates ( std::vector< ImagePtrT timgs,
ImagePtrT  tsum 
)
static

Definition at line 611 of file BaselineUtils.cc.

612  {
613  geom::Box2I sumbb = tsum->getBBox();
614  int sumx0 = sumbb.getMinX();
615  int sumy0 = sumbb.getMinY();
616 
617  // Compute tsum = the sum of templates
618  for (size_t i=0; i<timgs.size(); ++i) {
619  ImagePtrT timg = timgs[i];
620  geom::Box2I tbb = timg->getBBox();
621  int tx0 = tbb.getMinX();
622  int ty0 = tbb.getMinY();
623  // To handle "ramped" templates that can extend outside the
624  // parent, clip the bbox. Note that we saved tx0,ty0 BEFORE
625  // doing this!
626  tbb.clip(sumbb);
627  int copyx0 = tbb.getMinX();
628  // Here we iterate over the template bbox -- we could instead
629  // iterate over the "tfoot"s.
630  for (int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
631  typename ImageT::x_iterator in_it = timg->row_begin(y - ty0) + (copyx0 - tx0);
632  typename ImageT::x_iterator inend = in_it + tbb.getWidth();
633  typename ImageT::x_iterator tsum_it =
634  tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
635  for (; in_it != inend; ++in_it, ++tsum_it) {
636  *tsum_it += std::max((ImagePixelT)0., static_cast<ImagePixelT>(*in_it));
637  }
638  }
639  }
640 
641 }
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
int y
Definition: SpanSet.cc:49
int getMaxY() const noexcept
Definition: Box.h:162
int getWidth() const noexcept
Definition: Box.h:187
T max(T... args)
int getMinX() const noexcept
Definition: Box.h:157
T size(T... args)
void clip(Box2I const &other) noexcept
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:189
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
Definition: BaselineUtils.h:28

◆ apportionFlux()

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
std::vector< typename boost::shared_ptr< image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT >)> lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::apportionFlux ( MaskedImageT const &  img,
lsst::afw::detection::Footprint const &  foot,
std::vector< typename boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > >>  templates,
std::vector< std::shared_ptr< lsst::afw::detection::Footprint > >  templ_footprints,
ImagePtrT  templ_sum,
std::vector< bool > const &  ispsf,
std::vector< int > const &  pkx,
std::vector< int > const &  pky,
std::vector< std::shared_ptr< typename lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > > &  strays,
int  strayFluxOptions,
double  clipStrayFluxFraction 
)
static

Splits flux in a given image img, within a given footprint foot, among a number of templates timgs,tfoots.

This is where actual "deblending" takes place.

timgs* and tfoots MUST be the same length.

Flux is assigned to templates according to their relative heights at each pixel.

If strayFluxOptions includes ASSIGN_STRAYFLUX, then "stray flux" – 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.

If strayFluxOptions includes STRAYFLUX_R_TO_FOOTPRINT, the stray flux is distributed to the footprints based on 1/(1+r^2) of the minimum distance from the stray flux to footprint.

If strayFluxOptions includes "STRAYFLUX_NEAREST_FOOTPRINT*, the stray flux is assigned to the footprint with lowest L-1 (Manhattan) distance to the stray flux.

Otherwise, stray flux is assigned based on (1/(1+r^2) from the peaks.

If strayFluxOptions includes STRAYFLUX_TO_POINT_SOURCES_ALWAYS, then point sources are always included in the 1/(1+r^2) splitting. Otherwise, if STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY, point sources are included only if there are no extended sources nearby.

If any stray-flux portion is less than clipStrayFluxFraction, it is clipped to zero.

When doing stray flux, the "strays" arg is used as an extra return value, the stray flux assigned to each template.

When doing stray flux, the ispsf, pkx, and pky arrays are required. They give the peak x,y coords plus whether the peak is believed (by the deblender) to be a point source. pkx and pky MUST be the same length as timgs. If ispsf has nonzero length, it MUST be the same length as timgs.

If tsum is given, is it set to the sum of max(0, template).

The return value is a vector of MaskedImages containing the flux assigned to each template.

Definition at line 694 of file BaselineUtils.cc.

705  {
706 
707  if (timgs.size() != tfoots.size()) {
709  (boost::format("Template images must be the same length as template footprints (%d vs %d)")
710  % timgs.size() % tfoots.size()).str());
711  }
712 
713  for (size_t i=0; i<timgs.size(); ++i) {
714  if (!timgs[i]->getBBox().contains(tfoots[i]->getBBox())) {
716  "Template image MUST contain template footprint");
717  }
718  if (!img.getBBox().contains(foot.getBBox())) {
720  "Image bbox MUST contain parent footprint");
721  }
722  // template bounding-boxes *can* extend outside the parent
723  // footprint if we are ramping templates with significant flux
724  // at the edges. We handle this below.
725  }
726 
727  // the apportioned flux return value
729 
730  LOG_LOGGER _log = LOG_GET("meas.deblender.apportionFlux");
731  bool findStrayFlux = (strayFluxOptions & ASSIGN_STRAYFLUX);
732 
733  int ix0 = img.getX0();
734  int iy0 = img.getY0();
735  geom::Box2I fbb = foot.getBBox();
736 
737  if (!tsum) {
738  tsum = ImagePtrT(new ImageT(fbb.getDimensions()));
739  tsum->setXY0(fbb.getMinX(), fbb.getMinY());
740  }
741 
742  if (!tsum->getBBox().contains(foot.getBBox())) {
744  "Template sum image MUST contain parent footprint");
745  }
746 
747  geom::Box2I sumbb = tsum->getBBox();
748  int sumx0 = sumbb.getMinX();
749  int sumy0 = sumbb.getMinY();
750 
751  _sum_templates(timgs, tsum);
752 
753  // Compute flux portions
754  for (size_t i=0; i<timgs.size(); ++i) {
755  ImagePtrT timg = timgs[i];
756  // Initialize return value:
757  MaskedImagePtrT port(new MaskedImageT(timg->getDimensions()));
758  port->setXY0(timg->getXY0());
759  portions.push_back(port);
760 
761  // Split flux = image * template / tsum
762  geom::Box2I tbb = timg->getBBox();
763  int tx0 = tbb.getMinX();
764  int ty0 = tbb.getMinY();
765  // As above
766  tbb.clip(sumbb);
767  int copyx0 = tbb.getMinX();
768  for (int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
769  typename MaskedImageT::x_iterator in_it =
770  img.row_begin(y - iy0) + (copyx0 - ix0);
771  typename ImageT::x_iterator tptr =
772  timg->row_begin(y - ty0) + (copyx0 - tx0);
773  typename ImageT::x_iterator tend = tptr + tbb.getWidth();
774  typename ImageT::x_iterator tsum_it =
775  tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
776  typename MaskedImageT::x_iterator out_it =
777  port->row_begin(y - ty0) + (copyx0 - tx0);
778  for (; tptr != tend; ++tptr, ++in_it, ++out_it, ++tsum_it) {
779  if (*tsum_it == 0) {
780  continue;
781  }
782  double frac = std::max((ImagePixelT)0., static_cast<ImagePixelT>(*tptr)) / (*tsum_it);
783  //if (frac == 0) {
784  // treat mask planes differently?
785  // }
786  out_it.mask() = (*in_it).mask();
787  out_it.variance() = (*in_it).variance();
788  out_it.image() = (*in_it).image() * frac;
789  }
790  }
791  }
792 
793  if (findStrayFlux) {
794  if ((ispsf.size() > 0) && (ispsf.size() != timgs.size())) {
796  (boost::format("'ispsf' must be the same length as templates (%d vs %d)")
797  % ispsf.size() % timgs.size()).str());
798  }
799  if ((pkx.size() != timgs.size()) || (pky.size() != timgs.size())) {
801  (boost::format("'pkx' and 'pky' must be the same length as templates (%d,%d vs %d)")
802  % pkx.size() % pky.size() % timgs.size()).str());
803  }
804  _find_stray_flux(foot, tsum, img, strayFluxOptions, tfoots,
805  ispsf, pkx, pky, clipStrayFluxFraction, strays);
806  }
807  return portions;
808 }
Extent2I const getDimensions() const noexcept
Definition: Box.h:186
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
#define LOG_LOGGER
Definition: Log.h:703
lsst::afw::image::Image< ImagePixelT > ImageT
Definition: BaselineUtils.h:27
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
int y
Definition: SpanSet.cc:49
static void _find_stray_flux(lsst::afw::detection::Footprint const &foot, ImagePtrT tsum, MaskedImageT const &img, int strayFluxOptions, std::vector< std::shared_ptr< lsst::afw::detection::Footprint > > tfoots, std::vector< bool > const &ispsf, std::vector< int > const &pkx, std::vector< int > const &pky, double clipStrayFluxFraction, std::vector< std::shared_ptr< typename lsst::afw::detection::HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > > > &strays)
MaskedImageIterator< typename Image::x_iterator, typename Mask::x_iterator, typename Variance::x_iterator > x_iterator
An iterator to a row of a MaskedImage.
Definition: MaskedImage.h:556
lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > MaskedImageT
Definition: BaselineUtils.h:25
T push_back(T... args)
int getMaxY() const noexcept
Definition: Box.h:162
int getWidth() const noexcept
Definition: Box.h:187
T max(T... args)
int getMinX() const noexcept
Definition: Box.h:157
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
static void _sum_templates(std::vector< ImagePtrT > timgs, ImagePtrT tsum)
void clip(Box2I const &other) noexcept
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:189
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT > MaskedImagePtrT
Definition: BaselineUtils.h:26
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
Definition: BaselineUtils.h:28
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104

◆ buildSymmetricTemplate()

template<typename ImagePixelT , typename MaskPixelT , typename VariancePixelT >
std::pair< typename boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > >, typename boost::shared_ptr< lsst::afw::detection::Footprint > > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::buildSymmetricTemplate ( MaskedImageT const &  img,
lsst::afw::detection::Footprint const &  foot,
lsst::afw::detection::PeakRecord const &  pk,
double  sigma1,
bool  minZero,
bool  patchEdge,
bool *  patchedEdges 
)
static

Given an img, footprint foot, and peak, creates a symmetric template around the peak; produce a MaskedImage and Footprint describing a footprint where: output pixels (cx + dx, cy + dy) and (cx - dx, cy - dy) = min(input pixels (cx + dx, cy + dy) and (cx - dx, cy - dy))

If patchEdge is true and if the footprint touches pixels with the EDGE bit set, then for spans whose symmetric mirror are outside the image, the symmetric footprint is grown to include them and their pixel values are stored.

Definition at line 1191 of file BaselineUtils.cc.

1198  {
1199 
1200  typedef typename MaskedImageT::const_xy_locator xy_loc;
1201 
1202  *patchedEdges = false;
1203 
1204  int cx = peak.getIx();
1205  int cy = peak.getIy();
1206 
1207  LOG_LOGGER _log = LOG_GET("meas.deblender.symmetricFootprint");
1208 
1209  if (!img.getBBox(image::PARENT).contains(foot.getBBox())) {
1210  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError, "Image too small for footprint");
1211  }
1212 
1213  FootprintPtrT sfoot = symmetrizeFootprint(foot, cx, cy);
1214 
1215  if (!sfoot) {
1217  }
1218 
1219  if (!img.getBBox(image::PARENT).contains(sfoot->getBBox())) {
1221  "Image too small for symmetrized footprint");
1222  }
1223  afwGeom::SpanSet const & spans = *sfoot->getSpans();
1224 
1225  // does this footprint touch an EDGE?
1226  bool touchesEdge = false;
1227  if (patchEdge) {
1228  LOGL_DEBUG(_log, "Checking footprint for EDGE bits");
1229  MaskPtrT mask = img.getMask();
1230  bool edge = false;
1231  MaskPixelT edgebit = mask->getPlaneBitMask("EDGE");
1232  for (afwGeom::SpanSet::const_iterator fwd=spans.begin();
1233  fwd != spans.end(); ++fwd) {
1234  int x0 = fwd->getX0();
1235  int x1 = fwd->getX1();
1236  typename MaskT::x_iterator xiter =
1237  mask->x_at(x0 - mask->getX0(), fwd->getY() - mask->getY0());
1238  for (int x=x0; x<=x1; ++x, ++xiter) {
1239  if ((*xiter) & edgebit) {
1240  edge = true;
1241  break;
1242  }
1243  }
1244  if (edge)
1245  break;
1246  }
1247  if (edge) {
1248  LOGL_DEBUG(_log, "Footprint includes an EDGE pixel.");
1249  touchesEdge = true;
1250  }
1251  }
1252 
1253  // The result image:
1254  ImagePtrT targetimg(new ImageT(sfoot->getBBox()));
1255 
1257  afwGeom::SpanSet::const_iterator back = spans.end()-1;
1258 
1259  ImagePtrT theimg = img.getImage();
1260 
1261  for (; fwd <= back; fwd++, back--) {
1262  int fy = fwd->getY();
1263  int by = back->getY();
1264 
1265  for (int fx=fwd->getX0(), bx=back->getX1();
1266  fx <= fwd->getX1();
1267  fx++, bx--) {
1268  // FIXME -- CURRENTLY WE IGNORE THE MASK PLANE! options
1269  // include ORing the mask bits, or being clever about
1270  // ignoring some masked pixels, or copying the mask bits
1271  // of the min pixel
1272 
1273  // We have already checked the bounding box, so this should always be satisfied
1274  assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(fx, fy)));
1275  assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(bx, by)));
1276 
1277  // FIXME -- we could do this with image iterators instead.
1278  // But first profile to show that it's necessary and an
1279  // improvement.
1280  ImagePixelT pixf = theimg->get0(fx, fy);
1281  ImagePixelT pixb = theimg->get0(bx, by);
1282  ImagePixelT pix = std::min(pixf, pixb);
1283  if (minZero) {
1284  pix = std::max(pix, static_cast<ImagePixelT>(0));
1285  }
1286  targetimg->set0(fx, fy, pix);
1287  targetimg->set0(bx, by, pix);
1288 
1289  }
1290  }
1291 
1292  if (touchesEdge) {
1293  // Find spans whose mirrors fall outside the image bounds,
1294  // grow the footprint to include those spans, and plug in
1295  // their pixel values.
1296  geom::Box2I bb = sfoot->getBBox();
1297 
1298  // Actually, it's not necessarily the IMAGE bounds that count
1299  //-- the footprint may not go right to the image edge.
1300  //geom::Box2I imbb = img.getBBox();
1301  geom::Box2I imbb = foot.getBBox();
1302 
1303  LOGL_DEBUG(_log, "Footprint touches EDGE: start bbox [%i,%i],[%i,%i]",
1304  bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1305  // original footprint spans
1306  const afwGeom::SpanSet & ospans = *foot.getSpans();
1307  for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1308  int y = fwd->getY();
1309  int x = fwd->getX0();
1310  // mirrored coords
1311  int ym = cy + (cy - y);
1312  int xm = cx + (cx - x);
1313  if (!imbb.contains(geom::Point2I(xm, ym))) {
1314  bb.include(geom::Point2I(x, y));
1315  }
1316  x = fwd->getX1();
1317  xm = cx + (cx - x);
1318  if (!imbb.contains(geom::Point2I(xm, ym))) {
1319  bb.include(geom::Point2I(x, y));
1320  }
1321  }
1322  LOGL_DEBUG(_log, "Footprint touches EDGE: grown bbox [%i,%i],[%i,%i]",
1323  bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1324 
1325  // New template image
1326  ImagePtrT targetimg2(new ImageT(bb));
1327  sfoot->getSpans()->copyImage(*targetimg, *targetimg2);
1328 
1329  LOGL_DEBUG(_log, "Symmetric footprint spans:");
1330  const afwGeom::SpanSet & sspans = *sfoot->getSpans();
1331  for (fwd = sspans.begin(); fwd != sspans.end(); ++fwd) {
1332  LOGL_DEBUG(_log, " %s", fwd->toString().c_str());
1333  }
1334 
1335  // copy original 'img' pixels for the portion of spans whose
1336  // mirrors are out of bounds.
1337  std::vector<afwGeom::Span> newSpans(sfoot->getSpans()->begin(), sfoot->getSpans()->end());
1338  for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1339  int y = fwd->getY();
1340  int x0 = fwd->getX0();
1341  int x1 = fwd->getX1();
1342  // mirrored coords
1343  int ym = cy + (cy - y);
1344  int xm0 = cx + (cx - x0);
1345  int xm1 = cx + (cx - x1);
1346  bool in0 = imbb.contains(geom::Point2I(xm0, ym));
1347  bool in1 = imbb.contains(geom::Point2I(xm1, ym));
1348  if (in0 && in1) {
1349  // both endpoints of the symmetric span are in bounds; nothing to do
1350  continue;
1351  }
1352  // clip to the part of the span where the mirror is out of bounds
1353  if (in0) {
1354  // the mirror of x0 is in-bounds; move x0 to be the first pixel
1355  // whose mirror would be out-of-bounds
1356  x0 = cx + (cx - (imbb.getMinX() - 1));
1357  }
1358  if (in1) {
1359  x1 = cx + (cx - (imbb.getMaxX() + 1));
1360  }
1361  LOGL_DEBUG(_log, "Span y=%i, x=[%i,%i] has mirror (%i,[%i,%i]) out-of-bounds; clipped to %i,[%i,%i]",
1362  y, fwd->getX0(), fwd->getX1(), ym, xm1, xm0, y, x0, x1);
1363  typename MaskedImageT::x_iterator initer =
1364  img.x_at(x0 - img.getX0(), y - img.getY0());
1365  typename ImageT::x_iterator outiter =
1366  targetimg2->x_at(x0 - targetimg2->getX0(), y - targetimg2->getY0());
1367  for (int x=x0; x<=x1; ++x, ++outiter, ++initer) {
1368  *outiter = initer.image();
1369  }
1370  newSpans.push_back(afwGeom::Span(y, x0, x1));
1371  }
1372  sfoot->setSpans(std::make_shared<afwGeom::SpanSet>(std::move(newSpans)));
1373  targetimg = targetimg2;
1374  }
1375 
1376  *patchedEdges = touchesEdge;
1377  return std::pair<ImagePtrT, FootprintPtrT>(targetimg, sfoot);
1378 }
const_MaskedImageLocator< typename Image::xy_locator, typename Mask::xy_locator, typename Variance::xy_locator > const_xy_locator
A const_locator for a MaskedImage.
Definition: MaskedImage.h:581
#define LOG_LOGGER
Definition: Log.h:703
afw::table::Key< afw::table::Array< MaskPixelT > > mask
const_iterator end() const
Definition: SpanSet.h:89
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
lsst::afw::image::Image< ImagePixelT > ImageT
Definition: BaselineUtils.h:27
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
int y
Definition: SpanSet.cc:49
MaskedImageIterator< typename Image::x_iterator, typename Mask::x_iterator, typename Variance::x_iterator > x_iterator
An iterator to a row of a MaskedImage.
Definition: MaskedImage.h:556
boost::shared_ptr< lsst::afw::detection::Footprint > FootprintPtrT
Definition: BaselineUtils.h:33
const_iterator begin() const
Definition: SpanSet.h:88
static boost::shared_ptr< lsst::afw::detection::Footprint > symmetrizeFootprint(lsst::afw::detection::Footprint const &foot, int cx, int cy)
Given a Footprint foot and peak cx,cy, returns a Footprint that is symmetric around the peak (with tw...
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
T min(T... args)
boost::shared_ptr< lsst::afw::image::Mask< MaskPixelT > > MaskPtrT
Definition: BaselineUtils.h:30
int getMaxY() const noexcept
Definition: Box.h:162
T max(T... args)
T move(T... args)
int getMaxX() const noexcept
Definition: Box.h:161
double x
int getMinX() const noexcept
Definition: Box.h:157
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
std::vector< Span >::const_iterator const_iterator
Definition: SpanSet.h:80
void include(Point2I const &point)
Expand this to ensure that this->contains(point).
Definition: Box.cc:152
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
Definition: Box.cc:114
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
Definition: BaselineUtils.h:28

◆ getSignificantEdgePixels()

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
std::shared_ptr< det::Footprint > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::getSignificantEdgePixels ( ImagePtrT  ,
std::shared_ptr< lsst::afw::detection::Footprint ,
ImagePixelT  threshold 
)
static

Returns a list of pixels that are on the edge of the given Footprint sfoot* in image img, above threshold thresh.

Definition at line 1420 of file BaselineUtils.cc.

1422  {
1423  LOG_LOGGER _log = LOG_GET("meas.deblender.getSignificantEdgePixels");
1424 
1425 
1426  auto significant = std::make_shared<det::Footprint>();
1427  significant->setPeakSchema(sfoot->getPeaks().getSchema());
1428 
1429  int const x0 = img->getX0(), y0 = img->getY0();
1430  std::shared_ptr<afwGeom::SpanSet> edgeSpans = sfoot->getSpans()->findEdgePixels();
1431  std::vector<afwGeom::Span> tmpSpans;
1432  for (afwGeom::SpanSet::const_iterator ss = edgeSpans->begin(); ss != edgeSpans->end(); ++ss) {
1433  afwGeom::Span const& span = *ss;
1434  int const y = span.getY();
1435  int x = span.getX0();
1436  typename ImageT::const_x_iterator iter = img->x_at(x - x0, y - y0);
1437  bool onSpan = false; // Are we in a span of interest
1438  int xSpan; // Starting x of span
1439  for (; x <= span.getX1(); ++x, ++iter) {
1440  if (*iter >= thresh) {
1441  onSpan = true;
1442  xSpan = x;
1443  } else if (onSpan) {
1444  onSpan = false;
1445  tmpSpans.push_back(afwGeom::Span(y, xSpan, x - 1));
1446  }
1447  }
1448  if (onSpan) {
1449  tmpSpans.push_back(afwGeom::Span(y, xSpan, span.getX1()));
1450  }
1451  }
1452  significant->setSpans(std::make_shared<afwGeom::SpanSet>(std::move(tmpSpans)));
1453  return significant;
1454 }
#define LOG_LOGGER
Definition: Log.h:703
A range of pixels within one row of an Image.
Definition: Span.h:47
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
Definition: ImageBase.h:141
int y
Definition: SpanSet.cc:49
T push_back(T... args)
T move(T... args)
double x
STL class.
std::vector< Span >::const_iterator const_iterator
Definition: SpanSet.h:80
int getX1() const noexcept
Return the ending x-value.
Definition: Span.h:74
int getY() const noexcept
Return the y-value.
Definition: Span.h:76
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
int getX0() const noexcept
Return the starting x-value.
Definition: Span.h:72

◆ hasSignificantFluxAtEdge()

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
bool lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::hasSignificantFluxAtEdge ( ImagePtrT  ,
std::shared_ptr< lsst::afw::detection::Footprint ,
ImagePixelT  threshold 
)
static

Returns true if the given Footprint sfoot in image img has flux above value thresh at its edge.

Definition at line 1387 of file BaselineUtils.cc.

1389  {
1390 
1391  LOG_LOGGER _log = LOG_GET("meas.deblender.hasSignificantFluxAtEdge");
1392 
1393  // Find edge template pixels with significant flux -- perhaps
1394  // because their symmetric pixels were outside the footprint?
1395  // (clipped by an image edge, etc)
1396  std::shared_ptr<afwGeom::SpanSet> spans = sfoot->getSpans()->findEdgePixels();
1397 
1398  for (afwGeom::SpanSet::const_iterator sp = spans->begin(); sp != spans->end(); ++sp) {
1399  int const y = sp->getY();
1400  int const x0 = sp->getX0();
1401  int const x1 = sp->getX1();
1402  int x;
1403  typename ImageT::const_x_iterator xiter;
1404  for (xiter = img->x_at(x0 - img->getX0(), y - img->getY0()), x=x0; x<=x1; ++x, ++xiter) {
1405  if (*xiter >= thresh) {
1406  return true;
1407  }
1408  }
1409  }
1410  return false;
1411 }
#define LOG_LOGGER
Definition: Log.h:703
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
Definition: ImageBase.h:141
int y
Definition: SpanSet.cc:49
double x
std::vector< Span >::const_iterator const_iterator
Definition: SpanSet.h:80
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75

◆ makeMonotonic()

template<typename ImagePixelT , typename MaskPixelT , typename VariancePixelT >
void lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::makeMonotonic ( ImageT img,
lsst::afw::detection::PeakRecord const &  pk 
)
static

Given an image mimg and Peak location peak, overwrite mimg so that pixels further from the peak have values smaller than those close to the peak; make the profile monotonic-decreasing.

The exact algorithm is a little more complicated than that. The basic idea is of "casting a shadow" from a pixel to pixels farther from the peak in the same direction. Done naively, this results in very narrow "shadows" and ragged profiles. A tweak is to make the shadows "fatter" – make a pixel shadow a wedge of pixels – but if one does this naively, the wedge gets wider and wider too quickly. The algorithm works out from the peak in square "rings" of pixels, so if a pixel shadows a wedge 30 degrees wide, in the next ring of pixels the shadowed pixel at largest angle from the shadowing pixel will shade a yet-larger wedge, expanding the shadowing angle. To reduce this effect, we work in chunks of 5 pixels in radius, only copying the intermediate pixels to the "shadowing" image at the end of each chunk.

Currently the mask and variance planes of the input are totally ignored.

For illustration, run tests/monotonic.py and look at im*.png

Definition at line 227 of file BaselineUtils.cc.

229  {
230 
231  int cx = peak.getIx();
232  int cy = peak.getIy();
233  int ix0 = img.getX0();
234  int iy0 = img.getY0();
235  int iW = img.getWidth();
236  int iH = img.getHeight();
237 
238  ImagePtrT shadowingImg = ImagePtrT(new ImageT(img, true));
239 
240  int DW = std::max(cx - img.getX0(), img.getX0() + img.getWidth() - cx);
241  int DH = std::max(cy - img.getY0(), img.getY0() + img.getHeight() - cy);
242 
243  const int S = 5;
244 
245  // Work out from the peak in chunks of "S" pixels.
246  int s;
247  for (s = 0; s < std::max(DW,DH); s += S) {
248  int p;
249  for (p=0; p<S; p++) {
250  // visit pixels with L_inf distance = s + p from the
251  // center (ie, the s+p'th square ring of pixels)
252  // L is the half-length of the ring (box).
253  int L = s+p;
254  int x = L, y = -L;
255  int dx = 0, dy = 0; // initialized here to satisfy the
256  // compiler; initialized for real
257  // below (first time through loop)
258  /*
259  int i;
260  int leg;
261  for (i=0; i<(8*L); i++, x += dx, y += dy) {
262  if (i % (2*L) == 0) {
263  leg = (i/(2*L));
264  dx = ( leg % 2) * (-1 + 2*(leg/2));
265  dy = ((leg+1) % 2) * ( 1 - 2*(leg/2));
266  }
267  */
268 
269  /*
270  We visit pixels in a box of "radius" L, in this order:
271 
272  L=1:
273 
274  4 3 2
275  5 1
276  6 7 0
277 
278  L=2:
279 
280  8 7 6 5 4
281  9 3
282  10 2
283  11 1
284  12 13 14 15 0
285 
286  Note that the number of pixel visited is 8*L, and that we
287  change "dx" or "dy" each "2*L" steps.
288  */
289  for (int i=0; i<(8*L); i++, x += dx, y += dy) {
290  // time to change directions? (Note that this runs
291  // the first time through the loop, initializing dx,dy
292  // appropriately.)
293  if (i % (2*L) == 0) {
294  int leg = (i/(2*L));
295  // dx = [ 0, -1, 0, 1 ][leg]
296  dx = ( leg % 2) * (-1 + 2*(leg/2));
297  // dy = [ 1, 0, -1, 0 ][leg]
298  dy = ((leg+1) % 2) * ( 1 - 2*(leg/2));
299  }
300  //printf(" i=%i, leg=%i, dx=%i, dy=%i, x=%i, y=%i\n", i, leg, dx, dy, x, y);
301  int px = cx + x - ix0;
302  int py = cy + y - iy0;
303  // If the shadowing pixel is out of bounds, nothing to do.
304  if (px < 0 || px >= iW || py < 0 || py >= iH)
305  continue;
306  // The pixel casting the shadow
307  ImagePixelT pix = (*shadowingImg)(px,py);
308 
309  // Cast this pixel's shadow S pixels long in a cone.
310  // We compute the range of slopes (or inverse-slopes)
311  // shadowed by the pixel, [ds0,ds1]
312  double ds0, ds1;
313  // Range of slopes shadowed
314  const double A = 0.3;
315  int shx, shy;
316  int psx, psy;
317  // Are we traversing a vertical edge of the box?
318  if (dx == 0) {
319  // (if so, then "x" is +- L, so no div-by-zero)
320  ds0 = (double(y) / double(x)) - A;
321  ds1 = ds0 + 2.0 * A;
322  // cast the shadow on column x + sign(x)*shx
323  for (shx=1; shx<=S; shx++) {
324  int xsign = (x>0?1:-1);
325  // the column being shadowed
326  psx = cx + x + (xsign*shx) - ix0;
327  if (psx < 0 || psx >= iW)
328  continue;
329  // shadow covers a range of y values based on slope
330  for (shy = lround(shx * ds0);
331  shy <= lround(shx * ds1); shy++) {
332  psy = cy + y + xsign*shy - iy0;
333  if (psy < 0 || psy >= iH)
334  continue;
335  img(psx, psy) = std::min(img(psx, psy), pix);
336  }
337  }
338 
339  } else {
340  // We're traversing a horizontal edge of the box; y = +-L
341  ds0 = (double(x) / double(y)) - A;
342  ds1 = ds0 + 2.0 * A;
343  // Cast shadow on row y + sign(y)*shy
344  for (shy=1; shy<=S; shy++) {
345  int ysign = (y>0?1:-1);
346  psy = cy + y + (ysign*shy) - iy0;
347  if (psy < 0 || psy >= iH)
348  continue;
349  // shadow covers a range of x vals based on slope
350  for (shx = lround(shy * ds0);
351  shx <= lround(shy * ds1); shx++) {
352  psx = cx + x + ysign*shx - ix0;
353  if (psx < 0 || psx >= iW)
354  continue;
355  img(psx, psy) = std::min(img(psx, psy), pix);
356  }
357  }
358  }
359  }
360  }
361  shadowingImg->assign(img);
362  }
363 }
lsst::afw::image::Image< ImagePixelT > ImageT
Definition: BaselineUtils.h:27
int y
Definition: SpanSet.cc:49
T min(T... args)
T max(T... args)
double x
T lround(T... args)
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
Definition: BaselineUtils.h:28

◆ medianFilter()

template<typename ImagePixelT , typename MaskPixelT , typename VariancePixelT >
void lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::medianFilter ( ImageT const &  img,
ImageT out,
int  halfsize 
)
static

Run a spatial median filter over the given input img, writing the results to out.

halfsize is half the box size of the filter; ie, a halfsize of 50 means that each output ixel will be the median of the pixels in a 101 x 101-pixel box in the input image.

Margins are handled horribly: the median is computed only for pixels more than halfsize away from the edges; pixels near the edges are simply copied from the input img to out.

Mask and variance planes are, likewise, simply copied from img to out*.

Definition at line 149 of file BaselineUtils.cc.

151  {
152  int S = halfsize*2 + 1;
153  int SS = S*S;
154  typedef typename ImageT::xy_locator xy_loc;
155  xy_loc pix = img.xy_at(halfsize,halfsize);
157  for (int i=0; i<S; ++i) {
158  for (int j=0; j<S; ++j) {
159  locs.push_back(pix.cache_location(j-halfsize, i-halfsize));
160  }
161  }
162  int W = img.getWidth();
163  int H = img.getHeight();
164  ImagePixelT vals[S*S];
165  for (int y=halfsize; y<H-halfsize; ++y) {
166  xy_loc inpix = img.xy_at(halfsize, y), end = img.xy_at(W-halfsize, y);
167  for (typename ImageT::x_iterator optr = out.row_begin(y) + halfsize;
168  inpix != end; ++inpix.x(), ++optr) {
169  for (int i=0; i<SS; ++i)
170  vals[i] = inpix[locs[i]];
171  std::nth_element(vals, vals+SS/2, vals+SS);
172  *optr = vals[SS/2];
173  }
174  }
175 
176  // grumble grumble margins
177  for (int y=0; y<2*halfsize; ++y) {
178  int iy = y;
179  if (y >= halfsize)
180  iy = H - 1 - (y-halfsize);
181  typename ImageT::x_iterator optr = out.row_begin(iy);
182  typename ImageT::x_iterator iptr = img.row_begin(iy), end=img.row_end(iy);
183  for (; iptr != end; ++iptr,++optr)
184  *optr = *iptr;
185  }
186  for (int y=halfsize; y<H-halfsize; ++y) {
187  typename ImageT::x_iterator optr = out.row_begin(y);
188  typename ImageT::x_iterator iptr = img.row_begin(y), end=img.row_begin(y)+halfsize;
189  for (; iptr != end; ++iptr,++optr)
190  *optr = *iptr;
191  iptr = img.row_begin(y) + ((W-1) - halfsize);
192  end = img.row_begin(y) + (W-1);
193  optr = out.row_begin(y) + ((W-1) - halfsize);
194  for (; iptr != end; ++iptr,++optr)
195  *optr = *iptr;
196  }
197 
198 }
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
int y
Definition: SpanSet.cc:49
T push_back(T... args)
STL class.
T nth_element(T... args)
_view_t::xy_locator xy_locator
An xy_locator.
Definition: ImageBase.h:121
int end

◆ symmetrizeFootprint()

template<typename ImagePixelT , typename MaskPixelT , typename VariancePixelT >
boost::shared_ptr< lsst::afw::detection::Footprint > lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::symmetrizeFootprint ( lsst::afw::detection::Footprint const &  foot,
int  cx,
int  cy 
)
static

Given a Footprint foot and peak cx,cy, returns a Footprint that is symmetric around the peak (with twofold rotational symmetry) – the AND of the two symmetric halves.

Definition at line 976 of file BaselineUtils.cc.

978  {
979 
980  auto sfoot = std::make_shared<det::Footprint>();
981  sfoot->setPeakSchema(foot.getPeaks().getSchema());
982  afwGeom::SpanSet const & spans = *foot.getSpans();
983 
984  LOG_LOGGER _log = LOG_GET("meas.deblender.symmetrizeFootprint");
985 
986  // Find the Span containing the peak.
987  afwGeom::Span target(cy, cx, cx);
989  std::upper_bound(spans.begin(), spans.end(), target, span_compare);
990  // upper_bound returns the last position where "target" could be inserted;
991  // ie, the first Span larger than "target". The Span containing "target"
992  // should be peakspan-1 or (if the peak is on the first pixel in the span,
993  // peakspan.
994  afwGeom::Span sp;
995  if (peakspan == spans.begin()) {
996  sp = *peakspan;
997  if (!sp.contains(cx, cy)) {
998  LOGL_WARN(_log,
999  "Failed to find span containing (%i,%i): before the beginning of this footprint", cx, cy);
1000  return PTR(det::Footprint)();
1001  }
1002  } else {
1003  --peakspan;
1004  sp = *peakspan;
1005 
1006  if (!sp.contains(cx, cy)) {
1007  ++peakspan;
1008  sp = *peakspan;
1009  if (!sp.contains(cx, cy)) {
1010  geom::Box2I fbb = foot.getBBox();
1011  LOGL_WARN(_log, "Failed to find span containing (%i,%i): nearest is %i, [%i,%i]. "
1012  "Footprint bbox is [%i,%i],[%i,%i]",
1013  cx, cy, sp.getY(), sp.getX0(), sp.getX1(),
1014  fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY());
1015  return PTR(det::Footprint)();
1016  }
1017  }
1018  }
1019  LOGL_DEBUG(_log, "Span containing (%i,%i): (x=[%i,%i], y=%i)",
1020  cx, cy, sp.getX0(), sp.getX1(), sp.getY());
1021 
1022  // The symmetric templates are essentially an AND of the footprint
1023  // pixels and its 180-degree-rotated self, rotated around the
1024  // peak (cx,cy).
1025  //
1026  // We iterate forward and backward simultaneously, starting from
1027  // the span containing the peak and moving out, row by row.
1028  //
1029  // In the loop below, we search for the next pair of Spans that
1030  // overlap (in "dx" from the center), output the overlapping
1031  // portion of the Spans, and advance either the "fwd" or "back"
1032  // iterator. When we fail to find an overlapping pair of Spans,
1033  // we move on to the next row.
1034  //
1035  // [The following paragraph is somewhat obsoleted by the
1036  // RelativeSpanIterator class, which performs some of the renaming
1037  // and the dx,dy coords.]
1038  //
1039  // '''In reading the code, "forward", "advancing", etc, are all
1040  // from the perspective of the "fwd" iterator (the one going
1041  // forward through the Span list, from low to high Y and then low
1042  // to high X). It will help to imagine making a copy of the
1043  // footprint and rotating it around the center pixel by 180
1044  // degrees, so that "fwd" and "back" are both iterating the same
1045  // direction; we're then just finding the AND of those two
1046  // iterators, except we have to work in dx,dy coordinates rather
1047  // than original x,y coords, and the accessors for "back" are
1048  // opposite.'''
1049 
1050  RelativeSpanIterator fwd (peakspan, spans, cx, cy, true);
1051  RelativeSpanIterator back(peakspan, spans, cx, cy, false);
1052 
1053  int dy = 0;
1054  std::vector<afwGeom::Span> tmpSpans;
1055  while (fwd.notDone() && back.notDone()) {
1056  // forward and backward "y"; just symmetric around cy
1057  int fy = cy + dy;
1058  int by = cy - dy;
1059  // delta-x of the beginnings of the spans, for "fwd" and "back"
1060  int fdxlo = fwd.dxlo();
1061  int bdxlo = back.dxlo();
1062 
1063  // First find:
1064  // fend -- first span in the next row, or end(); ie,
1065  // the end of this row in the forward direction
1066  // bend -- the end of this row in the backward direction
1067  RelativeSpanIterator fend, bend;
1068  for (fend = fwd; fend.notDone(); ++fend) {
1069  if (fend.dy() != dy)
1070  break;
1071  }
1072  for (bend = back; bend.notDone(); ++bend) {
1073  if (bend.dy() != dy)
1074  break;
1075  }
1076 
1077  LOGL_DEBUG(_log, "dy=%i, fy=%i, fx=[%i, %i], by=%i, fx=[%i, %i], fdx=%i, bdx=%i",
1078  dy, fy, fwd.x0(), fwd.x1(), by, back.x0(), back.x1(),
1079  fdxlo, bdxlo);
1080 
1081  // Find possibly-overlapping span
1082  if (bdxlo > fdxlo) {
1083  LOGL_DEBUG(_log, "Advancing forward.");
1084  // While the "forward" span is entirely to the "left" of the "backward" span,
1085  // (in dx coords), ie, |---fwd---X X---back---|
1086  // and we are comparing the edges marked X
1087  while ((fwd != fend) && (fwd.dxhi() < bdxlo)) {
1088  fwd++;
1089  if (fwd == fend) {
1090  LOGL_DEBUG(_log, "Reached fend");
1091  } else {
1092  LOGL_DEBUG(_log, "Advanced to forward span %i, [%i, %i]",
1093  fy, fwd.x0(), fwd.x1());
1094  }
1095  }
1096  } else if (fdxlo > bdxlo) {
1097  LOGL_DEBUG(_log, "Advancing backward.");
1098  // While the "backward" span is entirely to the "left" of the "foreward" span,
1099  // (in dx coords), ie, |---back---X X---fwd---|
1100  // and we are comparing the edges marked X
1101  while ((back != bend) && (back.dxhi() < fdxlo)) {
1102  back++;
1103  if (back == bend) {
1104  LOGL_DEBUG(_log, "Reached bend");
1105  } else {
1106  LOGL_DEBUG(_log, "Advanced to backward span %i, [%i, %i]",
1107  by, back.x0(), back.x1());
1108  }
1109  }
1110  }
1111 
1112  if ((back == bend) || (fwd == fend)) {
1113  // We reached the end of the row without finding spans that could
1114  // overlap. Move onto the next dy.
1115  if (back == bend) {
1116  LOGL_DEBUG(_log, "Reached bend");
1117  }
1118  if (fwd == fend) {
1119  LOGL_DEBUG(_log, "Reached fend");
1120  }
1121  back = bend;
1122  fwd = fend;
1123  dy++;
1124  continue;
1125  }
1126 
1127  // Spans may overlap -- find the overlapping part.
1128  int dxlo = std::max(fwd.dxlo(), back.dxlo());
1129  int dxhi = std::min(fwd.dxhi(), back.dxhi());
1130  if (dxlo <= dxhi) {
1131  LOGL_DEBUG(_log, "Adding span fwd %i, [%i, %i], back %i, [%i, %i]",
1132  fy, cx+dxlo, cx+dxhi, by, cx-dxhi, cx-dxlo);
1133  tmpSpans.push_back(afwGeom::Span(fy, cx + dxlo, cx + dxhi));
1134  tmpSpans.push_back(afwGeom::Span(by, cx - dxhi, cx - dxlo));
1135  }
1136 
1137  // Advance the one whose "hi" edge is smallest
1138  if (fwd.dxhi() < back.dxhi()) {
1139  fwd++;
1140  if (fwd == fend) {
1141  LOGL_DEBUG(_log, "Stepped to fend");
1142  } else {
1143  LOGL_DEBUG(_log, "Stepped forward to span %i, [%i, %i]",
1144  fwd.y(), fwd.x0(), fwd.x1());
1145  }
1146  } else {
1147  back++;
1148  if (back == bend) {
1149  LOGL_DEBUG(_log, "Stepped to bend");
1150  } else {
1151  LOGL_DEBUG(_log, "Stepped backward to span %i, [%i, %i]",
1152  back.y(), back.x0(), back.x1());
1153  }
1154  }
1155 
1156  if ((back == bend) || (fwd == fend)) {
1157  // Reached the end of the row. On to the next dy!
1158  if (back == bend) {
1159  LOGL_DEBUG(_log, "Reached bend");
1160  }
1161  if (fwd == fend) {
1162  LOGL_DEBUG(_log, "Reached fend");
1163  }
1164  back = bend;
1165  fwd = fend;
1166  dy++;
1167  continue;
1168  }
1169 
1170  }
1171  sfoot->setSpans(std::make_shared<afwGeom::SpanSet>(std::move(tmpSpans)));
1172  return sfoot;
1173 }
#define LOG_LOGGER
Definition: Log.h:703
Key< Flag > const & target
const_iterator end() const
Definition: SpanSet.h:89
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
T upper_bound(T... args)
const_iterator begin() const
Definition: SpanSet.h:88
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
T min(T... args)
T push_back(T... args)
int getMaxY() const noexcept
Definition: Box.h:162
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
Definition: Log.h:536
T max(T... args)
T move(T... args)
int getMaxX() const noexcept
Definition: Box.h:161
Class to describe the properties of a detected object from an image.
Definition: Footprint.h:62
int getMinX() const noexcept
Definition: Box.h:157
STL class.
std::vector< Span >::const_iterator const_iterator
Definition: SpanSet.h:80
This is a convenience class used in symmetrizeFootprint, wrapping the idea of iterating through a Spa...
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158
#define PTR(...)
Definition: base.h:41

Member Data Documentation

◆ ASSIGN_STRAYFLUX

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::ASSIGN_STRAYFLUX = 0x1
static

Definition at line 62 of file BaselineUtils.h.

◆ STRAYFLUX_NEAREST_FOOTPRINT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::STRAYFLUX_NEAREST_FOOTPRINT = 0x10
static

Definition at line 68 of file BaselineUtils.h.

◆ STRAYFLUX_R_TO_FOOTPRINT

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::STRAYFLUX_R_TO_FOOTPRINT = 0x8
static

Definition at line 67 of file BaselineUtils.h.

◆ STRAYFLUX_TO_POINT_SOURCES_ALWAYS

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::STRAYFLUX_TO_POINT_SOURCES_ALWAYS = 0x4
static

Definition at line 64 of file BaselineUtils.h.

◆ STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY = 0x2
static

Definition at line 63 of file BaselineUtils.h.

◆ STRAYFLUX_TRIM

template<typename ImagePixelT , typename MaskPixelT = lsst::afw::image::MaskPixel, typename VariancePixelT = lsst::afw::image::VariancePixel>
const int lsst::meas::deblender::BaselineUtils< ImagePixelT, MaskPixelT, VariancePixelT >::STRAYFLUX_TRIM = 0x20
static

Definition at line 69 of file BaselineUtils.h.


The documentation for this class was generated from the following files: