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,
53 const itype nil = 0xffff;
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) {
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) {
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;
152 xy_loc pix = img.
xy_at(halfsize,halfsize);
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));
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);
165 inpix !=
end; ++inpix.x(), ++optr) {
166 for (
int i=0; i<SS; ++i)
167 vals[i] = inpix[locs[i]];
174 for (
int y=0; y<2*halfsize; ++y) {
177 iy = H - 1 - (y-halfsize);
180 for (; iptr !=
end; ++iptr,++optr)
183 for (
int y=halfsize; y<H-halfsize; ++y) {
186 for (; iptr !=
end; ++iptr,++optr)
188 iptr = img.
row_begin(y) + ((W-1) - halfsize);
190 optr = out.
row_begin(y) + ((W-1) - halfsize);
191 for (; iptr !=
end; ++iptr,++optr)
221 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
228 int cx = peak.
getIx();
229 int cy = peak.
getIy();
230 int ix0 = img.
getX0();
231 int iy0 = img.
getY0();
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,
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,
400 double clipStrayFluxFraction,
415 int ix0 = img.
getX0();
416 int iy0 = img.
getY0();
421 for (
size_t i=0; i<tfoots.size(); ++i) {
428 bool always = (strayFluxOptions & STRAYFLUX_TO_POINT_SOURCES_ALWAYS);
433 if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
443 if (!always && ispsf.
size()) {
446 auto empty = std::make_shared<det::Footprint>();
448 for (
size_t i=0; i<tfoots.size(); ++i) {
455 footlist = &templist;
457 nearestFootprint(*footlist, nearest, dist);
467 tsum->row_begin(y - sumy0) + (x0 - sumx0);
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>();
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]));
577 HeavyFootprintPtrT heavy(
new HeavyFootprint(*strayfoot[i]));
578 ndarray::Array<ImagePixelT,1,1> himg = heavy->getImageArray();
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) {
605 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
615 for (
size_t i=0; i<timgs.
size(); ++i) {
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>
700 int strayFluxOptions,
701 double clipStrayFluxFraction
704 if (timgs.
size() != tfoots.size()) {
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())) {
713 "Template image MUST contain template footprint");
717 "Image bbox MUST contain parent footprint");
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();
739 if (!tsum->getBBox().contains(foot.
getBBox())) {
741 "Template sum image MUST contain parent footprint");
748 _sum_templates(timgs, tsum);
751 for (
size_t i=0; i<timgs.
size(); ++i) {
755 port->setXY0(timg->getXY0());
769 timg->row_begin(y - ty0) + (copyx0 - tx0);
772 tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
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())) {
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())) {
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();
970 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
977 auto sfoot = std::make_shared<det::Footprint>();
981 LOG_LOGGER _log =
LOG_GET(
"meas.deblender.symmetrizeFootprint");
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);
1003 if (!sp.contains(cx, cy)) {
1006 if (!sp.contains(cx, cy)) {
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(),
1016 LOGL_DEBUG(_log,
"Span containing (%i,%i): (x=[%i,%i], y=%i)",
1017 cx, cy, sp.getX0(), sp.getX1(), sp.getY());
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) {
1084 while ((fwd != fend) && (fwd.dxhi() < bdxlo)) {
1089 LOGL_DEBUG(_log,
"Advanced to forward span %i, [%i, %i]",
1090 fy, fwd.x0(), fwd.x1());
1093 }
else if (fdxlo > bdxlo) {
1098 while ((back != bend) && (back.
dxhi() < fdxlo)) {
1103 LOGL_DEBUG(_log,
"Advanced to backward span %i, [%i, %i]",
1104 by, back.
x0(), back.
x1());
1109 if ((back == bend) || (fwd == fend)) {
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);
1135 if (fwd.dxhi() < back.
dxhi()) {
1140 LOGL_DEBUG(_log,
"Stepped forward to span %i, [%i, %i]",
1141 fwd.y(), fwd.x0(), fwd.x1());
1148 LOGL_DEBUG(_log,
"Stepped backward to span %i, [%i, %i]",
1149 back.
y(), back.
x0(), back.
x1());
1153 if ((back == bend) || (fwd == fend)) {
1168 sfoot->setSpans(std::make_shared<geom::SpanSet>(
std::move(tmpSpans)));
1184 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
1195 bool* patchedEdges) {
1199 *patchedEdges =
false;
1201 int cx = peak.
getIx();
1202 int cy = peak.
getIy();
1204 LOG_LOGGER _log =
LOG_GET(
"meas.deblender.symmetricFootprint");
1218 "Image too small for symmetrized footprint");
1223 bool touchesEdge =
false;
1225 LOGL_DEBUG(_log,
"Checking footprint for EDGE bits");
1228 MaskPixelT edgebit = mask->getPlaneBitMask(
"EDGE");
1230 fwd != spans.
end(); ++fwd) {
1231 int x0 = fwd->getX0();
1232 int x1 = fwd->getX1();
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.");
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);
1300 LOGL_DEBUG(_log,
"Footprint touches EDGE: start bbox [%i,%i],[%i,%i]",
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);
1319 LOGL_DEBUG(_log,
"Footprint touches EDGE: grown bbox [%i,%i],[%i,%i]",
1324 sfoot->getSpans()->copyImage(*targetimg, *targetimg2);
1326 LOGL_DEBUG(_log,
"Symmetric footprint spans:");
1328 for (fwd = sspans.
begin(); fwd != sspans.
end(); ++fwd) {
1329 LOGL_DEBUG(_log,
" %s", fwd->toString().c_str());
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);
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);
1363 targetimg2->x_at(x0 - targetimg2->getX0(), y - targetimg2->getY0());
1364 for (
int x=x0; x<=x1; ++x, ++outiter, ++initer) {
1365 *outiter = initer.
image();
1369 sfoot->setSpans(std::make_shared<geom::SpanSet>(
std::move(newSpans)));
1370 targetimg = targetimg2;
1373 *patchedEdges = touchesEdge;
1381 template<
typename ImagePixelT,
typename MaskPixelT,
typename VariancePixelT>
1386 ImagePixelT thresh) {
1388 LOG_LOGGER _log =
LOG_GET(
"meas.deblender.hasSignificantFluxAtEdge");
1396 int const y = sp->getY();
1397 int const x0 = sp->getX0();
1398 int const x1 = sp->getX1();
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>
1419 ImagePixelT thresh) {
1420 LOG_LOGGER _log =
LOG_GET(
"meas.deblender.getSignificantEdgePixels");
1423 auto significant = std::make_shared<det::Footprint>();
1426 int const x0 = img->getX0(), y0 = img->getY0();
1431 int const y = span.
getY();
1432 int x = span.
getX0();
1434 bool onSpan =
false;
1436 for (; x <= span.
getX1(); ++x, ++iter) {
1437 if (*iter >= thresh) {
1440 }
else if (onSpan) {
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)
const_iterator end() const
void include(Point2I const &point)
_const_view_t::x_iterator const_x_iterator
bool operator==(RelativeSpanIterator &other)
bool operator!=(const SpanSet::const_iterator &other)
_view_t::x_iterator x_iterator
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)
const_iterator begin() const
RelativeSpanIterator(SpanSet::const_iterator const &real, SpanSet const &arr, int cx, int cy, bool forward=true)
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...
geom::Box2I getBBox(ImageOrigin const origin=PARENT) const
x_iterator row_begin(int y) const
#define LOGL_DEBUG(logger, message...)
x_iterator x_at(int x, int y) const
ImagePtr getImage() const
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
x_iterator row_begin(int y) const
#define LOGL_WARN(logger, message...)
Reference< ImagePixelT >::type image()
bool contains(Point2I const &point) const
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 ...
#define LSST_EXCEPT(type,...)
def apportionFlux(debResult, log, assignStrayFlux=True, strayFluxAssignment='r-to-peak', strayFluxToPointSources='necessary', clipStrayFluxFraction=0.001, getTemplateSum=False)
std::vector< Span >::const_iterator const_iterator
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)
Extent2I const getDimensions() const
x_iterator row_end(int y) const
bool operator!=(RelativeSpanIterator &other)
void clip(Box2I const &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)
_view_t::xy_locator xy_locator
boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT > MaskedImagePtrT
xy_locator xy_at(int x, int y) const
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