LSSTApplications  18.1.0
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 393 of file BaselineUtils.cc.

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

◆ _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 609 of file BaselineUtils.cc.

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

703  {
704 
705  if (timgs.size() != tfoots.size()) {
707  (boost::format("Template images must be the same length as template footprints (%d vs %d)")
708  % timgs.size() % tfoots.size()).str());
709  }
710 
711  for (size_t i=0; i<timgs.size(); ++i) {
712  if (!timgs[i]->getBBox().contains(tfoots[i]->getBBox())) {
714  "Template image MUST contain template footprint");
715  }
716  if (!img.getBBox().contains(foot.getBBox())) {
718  "Image bbox MUST contain parent footprint");
719  }
720  // template bounding-boxes *can* extend outside the parent
721  // footprint if we are ramping templates with significant flux
722  // at the edges. We handle this below.
723  }
724 
725  // the apportioned flux return value
727 
728  LOG_LOGGER _log = LOG_GET("meas.deblender.apportionFlux");
729  bool findStrayFlux = (strayFluxOptions & ASSIGN_STRAYFLUX);
730 
731  int ix0 = img.getX0();
732  int iy0 = img.getY0();
733  afwGeom::Box2I fbb = foot.getBBox();
734 
735  if (!tsum) {
736  tsum = ImagePtrT(new ImageT(fbb.getDimensions()));
737  tsum->setXY0(fbb.getMinX(), fbb.getMinY());
738  }
739 
740  if (!tsum->getBBox().contains(foot.getBBox())) {
742  "Template sum image MUST contain parent footprint");
743  }
744 
745  afwGeom::Box2I sumbb = tsum->getBBox();
746  int sumx0 = sumbb.getMinX();
747  int sumy0 = sumbb.getMinY();
748 
749  _sum_templates(timgs, tsum);
750 
751  // Compute flux portions
752  for (size_t i=0; i<timgs.size(); ++i) {
753  ImagePtrT timg = timgs[i];
754  // Initialize return value:
755  MaskedImagePtrT port(new MaskedImageT(timg->getDimensions()));
756  port->setXY0(timg->getXY0());
757  portions.push_back(port);
758 
759  // Split flux = image * template / tsum
760  afwGeom::Box2I tbb = timg->getBBox();
761  int tx0 = tbb.getMinX();
762  int ty0 = tbb.getMinY();
763  // As above
764  tbb.clip(sumbb);
765  int copyx0 = tbb.getMinX();
766  for (int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
767  typename MaskedImageT::x_iterator in_it =
768  img.row_begin(y - iy0) + (copyx0 - ix0);
769  typename ImageT::x_iterator tptr =
770  timg->row_begin(y - ty0) + (copyx0 - tx0);
771  typename ImageT::x_iterator tend = tptr + tbb.getWidth();
772  typename ImageT::x_iterator tsum_it =
773  tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
774  typename MaskedImageT::x_iterator out_it =
775  port->row_begin(y - ty0) + (copyx0 - tx0);
776  for (; tptr != tend; ++tptr, ++in_it, ++out_it, ++tsum_it) {
777  if (*tsum_it == 0) {
778  continue;
779  }
780  double frac = std::max((ImagePixelT)0., static_cast<ImagePixelT>(*tptr)) / (*tsum_it);
781  //if (frac == 0) {
782  // treat mask planes differently?
783  // }
784  out_it.mask() = (*in_it).mask();
785  out_it.variance() = (*in_it).variance();
786  out_it.image() = (*in_it).image() * frac;
787  }
788  }
789  }
790 
791  if (findStrayFlux) {
792  if ((ispsf.size() > 0) && (ispsf.size() != timgs.size())) {
794  (boost::format("'ispsf' must be the same length as templates (%d vs %d)")
795  % ispsf.size() % timgs.size()).str());
796  }
797  if ((pkx.size() != timgs.size()) || (pky.size() != timgs.size())) {
799  (boost::format("'pkx' and 'pky' must be the same length as templates (%d,%d vs %d)")
800  % pkx.size() % pky.size() % timgs.size()).str());
801  }
802  _find_stray_flux(foot, tsum, img, strayFluxOptions, tfoots,
803  ispsf, pkx, pky, clipStrayFluxFraction, strays);
804  }
805  return portions;
806 }
Extent2I const getDimensions() const noexcept
Definition: Box.h:173
#define LOG_LOGGER
Definition: Log.h:688
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:134
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:557
lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > MaskedImageT
Definition: BaselineUtils.h:25
T push_back(T... args)
int getMaxY() const noexcept
Definition: Box.h:149
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
int getWidth() const noexcept
Definition: Box.h:174
T max(T... args)
int getMinX() const noexcept
Definition: Box.h:144
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:194
#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:54
int getMinY() const noexcept
Definition: Box.h:145
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 1189 of file BaselineUtils.cc.

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

1420  {
1421  LOG_LOGGER _log = LOG_GET("meas.deblender.getSignificantEdgePixels");
1422 
1423 
1424  auto significant = std::make_shared<det::Footprint>();
1425  significant->setPeakSchema(sfoot->getPeaks().getSchema());
1426 
1427  int const x0 = img->getX0(), y0 = img->getY0();
1428  std::shared_ptr<afwGeom::SpanSet> edgeSpans = sfoot->getSpans()->findEdgePixels();
1429  std::vector<afwGeom::Span> tmpSpans;
1430  for (afwGeom::SpanSet::const_iterator ss = edgeSpans->begin(); ss != edgeSpans->end(); ++ss) {
1431  afwGeom::Span const& span = *ss;
1432  int const y = span.getY();
1433  int x = span.getX0();
1434  typename ImageT::const_x_iterator iter = img->x_at(x - x0, y - y0);
1435  bool onSpan = false; // Are we in a span of interest
1436  int xSpan; // Starting x of span
1437  for (; x <= span.getX1(); ++x, ++iter) {
1438  if (*iter >= thresh) {
1439  onSpan = true;
1440  xSpan = x;
1441  } else if (onSpan) {
1442  onSpan = false;
1443  tmpSpans.push_back(afwGeom::Span(y, xSpan, x - 1));
1444  }
1445  }
1446  if (onSpan) {
1447  tmpSpans.push_back(afwGeom::Span(y, xSpan, span.getX1()));
1448  }
1449  }
1450  significant->setSpans(std::make_shared<afwGeom::SpanSet>(std::move(tmpSpans)));
1451  return significant;
1452 }
#define LOG_LOGGER
Definition: Log.h:688
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:142
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 1385 of file BaselineUtils.cc.

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

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

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

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

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: