5 #include "lsst/log/Log.h"
7 #include "lsst/pex/exceptions.h"
8 #include "lsst/afw/geom/Box.h"
12 namespace image = lsst::afw::image;
13 namespace det = lsst::afw::detection;
14 namespace deblend = lsst::meas::deblender;
15 namespace geom = lsst::afw::geom;
17 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
20 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
24 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
27 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
30 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
33 template <
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
36 static bool span_compare(geom::Span
const & sp1,
37 geom::Span
const & sp2) {
42 void nearestFootprint(std::vector<PTR(det::Footprint)>
const& foots,
43 std::shared_ptr<image::Image<std::uint16_t>> argmin,
44 std::shared_ptr<image::Image<std::uint16_t>> dist)
50 typedef std::uint16_t dtype;
51 typedef std::uint16_t itype;
53 const itype nil = 0xffff;
60 for (std::shared_ptr<det::Footprint>
const & foot : foots) {
61 foot->getSpans()->setImage(*argmin, static_cast<itype>(i));
62 foot->getSpans()->setImage(*dist, static_cast<dtype>(1));
67 int const height = dist->getHeight();
68 int const width = dist->getWidth();
71 for (
int y = 0; y != height; ++y) {
72 image::Image<dtype>::xy_locator dim = dist->xy_at(0, y);
73 image::Image<itype>::xy_locator aim = argmin->xy_at(0, y);
74 for (
int x = 0; x != width; ++x, ++dim.x(), ++aim.x()) {
82 dim(0, 0) = width + height;
86 dtype ndist = dim(0,-1) + 1;
87 if (ndist < dim(0,0)) {
94 dtype ndist = dim(-1,0) + 1;
95 if (ndist < dim(0,0)) {
104 for (
int y = height - 1; y >= 0; --y) {
105 image::Image<dtype>::xy_locator dim = dist->xy_at(width-1, y);
106 image::Image<itype>::xy_locator aim = argmin->xy_at(width-1, y);
107 for (
int x = width - 1; x >= 0; --x, --dim.x(), --aim.x()) {
110 if (y + 1 < height) {
111 dtype ndist = dim(0,1) + 1;
112 if (ndist < dim(0,0)) {
119 dtype ndist = dim(1,0) + 1;
120 if (ndist < dim(0,0)) {
143 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
149 int S = halfsize*2 + 1;
151 typedef typename ImageT::xy_locator xy_loc;
152 xy_loc pix = img.xy_at(halfsize,halfsize);
153 std::vector<typename xy_loc::cached_location_t> locs;
154 for (
int i=0; i<S; ++i) {
155 for (
int j=0; j<S; ++j) {
156 locs.push_back(pix.cache_location(j-halfsize, i-halfsize));
159 int W = img.getWidth();
160 int H = img.getHeight();
161 ImagePixelT vals[S*S];
162 for (
int y=halfsize; y<H-halfsize; ++y) {
163 xy_loc inpix = img.xy_at(halfsize, y), end = img.xy_at(W-halfsize, y);
164 for (
typename ImageT::x_iterator optr = out.row_begin(y) + halfsize;
165 inpix != end; ++inpix.x(), ++optr) {
166 for (
int i=0; i<SS; ++i)
167 vals[i] = inpix[locs[i]];
168 std::nth_element(vals, vals+SS/2, vals+SS);
174 for (
int y=0; y<2*halfsize; ++y) {
177 iy = H - 1 - (y-halfsize);
178 typename ImageT::x_iterator optr = out.row_begin(iy);
179 typename ImageT::x_iterator iptr = img.row_begin(iy), end=img.row_end(iy);
180 for (; iptr != end; ++iptr,++optr)
183 for (
int y=halfsize; y<H-halfsize; ++y) {
184 typename ImageT::x_iterator optr = out.row_begin(y);
185 typename ImageT::x_iterator iptr = img.row_begin(y), end=img.row_begin(y)+halfsize;
186 for (; iptr != end; ++iptr,++optr)
188 iptr = img.row_begin(y) + ((W-1) - halfsize);
189 end = img.row_begin(y) + (W-1);
190 optr = out.row_begin(y) + ((W-1) - halfsize);
191 for (; iptr != end; ++iptr,++optr)
221 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
226 det::PeakRecord
const& peak) {
228 int cx = peak.getIx();
229 int cy = peak.getIy();
230 int ix0 = img.getX0();
231 int iy0 = img.getY0();
232 int iW = img.getWidth();
233 int iH = img.getHeight();
237 int DW = std::max(cx - img.getX0(), img.getX0() + img.getWidth() - cx);
238 int DH = std::max(cy - img.getY0(), img.getY0() + img.getHeight() - cy);
244 for (s = 0; s < std::max(DW,DH); s += S) {
246 for (p=0; p<S; p++) {
286 for (
int i=0; i<(8*L); i++, x += dx, y += dy) {
290 if (i % (2*L) == 0) {
293 dx = ( leg % 2) * (-1 + 2*(leg/2));
295 dy = ((leg+1) % 2) * ( 1 - 2*(leg/2));
298 int px = cx + x - ix0;
299 int py = cy + y - iy0;
301 if (px < 0 || px >= iW || py < 0 || py >= iH)
304 ImagePixelT pix = (*shadowingImg)(px,py);
311 const double A = 0.3;
317 ds0 = (double(y) / double(x)) - A;
320 for (shx=1; shx<=S; shx++) {
321 int xsign = (x>0?1:-1);
323 psx = cx + x + (xsign*shx) - ix0;
324 if (psx < 0 || psx >= iW)
327 for (shy = lround(shx * ds0);
328 shy <= lround(shx * ds1); shy++) {
329 psy = cy + y + xsign*shy - iy0;
330 if (psy < 0 || psy >= iH)
332 img(psx, psy) = std::min(img(psx, psy), pix);
338 ds0 = (double(x) / double(y)) - A;
341 for (shy=1; shy<=S; shy++) {
342 int ysign = (y>0?1:-1);
343 psy = cy + y + (ysign*shy) - iy0;
344 if (psy < 0 || psy >= iH)
347 for (shx = lround(shy * ds0);
348 shx <= lround(shy * ds1); shx++) {
349 psx = cx + x + ysign*shx - ix0;
350 if (psx < 0 || psx >= iW)
352 img(psx, psy) = std::min(img(psx, psy), pix);
358 shadowingImg->assign(img);
362 static double _get_contrib_r_to_footprint(
int x,
int y,
363 PTR(det::Footprint) tfoot) {
365 for (geom::Span
const & sp : *(tfoot->getSpans())) {
368 int dx = sp.getX0() - x;
381 int dy = sp.getY() - y;
382 minr2 = std::min(minr2, (
double)(mindx*mindx + dy*dy));
385 return 1. / (1. + minr2);
389 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
395 int strayFluxOptions,
396 std::vector<PTR(det::Footprint)> tfoots,
397 std::vector<bool>
const& ispsf,
398 std::vector<int>
const& pkx,
399 std::vector<int>
const& pky,
400 double clipStrayFluxFraction,
401 std::vector<std::shared_ptr<
typename det::HeavyFootprint<ImagePixelT,MaskPixelT,VariancePixelT> > > & strays
404 typedef typename det::HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT> HeavyFootprint;
409 std::vector<PTR(det::Footprint) > strayfoot;
410 std::vector<std::vector<geom::Span>> straySpans(tfoots.size());
411 std::vector<std::vector<ImagePixelT> > straypix;
412 std::vector<std::vector<MaskPixelT> > straymask;
413 std::vector<std::vector<VariancePixelT> > strayvar;
415 int ix0 = img.getX0();
416 int iy0 = img.getY0();
417 geom::Box2I sumbb = tsum->getBBox();
418 int sumx0 = sumbb.getMinX();
419 int sumy0 = sumbb.getMinY();
421 for (
size_t i=0; i<tfoots.size(); ++i) {
422 strayfoot.push_back(PTR(det::Footprint)());
423 straypix.push_back(std::vector<ImagePixelT>());
424 straymask.push_back(std::vector<MaskPixelT>());
425 strayvar.push_back(std::vector<VariancePixelT>());
428 bool always = (strayFluxOptions & STRAYFLUX_TO_POINT_SOURCES_ALWAYS);
430 typedef std::uint16_t itype;
431 PTR(image::Image<itype>) nearest;
433 if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
436 typedef std::uint16_t dtype;
437 PTR(image::Image<dtype>) dist(
new image::Image<dtype>(sumbb));
438 nearest = PTR(image::Image<itype>)(
new image::Image<itype>(sumbb));
440 std::vector<PTR(det::Footprint)> templist;
441 std::vector<PTR(det::Footprint)>* footlist = &tfoots;
443 if (!always && ispsf.size()) {
446 auto empty = std::make_shared<det::Footprint>();
447 empty->setPeakSchema(foot.getPeaks().getSchema());
448 for (
size_t i=0; i<tfoots.size(); ++i) {
450 templist.push_back(empty);
452 templist.push_back(tfoots[i]);
455 footlist = &templist;
457 nearestFootprint(*footlist, nearest, dist);
462 for (geom::Span
const & s : *foot.getSpans()) {
466 typename ImageT::x_iterator tsum_it =
467 tsum->row_begin(y - sumy0) + (x0 - sumx0);
468 typename MaskedImageT::x_iterator in_it =
469 img.row_begin(y - iy0) + (x0 - ix0);
470 double contrib[tfoots.size()];
472 for (
int x = x0; x <= x1; ++x, ++tsum_it, ++in_it) {
476 if ((*tsum_it > 0) || (*in_it).image() <= 0) {
480 if (strayFluxOptions & STRAYFLUX_R_TO_FOOTPRINT) {
482 for (
size_t i=0; i<tfoots.size(); ++i) {
485 }
else if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
486 for (
size_t i=0; i<tfoots.size(); ++i) {
489 int i = nearest->get0(x, y);
493 for (
size_t i=0; i<tfoots.size(); ++i) {
498 contrib[i] = 1. / (1. + dx*dx + dy*dy);
504 bool ptsrcs = always;
506 for (
size_t i=0; i<tfoots.size(); ++i) {
508 if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
511 if (contrib[i] == -1.0) {
512 contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
518 STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY)) {
522 for (
size_t i=0; i<tfoots.size(); ++i) {
523 if (contrib[i] == -1.0) {
524 contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
531 double strayclip = (clipStrayFluxFraction * csum);
533 for (
size_t i=0; i<tfoots.size(); ++i) {
535 if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
540 if (contrib[i] < strayclip) {
547 for (
size_t i=0; i<tfoots.size(); ++i) {
548 if (contrib[i] == 0.) {
552 double p = (contrib[i] / csum) * (*in_it).image();
555 strayfoot[i] = std::make_shared<det::Footprint>();
556 strayfoot[i]->setPeakSchema(foot.getPeaks().getSchema());
558 straySpans[i].push_back(geom::Span(y, x, x));
559 straypix[i].push_back(p);
560 straymask[i].push_back((*in_it).mask());
561 strayvar[i].push_back((*in_it).variance());
567 for (
size_t i=0; i<tfoots.size(); ++i) {
569 strayfoot[i]->setSpans(std::make_shared<geom::SpanSet>(straySpans[i]));
572 strays.push_back(HeavyFootprintPtrT());
577 HeavyFootprintPtrT heavy(
new HeavyFootprint(*strayfoot[i]));
578 ndarray::Array<ImagePixelT,1,1> himg = heavy->getImageArray();
579 typename std::vector<ImagePixelT>::const_iterator spix;
580 typename std::vector<MaskPixelT>::const_iterator smask;
581 typename std::vector<VariancePixelT>::const_iterator svar;
582 typename ndarray::Array<ImagePixelT,1,1>::Iterator hpix;
583 typename ndarray::Array<MaskPixelT,1,1>::Iterator mpix;
584 typename ndarray::Array<VariancePixelT,1,1>::Iterator vpix;
586 assert((
size_t)strayfoot[i]->getArea() == straypix[i].size());
588 for (spix = straypix[i].begin(),
589 smask = straymask[i].begin(),
590 svar = strayvar [i].begin(),
592 mpix = heavy->getMaskArray().begin(),
593 vpix = heavy->getVarianceArray().begin();
594 spix != straypix[i].end();
595 ++spix, ++smask, ++svar, ++hpix, ++mpix, ++vpix) {
600 strays.push_back(heavy);
605 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
610 geom::Box2I sumbb = tsum->getBBox();
611 int sumx0 = sumbb.getMinX();
612 int sumy0 = sumbb.getMinY();
615 for (
size_t i=0; i<timgs.size(); ++i) {
617 geom::Box2I tbb = timg->getBBox();
618 int tx0 = tbb.getMinX();
619 int ty0 = tbb.getMinY();
624 int copyx0 = tbb.getMinX();
627 for (
int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
628 typename ImageT::x_iterator in_it = timg->row_begin(y - ty0) + (copyx0 - tx0);
629 typename ImageT::x_iterator inend = in_it + tbb.getWidth();
630 typename ImageT::x_iterator tsum_it =
631 tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
632 for (; in_it != inend; ++in_it, ++tsum_it) {
633 *tsum_it += std::max((ImagePixelT)0., static_cast<ImagePixelT>(*in_it));
688 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
689 std::vector<typename PTR(image::MaskedImage<ImagePixelT, MaskPixelT, VariancePixelT>)>
692 det::Footprint
const& foot,
693 std::vector<ImagePtrT> timgs,
694 std::vector<PTR(det::Footprint)> tfoots,
696 std::vector<bool>
const& ispsf,
697 std::vector<int>
const& pkx,
698 std::vector<int>
const& pky,
699 std::vector<std::shared_ptr<typename det::HeavyFootprint<ImagePixelT,MaskPixelT,VariancePixelT> > > & strays,
700 int strayFluxOptions,
701 double clipStrayFluxFraction
704 if (timgs.size() != tfoots.size()) {
705 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
706 (boost::format(
"Template images must be the same length as template footprints (%d vs %d)")
707 % timgs.size() % tfoots.size()).str());
710 for (
size_t i=0; i<timgs.size(); ++i) {
711 if (!timgs[i]->getBBox().contains(tfoots[i]->getBBox())) {
712 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
713 "Template image MUST contain template footprint");
715 if (!img.getBBox().contains(foot.getBBox())) {
716 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
717 "Image bbox MUST contain parent footprint");
725 std::vector<MaskedImagePtrT> portions;
727 LOG_LOGGER _log = LOG_GET(
"meas.deblender.apportionFlux");
728 bool findStrayFlux = (strayFluxOptions & ASSIGN_STRAYFLUX);
730 int ix0 = img.getX0();
731 int iy0 = img.getY0();
732 geom::Box2I fbb = foot.getBBox();
736 tsum->setXY0(fbb.getMinX(), fbb.getMinY());
739 if (!tsum->getBBox().contains(foot.getBBox())) {
740 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
741 "Template sum image MUST contain parent footprint");
744 geom::Box2I sumbb = tsum->getBBox();
745 int sumx0 = sumbb.getMinX();
746 int sumy0 = sumbb.getMinY();
748 _sum_templates(timgs, tsum);
751 for (
size_t i=0; i<timgs.size(); ++i) {
755 port->setXY0(timg->getXY0());
756 portions.push_back(port);
759 geom::Box2I tbb = timg->getBBox();
760 int tx0 = tbb.getMinX();
761 int ty0 = tbb.getMinY();
764 int copyx0 = tbb.getMinX();
765 for (
int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
766 typename MaskedImageT::x_iterator in_it =
767 img.row_begin(y - iy0) + (copyx0 - ix0);
768 typename ImageT::x_iterator tptr =
769 timg->row_begin(y - ty0) + (copyx0 - tx0);
770 typename ImageT::x_iterator tend = tptr + tbb.getWidth();
771 typename ImageT::x_iterator tsum_it =
772 tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
773 typename MaskedImageT::x_iterator out_it =
774 port->row_begin(y - ty0) + (copyx0 - tx0);
775 for (; tptr != tend; ++tptr, ++in_it, ++out_it, ++tsum_it) {
779 double frac = std::max((ImagePixelT)0., static_cast<ImagePixelT>(*tptr)) / (*tsum_it);
783 out_it.mask() = (*in_it).mask();
784 out_it.variance() = (*in_it).variance();
785 out_it.image() = (*in_it).image() * frac;
791 if ((ispsf.size() > 0) && (ispsf.size() != timgs.size())) {
792 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
793 (boost::format(
"'ispsf' must be the same length as templates (%d vs %d)")
794 % ispsf.size() % timgs.size()).str());
796 if ((pkx.size() != timgs.size()) || (pky.size() != timgs.size())) {
797 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
798 (boost::format(
"'pkx' and 'pky' must be the same length as templates (%d,%d vs %d)")
799 % pkx.size() % pky.size() % timgs.size()).str());
801 _find_stray_flux(foot, tsum, img, strayFluxOptions, tfoots,
802 ispsf, pkx, pky, clipStrayFluxFraction, strays);
824 int cx,
int cy,
bool forward=
true)
825 : _real(real), _cx(cx), _cy(cy), _forward(forward)
835 return _real == other;
838 return _real != other;
841 return _real <= other;
844 return _real < other;
847 return _real >= other;
850 return _real > other;
854 return (_real == other._real) &&
855 (_cx == other._cx) && (_cy == other._cy) &&
856 (_forward == other._forward);
859 return !(*
this == other);
880 return _real >= _end;
886 return _real->getX0() - _cx;
888 return _cx - _real->getX1();
893 return _real->getX1() - _cx;
895 return _cx - _real->getX0();
899 return std::abs(_real->getY() - _cy);
902 return _real->getX0();
905 return _real->getX1();
908 return _real->getY();
912 SpanSet::const_iterator _real;
913 SpanSet::const_iterator _end;
970 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
971 PTR(lsst::afw::detection::Footprint)
972 deblend::BaselineUtils<ImagePixelT,MaskPixelT,VariancePixelT>::
974 det::Footprint const& foot,
977 auto sfoot = std::make_shared<det::Footprint>();
978 sfoot->setPeakSchema(foot.getPeaks().getSchema());
979 geom::SpanSet
const & spans = *foot.getSpans();
981 LOG_LOGGER _log = LOG_GET(
"meas.deblender.symmetrizeFootprint");
984 geom::Span target(cy, cx, cx);
985 geom::SpanSet::const_iterator peakspan =
986 std::upper_bound(spans.begin(), spans.end(), target, span_compare);
992 if (peakspan == spans.begin()) {
994 if (!sp.contains(cx, cy)) {
996 "Failed to find span containing (%i,%i): before the beginning of this footprint", cx, cy);
997 return PTR(det::Footprint)();
1003 if (!sp.contains(cx, cy)) {
1006 if (!sp.contains(cx, cy)) {
1007 geom::Box2I fbb = foot.getBBox();
1008 LOGL_WARN(_log,
"Failed to find span containing (%i,%i): nearest is %i, [%i,%i]. "
1009 "Footprint bbox is [%i,%i],[%i,%i]",
1010 cx, cy, sp.getY(), sp.getX0(), sp.getX1(),
1011 fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY());
1012 return PTR(det::Footprint)();
1016 LOGL_DEBUG(_log,
"Span containing (%i,%i): (x=[%i,%i], y=%i)",
1017 cx, cy, sp.getX0(), sp.getX1(), sp.getY());
1051 std::vector<geom::Span> tmpSpans;
1052 while (fwd.notDone() && back.
notDone()) {
1057 int fdxlo = fwd.dxlo();
1058 int bdxlo = back.
dxlo();
1065 for (fend = fwd; fend.
notDone(); ++fend) {
1066 if (fend.
dy() != dy)
1069 for (bend = back; bend.
notDone(); ++bend) {
1070 if (bend.
dy() != dy)
1074 LOGL_DEBUG(_log,
"dy=%i, fy=%i, fx=[%i, %i], by=%i, fx=[%i, %i], fdx=%i, bdx=%i",
1075 dy, fy, fwd.x0(), fwd.x1(), by, back.
x0(), back.
x1(),
1079 if (bdxlo > fdxlo) {
1080 LOGL_DEBUG(_log,
"Advancing forward.");
1084 while ((fwd != fend) && (fwd.dxhi() < bdxlo)) {
1087 LOGL_DEBUG(_log,
"Reached fend");
1089 LOGL_DEBUG(_log,
"Advanced to forward span %i, [%i, %i]",
1090 fy, fwd.x0(), fwd.x1());
1093 }
else if (fdxlo > bdxlo) {
1094 LOGL_DEBUG(_log,
"Advancing backward.");
1098 while ((back != bend) && (back.
dxhi() < fdxlo)) {
1101 LOGL_DEBUG(_log,
"Reached bend");
1103 LOGL_DEBUG(_log,
"Advanced to backward span %i, [%i, %i]",
1104 by, back.
x0(), back.
x1());
1109 if ((back == bend) || (fwd == fend)) {
1113 LOGL_DEBUG(_log,
"Reached bend");
1116 LOGL_DEBUG(_log,
"Reached fend");
1125 int dxlo = std::max(fwd.dxlo(), back.
dxlo());
1126 int dxhi = std::min(fwd.dxhi(), back.
dxhi());
1128 LOGL_DEBUG(_log,
"Adding span fwd %i, [%i, %i], back %i, [%i, %i]",
1129 fy, cx+dxlo, cx+dxhi, by, cx-dxhi, cx-dxlo);
1130 tmpSpans.push_back(geom::Span(fy, cx + dxlo, cx + dxhi));
1131 tmpSpans.push_back(geom::Span(by, cx - dxhi, cx - dxlo));
1135 if (fwd.dxhi() < back.
dxhi()) {
1138 LOGL_DEBUG(_log,
"Stepped to fend");
1140 LOGL_DEBUG(_log,
"Stepped forward to span %i, [%i, %i]",
1141 fwd.y(), fwd.x0(), fwd.x1());
1146 LOGL_DEBUG(_log,
"Stepped to bend");
1148 LOGL_DEBUG(_log,
"Stepped backward to span %i, [%i, %i]",
1149 back.
y(), back.
x0(), back.
x1());
1153 if ((back == bend) || (fwd == fend)) {
1156 LOGL_DEBUG(_log,
"Reached bend");
1159 LOGL_DEBUG(_log,
"Reached fend");
1168 sfoot->setSpans(std::make_shared<geom::SpanSet>(std::move(tmpSpans)));
1184 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
1185 std::pair<typename PTR(lsst::afw::image::Image<ImagePixelT>),
1186 typename PTR(lsst::afw::detection::Footprint) >
1190 det::Footprint
const& foot,
1191 det::PeakRecord
const& peak,
1195 bool* patchedEdges) {
1197 typedef typename MaskedImageT::const_xy_locator xy_loc;
1199 *patchedEdges =
false;
1201 int cx = peak.getIx();
1202 int cy = peak.getIy();
1204 LOG_LOGGER _log = LOG_GET(
"meas.deblender.symmetricFootprint");
1206 if (!img.getBBox(image::PARENT).contains(foot.getBBox())) {
1207 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
"Image too small for footprint");
1213 return std::pair<ImagePtrT, FootprintPtrT>(
ImagePtrT(), sfoot);
1216 if (!img.getBBox(image::PARENT).contains(sfoot->getBBox())) {
1217 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
1218 "Image too small for symmetrized footprint");
1220 geom::SpanSet
const & spans = *sfoot->getSpans();
1223 bool touchesEdge =
false;
1225 LOGL_DEBUG(_log,
"Checking footprint for EDGE bits");
1228 MaskPixelT edgebit = mask->getPlaneBitMask(
"EDGE");
1229 for (geom::SpanSet::const_iterator fwd=spans.begin();
1230 fwd != spans.end(); ++fwd) {
1231 int x0 = fwd->getX0();
1232 int x1 = fwd->getX1();
1233 typename MaskT::x_iterator xiter =
1234 mask->x_at(x0 - mask->getX0(), fwd->getY() - mask->getY0());
1235 for (
int x=x0; x<=x1; ++x, ++xiter) {
1236 if ((*xiter) & edgebit) {
1245 LOGL_DEBUG(_log,
"Footprint includes an EDGE pixel.");
1253 geom::SpanSet::const_iterator fwd = spans.begin();
1254 geom::SpanSet::const_iterator back = spans.end()-1;
1258 for (; fwd <= back; fwd++, back--) {
1259 int fy = fwd->getY();
1260 int by = back->getY();
1262 for (
int fx=fwd->getX0(), bx=back->getX1();
1271 assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(fx, fy)));
1272 assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(bx, by)));
1277 ImagePixelT pixf = theimg->get0(fx, fy);
1278 ImagePixelT pixb = theimg->get0(bx, by);
1279 ImagePixelT pix = std::min(pixf, pixb);
1281 pix = std::max(pix, static_cast<ImagePixelT>(0));
1283 targetimg->set0(fx, fy, pix);
1284 targetimg->set0(bx, by, pix);
1293 geom::Box2I bb = sfoot->getBBox();
1298 geom::Box2I imbb = foot.getBBox();
1300 LOGL_DEBUG(_log,
"Footprint touches EDGE: start bbox [%i,%i],[%i,%i]",
1301 bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1303 const geom::SpanSet & ospans = *foot.getSpans();
1304 for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1305 int y = fwd->getY();
1306 int x = fwd->getX0();
1308 int ym = cy + (cy - y);
1309 int xm = cx + (cx - x);
1310 if (!imbb.contains(geom::Point2I(xm, ym))) {
1311 bb.include(geom::Point2I(x, y));
1315 if (!imbb.contains(geom::Point2I(xm, ym))) {
1316 bb.include(geom::Point2I(x, y));
1319 LOGL_DEBUG(_log,
"Footprint touches EDGE: grown bbox [%i,%i],[%i,%i]",
1320 bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1324 sfoot->getSpans()->copyImage(*targetimg, *targetimg2);
1326 LOGL_DEBUG(_log,
"Symmetric footprint spans:");
1327 const geom::SpanSet & sspans = *sfoot->getSpans();
1328 for (fwd = sspans.begin(); fwd != sspans.end(); ++fwd) {
1329 LOGL_DEBUG(_log,
" %s", fwd->toString().c_str());
1334 std::vector<geom::Span> newSpans(sfoot->getSpans()->begin(), sfoot->getSpans()->end());
1335 for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1336 int y = fwd->getY();
1337 int x0 = fwd->getX0();
1338 int x1 = fwd->getX1();
1340 int ym = cy + (cy - y);
1341 int xm0 = cx + (cx - x0);
1342 int xm1 = cx + (cx - x1);
1343 bool in0 = imbb.contains(geom::Point2I(xm0, ym));
1344 bool in1 = imbb.contains(geom::Point2I(xm1, ym));
1353 x0 = cx + (cx - (imbb.getMinX() - 1));
1356 x1 = cx + (cx - (imbb.getMaxX() + 1));
1358 LOGL_DEBUG(_log,
"Span y=%i, x=[%i,%i] has mirror (%i,[%i,%i]) out-of-bounds; clipped to %i,[%i,%i]",
1359 y, fwd->getX0(), fwd->getX1(), ym, xm1, xm0, y, x0, x1);
1360 typename MaskedImageT::x_iterator initer =
1361 img.x_at(x0 - img.getX0(), y - img.getY0());
1362 typename ImageT::x_iterator outiter =
1363 targetimg2->x_at(x0 - targetimg2->getX0(), y - targetimg2->getY0());
1364 for (
int x=x0; x<=x1; ++x, ++outiter, ++initer) {
1365 *outiter = initer.image();
1367 newSpans.push_back(geom::Span(y, x0, x1));
1369 sfoot->setSpans(std::make_shared<geom::SpanSet>(std::move(newSpans)));
1370 targetimg = targetimg2;
1373 *patchedEdges = touchesEdge;
1374 return std::pair<ImagePtrT, FootprintPtrT>(targetimg, sfoot);
1381 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
1385 PTR(det::Footprint) sfoot,
1386 ImagePixelT thresh) {
1388 LOG_LOGGER _log = LOG_GET(
"meas.deblender.hasSignificantFluxAtEdge");
1393 std::shared_ptr<geom::SpanSet> spans = sfoot->getSpans()->findEdgePixels();
1395 for (geom::SpanSet::const_iterator sp = spans->begin(); sp != spans->end(); ++sp) {
1396 int const y = sp->getY();
1397 int const x0 = sp->getX0();
1398 int const x1 = sp->getX1();
1400 typename ImageT::const_x_iterator xiter;
1401 for (xiter = img->x_at(x0 - img->getX0(), y - img->getY0()), x=x0; x<=x1; ++x, ++xiter) {
1402 if (*xiter >= thresh) {
1414 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
1415 std::shared_ptr<det::Footprint>
1418 PTR(det::Footprint) sfoot,
1419 ImagePixelT thresh) {
1420 LOG_LOGGER _log = LOG_GET(
"meas.deblender.getSignificantEdgePixels");
1423 auto significant = std::make_shared<det::Footprint>();
1424 significant->setPeakSchema(sfoot->getPeaks().getSchema());
1426 int const x0 = img->getX0(), y0 = img->getY0();
1427 std::shared_ptr<geom::SpanSet> edgeSpans = sfoot->getSpans()->findEdgePixels();
1428 std::vector<geom::Span> tmpSpans;
1429 for (geom::SpanSet::const_iterator ss = edgeSpans->begin(); ss != edgeSpans->end(); ++ss) {
1430 geom::Span
const& span = *ss;
1431 int const y = span.getY();
1432 int x = span.getX0();
1433 typename ImageT::const_x_iterator iter = img->x_at(x - x0, y - y0);
1434 bool onSpan =
false;
1436 for (; x <= span.getX1(); ++x, ++iter) {
1437 if (*iter >= thresh) {
1440 }
else if (onSpan) {
1442 tmpSpans.push_back(geom::Span(y, xSpan, x - 1));
1446 tmpSpans.push_back(geom::Span(y, xSpan, span.getX1()));
1449 significant->setSpans(std::make_shared<geom::SpanSet>(std::move(tmpSpans)));
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...
static std::shared_ptr< lsst::afw::detection::Footprint > getSignificantEdgePixels(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...
bool operator<(const SpanSet::const_iterator &other)
lsst::afw::image::Image< ImagePixelT > ImageT
bool operator==(RelativeSpanIterator &other)
bool operator!=(const SpanSet::const_iterator &other)
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)
boost::shared_ptr< lsst::afw::detection::Footprint > FootprintPtrT
bool operator==(const SpanSet::const_iterator &other)
RelativeSpanIterator(SpanSet::const_iterator const &real, SpanSet const &arr, int cx, int cy, bool forward=true)
lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > MaskedImageT
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. ...
bool operator>=(const SpanSet::const_iterator &other)
boost::shared_ptr< lsst::afw::image::Mask< MaskPixelT > > MaskPtrT
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 ...
This is a convenience class used in symmetrizeFootprint, wrapping the idea of iterating through a Spa...
static void _sum_templates(std::vector< ImagePtrT > timgs, ImagePtrT tsum)
bool operator!=(RelativeSpanIterator &other)
static std::pair< ImagePtrT, FootprintPtrT > buildSymmetricTemplate(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 Maske...
RelativeSpanIterator operator++()
RelativeSpanIterator operator++(int dummy)
boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT > MaskedImagePtrT
bool operator>(const SpanSet::const_iterator &other)
bool operator<=(const SpanSet::const_iterator &other)
boost::shared_ptr< lsst::afw::detection::HeavyFootprint< ImagePixelT > MaskPixelT, VariancePixelT > HeavyFootprintPtrT
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT