LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
Baseline.cc
Go to the documentation of this file.
1 #include <list>
2 #include <cmath>
3 #include <cstdint>
4 
6 #include "lsst/pex/logging.h"
7 #include "lsst/pex/exceptions.h"
8 #include "lsst/afw/geom/Box.h"
9 
10 using std::lround;
11 
12 namespace image = lsst::afw::image;
13 namespace det = lsst::afw::detection;
14 namespace deblend = lsst::meas::deblender;
15 namespace geom = lsst::afw::geom;
16 namespace pexLog = lsst::pex::logging;
17 
18 
19 static bool span_ptr_compare(PTR(det::Span) sp1, PTR(det::Span) sp2) {
20  return (*sp1 < *sp2);
21 }
22 
36 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
37 void
39 medianFilter(ImageT const& img,
40  ImageT & out,
41  int halfsize) {
42  int S = halfsize*2 + 1;
43  int SS = S*S;
44  typedef typename ImageT::xy_locator xy_loc;
45  xy_loc pix = img.xy_at(halfsize,halfsize);
46  std::vector<typename xy_loc::cached_location_t> locs;
47  for (int i=0; i<S; ++i) {
48  for (int j=0; j<S; ++j) {
49  locs.push_back(pix.cache_location(j-halfsize, i-halfsize));
50  }
51  }
52  int W = img.getWidth();
53  int H = img.getHeight();
54  ImagePixelT vals[S*S];
55  for (int y=halfsize; y<H-halfsize; ++y) {
56  xy_loc inpix = img.xy_at(halfsize, y), end = img.xy_at(W-halfsize, y);
57  for (typename ImageT::x_iterator optr = out.row_begin(y) + halfsize;
58  inpix != end; ++inpix.x(), ++optr) {
59  for (int i=0; i<SS; ++i)
60  vals[i] = inpix[locs[i]];
61  std::nth_element(vals, vals+SS/2, vals+SS);
62  *optr = vals[SS/2];
63  }
64  }
65 
66  // grumble grumble margins
67  for (int y=0; y<2*halfsize; ++y) {
68  int iy = y;
69  if (y >= halfsize)
70  iy = H - 1 - (y-halfsize);
71  typename ImageT::x_iterator optr = out.row_begin(iy);
72  typename ImageT::x_iterator iptr = img.row_begin(iy), end=img.row_end(iy);
73  for (; iptr != end; ++iptr,++optr)
74  *optr = *iptr;
75  }
76  for (int y=halfsize; y<H-halfsize; ++y) {
77  typename ImageT::x_iterator optr = out.row_begin(y);
78  typename ImageT::x_iterator iptr = img.row_begin(y), end=img.row_begin(y)+halfsize;
79  for (; iptr != end; ++iptr,++optr)
80  *optr = *iptr;
81  iptr = img.row_begin(y) + ((W-1) - halfsize);
82  end = img.row_begin(y) + (W-1);
83  optr = out.row_begin(y) + ((W-1) - halfsize);
84  for (; iptr != end; ++iptr,++optr)
85  *optr = *iptr;
86  }
87 
88 }
89 
114 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
115 void
118  ImageT & img,
119  det::PeakRecord const& peak) {
120 
121  int cx = peak.getIx();
122  int cy = peak.getIy();
123  int ix0 = img.getX0();
124  int iy0 = img.getY0();
125  int iW = img.getWidth();
126  int iH = img.getHeight();
127 
128  ImagePtrT shadowingImg = ImagePtrT(new ImageT(img, true));
129 
130  int DW = std::max(cx - img.getX0(), img.getX0() + img.getWidth() - cx);
131  int DH = std::max(cy - img.getY0(), img.getY0() + img.getHeight() - cy);
132 
133  const int S = 5;
134 
135  // Work out from the peak in chunks of "S" pixels.
136  int s;
137  for (s = 0; s < std::max(DW,DH); s += S) {
138  int p;
139  for (p=0; p<S; p++) {
140  // visit pixels with L_inf distance = s + p from the
141  // center (ie, the s+p'th square ring of pixels)
142  // L is the half-length of the ring (box).
143  int L = s+p;
144  int x = L, y = -L;
145  int dx = 0, dy = 0; // initialized here to satisfy the
146  // compiler; initialized for real
147  // below (first time through loop)
148  /*
149  int i;
150  int leg;
151  for (i=0; i<(8*L); i++, x += dx, y += dy) {
152  if (i % (2*L) == 0) {
153  leg = (i/(2*L));
154  dx = ( leg % 2) * (-1 + 2*(leg/2));
155  dy = ((leg+1) % 2) * ( 1 - 2*(leg/2));
156  }
157  */
158 
159  /*
160  We visit pixels in a box of "radius" L, in this order:
161 
162  L=1:
163 
164  4 3 2
165  5 1
166  6 7 0
167 
168  L=2:
169 
170  8 7 6 5 4
171  9 3
172  10 2
173  11 1
174  12 13 14 15 0
175 
176  Note that the number of pixel visited is 8*L, and that we
177  change "dx" or "dy" each "2*L" steps.
178  */
179  for (int i=0; i<(8*L); i++, x += dx, y += dy) {
180  // time to change directions? (Note that this runs
181  // the first time through the loop, initializing dx,dy
182  // appropriately.)
183  if (i % (2*L) == 0) {
184  int leg = (i/(2*L));
185  // dx = [ 0, -1, 0, 1 ][leg]
186  dx = ( leg % 2) * (-1 + 2*(leg/2));
187  // dy = [ 1, 0, -1, 0 ][leg]
188  dy = ((leg+1) % 2) * ( 1 - 2*(leg/2));
189  }
190  //printf(" i=%i, leg=%i, dx=%i, dy=%i, x=%i, y=%i\n", i, leg, dx, dy, x, y);
191  int px = cx + x - ix0;
192  int py = cy + y - iy0;
193  // If the shadowing pixel is out of bounds, nothing to do.
194  if (px < 0 || px >= iW || py < 0 || py >= iH)
195  continue;
196  // The pixel casting the shadow
197  ImagePixelT pix = (*shadowingImg)(px,py);
198 
199  // Cast this pixel's shadow S pixels long in a cone.
200  // We compute the range of slopes (or inverse-slopes)
201  // shadowed by the pixel, [ds0,ds1]
202  double ds0, ds1;
203  // Range of slopes shadowed
204  const double A = 0.3;
205  int shx, shy;
206  int psx, psy;
207  // Are we traversing a vertical edge of the box?
208  if (dx == 0) {
209  // (if so, then "x" is +- L, so no div-by-zero)
210  ds0 = (double(y) / double(x)) - A;
211  ds1 = ds0 + 2.0 * A;
212  // cast the shadow on column x + sign(x)*shx
213  for (shx=1; shx<=S; shx++) {
214  int xsign = (x>0?1:-1);
215  // the column being shadowed
216  psx = cx + x + (xsign*shx) - ix0;
217  if (psx < 0 || psx >= iW)
218  continue;
219  // shadow covers a range of y values based on slope
220  for (shy = lround(shx * ds0);
221  shy <= lround(shx * ds1); shy++) {
222  psy = cy + y + xsign*shy - iy0;
223  if (psy < 0 || psy >= iH)
224  continue;
225  img(psx, psy) = std::min(img(psx, psy), pix);
226  }
227  }
228 
229  } else {
230  // We're traversing a horizontal edge of the box; y = +-L
231  ds0 = (double(x) / double(y)) - A;
232  ds1 = ds0 + 2.0 * A;
233  // Cast shadow on row y + sign(y)*shy
234  for (shy=1; shy<=S; shy++) {
235  int ysign = (y>0?1:-1);
236  psy = cy + y + (ysign*shy) - iy0;
237  if (psy < 0 || psy >= iH)
238  continue;
239  // shadow covers a range of x vals based on slope
240  for (shx = lround(shy * ds0);
241  shx <= lround(shy * ds1); shx++) {
242  psx = cx + x + ysign*shx - ix0;
243  if (psx < 0 || psx >= iW)
244  continue;
245  img(psx, psy) = std::min(img(psx, psy), pix);
246  }
247  }
248  }
249  }
250  }
251  shadowingImg->assign(img);
252  }
253 }
254 
255 static double _get_contrib_r_to_footprint(int x, int y,
256  PTR(det::Footprint) tfoot) {
257  typedef det::Footprint::SpanList SpanList;
258  double minr2 = 1e12;
259  SpanList const& tspans = tfoot->getSpans();
260  for (SpanList::const_iterator ts = tspans.begin(); ts < tspans.end(); ++ts) {
261  geom::Span* sp = ts->get();
262  int mindx;
263  // span is to right of pixel?
264  int dx = sp->getX0() - x;
265  if (dx >= 0) {
266  mindx = dx;
267  } else {
268  // span is to left of pixel?
269  dx = x - sp->getX1();
270  if (dx >= 0) {
271  mindx = dx;
272  } else {
273  // span contains pixel (in x direction)
274  mindx = 0;
275  }
276  }
277  int dy = sp->getY() - y;
278  minr2 = std::min(minr2, (double)(mindx*mindx + dy*dy));
279  }
280  //printf("stray flux at (%i,%i): dist to t %i is %g\n", x, y, (int)i, sqrt(minr2));
281  return 1. / (1. + minr2);
282 }
283 
284 
285 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
286 void
289  ImagePtrT tsum,
290  MaskedImageT const& img,
291  int strayFluxOptions,
292  std::vector<PTR(det::Footprint)> tfoots,
293  std::vector<bool> const& ispsf,
294  std::vector<int> const& pkx,
295  std::vector<int> const& pky,
296  double clipStrayFluxFraction,
297  std::vector<std::shared_ptr<typename det::HeavyFootprint<ImagePixelT,MaskPixelT,VariancePixelT> > > & strays
298  ) {
299 
300  typedef typename det::Footprint::SpanList SpanList;
301  typedef typename det::HeavyFootprint<ImagePixelT, MaskPixelT, VariancePixelT> HeavyFootprint;
302  typedef typename std::shared_ptr< HeavyFootprint > HeavyFootprintPtrT;
303 
304  // when doing stray flux: the footprints and pixels, which we'll
305  // combine into the return 'strays' HeavyFootprint at the end.
306  std::vector<PTR(det::Footprint) > strayfoot;
307  std::vector<std::vector<ImagePixelT> > straypix;
308  std::vector<std::vector<MaskPixelT> > straymask;
309  std::vector<std::vector<VariancePixelT> > strayvar;
310 
311  int ix0 = img.getX0();
312  int iy0 = img.getY0();
313  geom::Box2I sumbb = tsum->getBBox();
314  int sumx0 = sumbb.getMinX();
315  int sumy0 = sumbb.getMinY();
316 
317  for (size_t i=0; i<tfoots.size(); ++i) {
318  strayfoot.push_back(PTR(det::Footprint)());
319  straypix.push_back(std::vector<ImagePixelT>());
320  straymask.push_back(std::vector<MaskPixelT>());
321  strayvar.push_back(std::vector<VariancePixelT>());
322  }
323 
324  bool always = (strayFluxOptions & STRAYFLUX_TO_POINT_SOURCES_ALWAYS);
325 
326  typedef std::uint16_t itype;
327  PTR(image::Image<itype>) nearest;
328 
329  if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
330  // Compute the map of which footprint is closest to each
331  // pixel in the bbox.
332  typedef std::uint16_t dtype;
333  PTR(image::Image<dtype>) dist(new image::Image<dtype>(sumbb));
334  nearest = PTR(image::Image<itype>)(new image::Image<itype>(sumbb));
335 
336  std::vector<PTR(det::Footprint)> templist;
337  std::vector<PTR(det::Footprint)>* footlist = &tfoots;
338 
339  if (!always && ispsf.size()) {
340  // create a temp list that has empty footprints in place
341  // of all the point sources.
342  PTR(det::Footprint) empty(new det::Footprint(foot.getPeaks().getSchema()));
343  for (size_t i=0; i<tfoots.size(); ++i) {
344  if (ispsf[i]) {
345  templist.push_back(empty);
346  } else {
347  templist.push_back(tfoots[i]);
348  }
349  }
350  footlist = &templist;
351  }
352  nearestFootprint(*footlist, nearest, dist);
353  }
354 
355  // Go through the (parent) Footprint looking for stray flux:
356  // pixels that are not claimed by any template, and positive.
357  const SpanList& spans = foot.getSpans();
358  for (SpanList::const_iterator s = spans.begin(); s < spans.end(); s++) {
359  int y = (*s)->getY();
360  int x0 = (*s)->getX0();
361  int x1 = (*s)->getX1();
362  typename ImageT::x_iterator tsum_it =
363  tsum->row_begin(y - sumy0) + (x0 - sumx0);
364  typename MaskedImageT::x_iterator in_it =
365  img.row_begin(y - iy0) + (x0 - ix0);
366  double contrib[tfoots.size()];
367 
368  for (int x = x0; x <= x1; ++x, ++tsum_it, ++in_it) {
369  // Skip pixels that are covered by at least one
370  // template (*tsum_it > 0) or the input is not
371  // positive (*in_it <= 0).
372  if ((*tsum_it > 0) || (*in_it).image() <= 0) {
373  continue;
374  }
375 
376  if (strayFluxOptions & STRAYFLUX_R_TO_FOOTPRINT) {
377  // we'll compute these just-in-time
378  for (size_t i=0; i<tfoots.size(); ++i) {
379  contrib[i] = -1.0;
380  }
381  } else if (strayFluxOptions & STRAYFLUX_NEAREST_FOOTPRINT) {
382  for (size_t i=0; i<tfoots.size(); ++i) {
383  contrib[i] = 0.0;
384  }
385  int i = nearest->get0(x, y);
386  contrib[i] = 1.0;
387  } else {
388  // R_TO_PEAK
389  for (size_t i=0; i<tfoots.size(); ++i) {
390  // Split the stray flux by 1/(1+r^2) to peaks
391  int dx, dy;
392  dx = pkx[i] - x;
393  dy = pky[i] - y;
394  contrib[i] = 1. / (1. + dx*dx + dy*dy);
395  }
396  }
397 
398  // Round 1: skip point sources unless STRAYFLUX_TO_POINT_SOURCES_ALWAYS
399  // are we going to assign stray flux to ptsrcs?
400  bool ptsrcs = always;
401  double csum = 0.;
402  for (size_t i=0; i<tfoots.size(); ++i) {
403  // if we're skipping point sources and this is a point source...
404  if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
405  continue;
406  }
407  if (contrib[i] == -1.0) {
408  contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
409  }
410  csum += contrib[i];
411  }
412  if ((csum == 0.) &&
413  (strayFluxOptions &
414  STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY)) {
415  // No extended sources -- assign to pt sources
416  //log.debugf("necessary to assign stray flux to point sources");
417  ptsrcs = true;
418  for (size_t i=0; i<tfoots.size(); ++i) {
419  if (contrib[i] == -1.0) {
420  contrib[i] = _get_contrib_r_to_footprint(x, y, tfoots[i]);
421  }
422  csum += contrib[i];
423  }
424  }
425 
426  // Drop small contributions...
427  double strayclip = (clipStrayFluxFraction * csum);
428  csum = 0.;
429  for (size_t i=0; i<tfoots.size(); ++i) {
430  // skip ptsrcs?
431  if ((!ptsrcs) && ispsf.size() && ispsf[i]) {
432  contrib[i] = 0.;
433  continue;
434  }
435  // skip small contributions
436  if (contrib[i] < strayclip) {
437  contrib[i] = 0.;
438  continue;
439  }
440  csum += contrib[i];
441  }
442 
443  for (size_t i=0; i<tfoots.size(); ++i) {
444  if (contrib[i] == 0.) {
445  continue;
446  }
447  // the stray flux to give to template i
448  double p = (contrib[i] / csum) * (*in_it).image();
449  if (!strayfoot[i]) {
450  strayfoot[i] = PTR(det::Footprint)(new det::Footprint(foot.getPeaks().getSchema()));
451  }
452  strayfoot[i]->addSpanInSeries(y, x, x); // XXX this may be rather heavy in memory use
453  straypix[i].push_back(p);
454  straymask[i].push_back((*in_it).mask());
455  strayvar[i].push_back((*in_it).variance());
456  }
457  }
458  }
459 
460  // Store the stray flux in HeavyFootprints
461  for (size_t i=0; i<tfoots.size(); ++i) {
462  if (!strayfoot[i]) {
463  strays.push_back(HeavyFootprintPtrT());
464  } else {
468  HeavyFootprintPtrT heavy(new HeavyFootprint(*strayfoot[i]));
469  ndarray::Array<ImagePixelT,1,1> himg = heavy->getImageArray();
470  typename std::vector<ImagePixelT>::const_iterator spix;
471  typename std::vector<MaskPixelT>::const_iterator smask;
472  typename std::vector<VariancePixelT>::const_iterator svar;
473  typename ndarray::Array<ImagePixelT,1,1>::Iterator hpix;
474  typename ndarray::Array<MaskPixelT,1,1>::Iterator mpix;
475  typename ndarray::Array<VariancePixelT,1,1>::Iterator vpix;
476 
477  assert((size_t)strayfoot[i]->getNpix() == straypix[i].size());
478 
479  for (spix = straypix[i].begin(),
480  smask = straymask[i].begin(),
481  svar = strayvar [i].begin(),
482  hpix = himg.begin(),
483  mpix = heavy->getMaskArray().begin(),
484  vpix = heavy->getVarianceArray().begin();
485  spix != straypix[i].end();
486  ++spix, ++smask, ++svar, ++hpix, ++mpix, ++vpix) {
487  *hpix = *spix;
488  *mpix = *smask;
489  *vpix = *svar;
490  }
491  strays.push_back(heavy);
492  }
493  }
494 }
495 
496 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
497 void
499 _sum_templates(std::vector<ImagePtrT> timgs,
500  ImagePtrT tsum) {
501  geom::Box2I sumbb = tsum->getBBox();
502  int sumx0 = sumbb.getMinX();
503  int sumy0 = sumbb.getMinY();
504 
505  // Compute tsum = the sum of templates
506  for (size_t i=0; i<timgs.size(); ++i) {
507  ImagePtrT timg = timgs[i];
508  geom::Box2I tbb = timg->getBBox();
509  int tx0 = tbb.getMinX();
510  int ty0 = tbb.getMinY();
511  // To handle "ramped" templates that can extend outside the
512  // parent, clip the bbox. Note that we saved tx0,ty0 BEFORE
513  // doing this!
514  tbb.clip(sumbb);
515  int copyx0 = tbb.getMinX();
516  // Here we iterate over the template bbox -- we could instead
517  // iterate over the "tfoot"s.
518  for (int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
519  typename ImageT::x_iterator in_it = timg->row_begin(y - ty0) + (copyx0 - tx0);
520  typename ImageT::x_iterator inend = in_it + tbb.getWidth();
521  typename ImageT::x_iterator tsum_it =
522  tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
523  for (; in_it != inend; ++in_it, ++tsum_it) {
524  *tsum_it += std::max((ImagePixelT)0., static_cast<ImagePixelT>(*in_it));
525  }
526  }
527  }
528 
529 }
530 
579 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
580 std::vector<typename PTR(image::MaskedImage<ImagePixelT, MaskPixelT, VariancePixelT>)>
582 apportionFlux(MaskedImageT const& img,
583  det::Footprint const& foot,
584  std::vector<ImagePtrT> timgs,
585  std::vector<PTR(det::Footprint)> tfoots,
586  ImagePtrT tsum,
587  std::vector<bool> const& ispsf,
588  std::vector<int> const& pkx,
589  std::vector<int> const& pky,
590  std::vector<std::shared_ptr<typename det::HeavyFootprint<ImagePixelT,MaskPixelT,VariancePixelT> > > & strays,
591  int strayFluxOptions,
592  double clipStrayFluxFraction
593  ) {
594  typedef typename det::Footprint::SpanList SpanList;
595 
596  if (timgs.size() != tfoots.size()) {
597  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
598  (boost::format("Template images must be the same length as template footprints (%d vs %d)")
599  % timgs.size() % tfoots.size()).str());
600  }
601 
602  for (size_t i=0; i<timgs.size(); ++i) {
603  if (!timgs[i]->getBBox().contains(tfoots[i]->getBBox())) {
604  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
605  "Template image MUST contain template footprint");
606  }
607  if (!img.getBBox().contains(foot.getBBox())) {
608  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
609  "Image bbox MUST contain parent footprint");
610  }
611  // template bounding-boxes *can* extend outside the parent
612  // footprint if we are ramping templates with significant flux
613  // at the edges. We handle this below.
614  }
615 
616  // the apportioned flux return value
617  std::vector<MaskedImagePtrT> portions;
618 
620  "lsst.meas.deblender.apportionFlux");
621  bool findStrayFlux = (strayFluxOptions & ASSIGN_STRAYFLUX);
622 
623  int ix0 = img.getX0();
624  int iy0 = img.getY0();
625  geom::Box2I fbb = foot.getBBox();
626 
627  if (!tsum) {
628  tsum = ImagePtrT(new ImageT(fbb.getDimensions()));
629  tsum->setXY0(fbb.getMinX(), fbb.getMinY());
630  }
631 
632  if (!tsum->getBBox().contains(foot.getBBox())) {
633  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
634  "Template sum image MUST contain parent footprint");
635  }
636 
637  geom::Box2I sumbb = tsum->getBBox();
638  int sumx0 = sumbb.getMinX();
639  int sumy0 = sumbb.getMinY();
640 
641  _sum_templates(timgs, tsum);
642 
643  // Compute flux portions
644  for (size_t i=0; i<timgs.size(); ++i) {
645  ImagePtrT timg = timgs[i];
646  // Initialize return value:
647  MaskedImagePtrT port(new MaskedImageT(timg->getDimensions()));
648  port->setXY0(timg->getXY0());
649  portions.push_back(port);
650 
651  // Split flux = image * template / tsum
652  geom::Box2I tbb = timg->getBBox();
653  int tx0 = tbb.getMinX();
654  int ty0 = tbb.getMinY();
655  // As above
656  tbb.clip(sumbb);
657  int copyx0 = tbb.getMinX();
658  for (int y=tbb.getMinY(); y<=tbb.getMaxY(); ++y) {
659  typename MaskedImageT::x_iterator in_it =
660  img.row_begin(y - iy0) + (copyx0 - ix0);
661  typename ImageT::x_iterator tptr =
662  timg->row_begin(y - ty0) + (copyx0 - tx0);
663  typename ImageT::x_iterator tend = tptr + tbb.getWidth();
664  typename ImageT::x_iterator tsum_it =
665  tsum->row_begin(y - sumy0) + (copyx0 - sumx0);
666  typename MaskedImageT::x_iterator out_it =
667  port->row_begin(y - ty0) + (copyx0 - tx0);
668  for (; tptr != tend; ++tptr, ++in_it, ++out_it, ++tsum_it) {
669  if (*tsum_it == 0) {
670  continue;
671  }
672  double frac = std::max((ImagePixelT)0., static_cast<ImagePixelT>(*tptr)) / (*tsum_it);
673  //if (frac == 0) {
674  // treat mask planes differently?
675  // }
676  out_it.mask() = (*in_it).mask();
677  out_it.variance() = (*in_it).variance();
678  out_it.image() = (*in_it).image() * frac;
679  }
680  }
681  }
682 
683  if (findStrayFlux) {
684  if ((ispsf.size() > 0) && (ispsf.size() != timgs.size())) {
685  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
686  (boost::format("'ispsf' must be the same length as templates (%d vs %d)")
687  % ispsf.size() % timgs.size()).str());
688  }
689  if ((pkx.size() != timgs.size()) || (pky.size() != timgs.size())) {
690  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
691  (boost::format("'pkx' and 'pky' must be the same length as templates (%d,%d vs %d)")
692  % pkx.size() % pky.size() % timgs.size()).str());
693  }
694  _find_stray_flux(foot, tsum, img, strayFluxOptions, tfoots,
695  ispsf, pkx, pky, clipStrayFluxFraction, strays);
696  }
697  return portions;
698 }
699 
700 
710 public:
712 
714 
715  RelativeSpanIterator(SpanList::const_iterator const& real,
716  SpanList const& arr,
717  int cx, int cy, bool forward=true)
718  : _real(real), _cx(cx), _cy(cy), _forward(forward)
719  {
720  if (_forward) {
721  _end = arr.end();
722  } else {
723  _end = arr.begin();
724  }
725  }
726 
727  bool operator==(const SpanList::const_iterator & other) {
728  return _real == other;
729  }
730  bool operator!=(const SpanList::const_iterator & other) {
731  return _real != other;
732  }
733  bool operator<=(const SpanList::const_iterator & other) {
734  return _real <= other;
735  }
736  bool operator<(const SpanList::const_iterator & other) {
737  return _real < other;
738  }
739  bool operator>=(const SpanList::const_iterator & other) {
740  return _real >= other;
741  }
742  bool operator>(const SpanList::const_iterator & other) {
743  return _real > other;
744  }
745 
747  return (_real == other._real) &&
748  (_cx == other._cx) && (_cy == other._cy) &&
749  (_forward == other._forward);
750  }
752  return !(*this == other);
753  }
754 
756  if (_forward) {
757  _real++;
758  } else {
759  _real--;
760  }
761  return *this;
762  }
764  RelativeSpanIterator result = *this;
765  ++(*this);
766  return result;
767  }
768 
769  bool notDone() {
770  if (_forward) {
771  return _real < _end;
772  } else {
773  return _real >= _end;
774  }
775  }
776 
777  int dxlo() {
778  if (_forward) {
779  return (*_real)->getX0() - _cx;
780  } else {
781  return _cx - (*_real)->getX1();
782  }
783  }
784  int dxhi() {
785  if (_forward) {
786  return (*_real)->getX1() - _cx;
787  } else {
788  return _cx - (*_real)->getX0();
789  }
790  }
791  int dy() {
792  return std::abs((*_real)->getY() - _cy);
793  }
794  int x0() {
795  return (*_real)->getX0();
796  }
797  int x1() {
798  return (*_real)->getX1();
799  }
800  int y() {
801  return (*_real)->getY();
802  }
803 
804 private:
805  SpanList::const_iterator _real;
806  SpanList::const_iterator _end;
807  int _cx;
808  int _cy;
809  bool _forward;
810 };
811 
812 
813 /*
814  // Check symmetrizeFootprint by computing truth naively.
815  // compute correct answer dumbly
816  det::Footprint truefoot;
817  geom::Box2I bbox = foot.getBBox();
818  for (int y=bbox.getMinY(); y<=bbox.getMaxY(); y++) {
819  for (int x=bbox.getMinX(); x<=bbox.getMaxX(); x++) {
820  int dy = y - cy;
821  int dx = x - cx;
822  int x2 = cx - dx;
823  int y2 = cy - dy;
824  if (foot.contains(geom::Point2I(x, y)) &&
825  foot.contains(geom::Point2I(x2, y2))) {
826  truefoot.addSpan(y, x, x);
827  }
828  }
829  }
830  truefoot.normalize();
831 
832  SpanList sp1 = truefoot.getSpans();
833  SpanList sp2 = sfoot->getSpans();
834  for (SpanList::const_iterator spit1 = sp1.begin(),
835  spit2 = sp2.begin();
836  spit1 != sp1.end() && spit2 != sp2.end();
837  spit1++, spit2++) {
838  //printf("\n");
839  printf(" true y %i, x [%i, %i]\n", (*spit1)->getY(), (*spit1)->getX0(), (*spit1)->getX1());
840  printf(" sfoot y %i, x [%i, %i]\n", (*spit2)->getY(), (*spit2)->getX0(), (*spit2)->getX1());
841  if (((*spit1)->getY() != (*spit2)->getY()) ||
842  ((*spit1)->getX0() != (*spit2)->getX0()) ||
843  ((*spit1)->getX1() != (*spit2)->getX1())) {
844  printf("*******************************************\n");
845  }
846  }
847  assert(sp1.size() == sp2.size());
848  for (SpanList::const_iterator spit1 = sp1.begin(),
849  spit2 = sp2.begin();
850  spit1 != sp1.end() && spit2 != sp2.end();
851  spit1++, spit2++) {
852  assert((*spit1)->getY() == (*spit2)->getY());
853  assert((*spit1)->getX0() == (*spit2)->getX0());
854  assert((*spit1)->getX1() == (*spit2)->getX1());
855  }
856  */
857 
863 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
865 deblend::BaselineUtils<ImagePixelT,MaskPixelT,VariancePixelT>::
866 symmetrizeFootprint(
867  det::Footprint const& foot,
868  int cx, int cy) {
869 
870  typedef typename det::Footprint::SpanList SpanList;
871 
872  PTR(det::Footprint) sfoot(new det::Footprint(foot.getPeaks().getSchema()));
873  const SpanList spans = foot.getSpans();
874  assert(foot.isNormalized());
875 
877  "lsst.meas.deblender.symmetrizeFootprint");
878 
879  // Find the Span containing the peak.
880  PTR(det::Span) target(new det::Span(cy, cx, cx));
881  SpanList::const_iterator peakspan =
882  std::upper_bound(spans.begin(), spans.end(), target, span_ptr_compare);
883  // upper_bound returns the last position where "target" could be inserted;
884  // ie, the first Span larger than "target". The Span containing "target"
885  // should be peakspan-1 or (if the peak is on the first pixel in the span,
886  // peakspan.
887  PTR(det::Span) sp;
888  if (peakspan == spans.begin()) {
889  sp = *peakspan;
890  if (!sp->contains(cx, cy)) {
891  log.warnf(
892  "Failed to find span containing (%i,%i): before the beginning of this footprint", cx, cy);
893  return PTR(det::Footprint)();
894  }
895  } else {
896  --peakspan;
897  sp = *peakspan;
898 
899  if (!sp->contains(cx, cy)) {
900  ++peakspan;
901  sp = *peakspan;
902  if (!sp->contains(cx, cy)) {
903  geom::Box2I fbb = foot.getBBox();
904  log.warnf("Failed to find span containing (%i,%i): nearest is %i, [%i,%i]. "
905  "Footprint bbox is [%i,%i],[%i,%i]",
906  cx, cy, sp->getY(), sp->getX0(), sp->getX1(),
907  fbb.getMinX(), fbb.getMaxX(), fbb.getMinY(), fbb.getMaxY());
908  return PTR(det::Footprint)();
909  }
910  }
911  }
912  log.debugf("Span containing (%i,%i): (x=[%i,%i], y=%i)",
913  cx, cy, sp->getX0(), sp->getX1(), sp->getY());
914 
915  // The symmetric templates are essentially an AND of the footprint
916  // pixels and its 180-degree-rotated self, rotated around the
917  // peak (cx,cy).
918  //
919  // We iterate forward and backward simultaneously, starting from
920  // the span containing the peak and moving out, row by row.
921  //
922  // In the loop below, we search for the next pair of Spans that
923  // overlap (in "dx" from the center), output the overlapping
924  // portion of the Spans, and advance either the "fwd" or "back"
925  // iterator. When we fail to find an overlapping pair of Spans,
926  // we move on to the next row.
927  //
928  // [The following paragraph is somewhat obsoleted by the
929  // RelativeSpanIterator class, which performs some of the renaming
930  // and the dx,dy coords.]
931  //
932  // '''In reading the code, "forward", "advancing", etc, are all
933  // from the perspective of the "fwd" iterator (the one going
934  // forward through the Span list, from low to high Y and then low
935  // to high X). It will help to imagine making a copy of the
936  // footprint and rotating it around the center pixel by 180
937  // degrees, so that "fwd" and "back" are both iterating the same
938  // direction; we're then just finding the AND of those two
939  // iterators, except we have to work in dx,dy coordinates rather
940  // than original x,y coords, and the accessors for "back" are
941  // opposite.'''
942 
943  RelativeSpanIterator fwd (peakspan, spans, cx, cy, true);
944  RelativeSpanIterator back(peakspan, spans, cx, cy, false);
945 
946  int dy = 0;
947  while (fwd.notDone() && back.notDone()) {
948  // forward and backward "y"; just symmetric around cy
949  int fy = cy + dy;
950  int by = cy - dy;
951  // delta-x of the beginnings of the spans, for "fwd" and "back"
952  int fdxlo = fwd.dxlo();
953  int bdxlo = back.dxlo();
954 
955  // First find:
956  // fend -- first span in the next row, or end(); ie,
957  // the end of this row in the forward direction
958  // bend -- the end of this row in the backward direction
959  RelativeSpanIterator fend, bend;
960  for (fend = fwd; fend.notDone(); ++fend) {
961  if (fend.dy() != dy)
962  break;
963  }
964  for (bend = back; bend.notDone(); ++bend) {
965  if (bend.dy() != dy)
966  break;
967  }
968 
969  log.debugf("dy=%i, fy=%i, fx=[%i, %i], by=%i, fx=[%i, %i], fdx=%i, bdx=%i",
970  dy, fy, fwd.x0(), fwd.x1(), by, back.x0(), back.x1(),
971  fdxlo, bdxlo);
972 
973  // Find possibly-overlapping span
974  if (bdxlo > fdxlo) {
975  log.debugf("Advancing forward.");
976  // While the "forward" span is entirely to the "left" of the "backward" span,
977  // (in dx coords), ie, |---fwd---X X---back---|
978  // and we are comparing the edges marked X
979  while ((fwd != fend) && (fwd.dxhi() < bdxlo)) {
980  fwd++;
981  if (fwd == fend) {
982  log.debugf("Reached fend");
983  } else {
984  log.debugf("Advanced to forward span %i, [%i, %i]",
985  fy, fwd.x0(), fwd.x1());
986  }
987  }
988  } else if (fdxlo > bdxlo) {
989  log.debugf("Advancing backward.");
990  // While the "backward" span is entirely to the "left" of the "foreward" span,
991  // (in dx coords), ie, |---back---X X---fwd---|
992  // and we are comparing the edges marked X
993  while ((back != bend) && (back.dxhi() < fdxlo)) {
994  back++;
995  if (back == bend) {
996  log.debugf("Reached bend");
997  } else {
998  log.debugf("Advanced to backward span %i, [%i, %i]",
999  by, back.x0(), back.x1());
1000  }
1001  }
1002  }
1003 
1004  if ((back == bend) || (fwd == fend)) {
1005  // We reached the end of the row without finding spans that could
1006  // overlap. Move onto the next dy.
1007  if (back == bend) {
1008  log.debugf("Reached bend");
1009  }
1010  if (fwd == fend) {
1011  log.debugf("Reached fend");
1012  }
1013  back = bend;
1014  fwd = fend;
1015  dy++;
1016  continue;
1017  }
1018 
1019  // Spans may overlap -- find the overlapping part.
1020  int dxlo = std::max(fwd.dxlo(), back.dxlo());
1021  int dxhi = std::min(fwd.dxhi(), back.dxhi());
1022  if (dxlo <= dxhi) {
1023  log.debugf("Adding span fwd %i, [%i, %i], back %i, [%i, %i]",
1024  fy, cx+dxlo, cx+dxhi, by, cx-dxhi, cx-dxlo);
1025  sfoot->addSpan(fy, cx + dxlo, cx + dxhi);
1026  sfoot->addSpan(by, cx - dxhi, cx - dxlo);
1027  }
1028 
1029  // Advance the one whose "hi" edge is smallest
1030  if (fwd.dxhi() < back.dxhi()) {
1031  fwd++;
1032  if (fwd == fend) {
1033  log.debugf("Stepped to fend");
1034  } else {
1035  log.debugf("Stepped forward to span %i, [%i, %i]",
1036  fwd.y(), fwd.x0(), fwd.x1());
1037  }
1038  } else {
1039  back++;
1040  if (back == bend) {
1041  log.debugf("Stepped to bend");
1042  } else {
1043  log.debugf("Stepped backward to span %i, [%i, %i]",
1044  back.y(), back.x0(), back.x1());
1045  }
1046  }
1047 
1048  if ((back == bend) || (fwd == fend)) {
1049  // Reached the end of the row. On to the next dy!
1050  if (back == bend) {
1051  log.debugf("Reached bend");
1052  }
1053  if (fwd == fend) {
1054  log.debugf("Reached fend");
1055  }
1056  back = bend;
1057  fwd = fend;
1058  dy++;
1059  continue;
1060  }
1061 
1062  }
1063  sfoot->normalize();
1064  return sfoot;
1065 }
1066 
1079 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
1080 std::pair<typename PTR(lsst::afw::image::Image<ImagePixelT>),
1084  MaskedImageT const& img,
1085  det::Footprint const& foot,
1086  det::PeakRecord const& peak,
1087  double sigma1,
1088  bool minZero,
1089  bool patchEdge,
1090  bool* patchedEdges) {
1091 
1092  typedef typename MaskedImageT::const_xy_locator xy_loc;
1093  typedef typename det::Footprint::SpanList SpanList;
1094 
1095  *patchedEdges = false;
1096 
1097  int cx = peak.getIx();
1098  int cy = peak.getIy();
1099 
1101  "lsst.meas.deblender.symmetricFootprint");
1102 
1103  if (!img.getBBox(image::PARENT).contains(foot.getBBox())) {
1104  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError, "Image too small for footprint");
1105  }
1106 
1107  FootprintPtrT sfoot = symmetrizeFootprint(foot, cx, cy);
1108  if (!sfoot) {
1109  return std::pair<ImagePtrT, FootprintPtrT>(ImagePtrT(), sfoot);
1110  }
1111 
1112  if (!img.getBBox(image::PARENT).contains(sfoot->getBBox())) {
1113  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
1114  "Image too small for symmetrized footprint");
1115  }
1116  const SpanList spans = sfoot->getSpans();
1117 
1118  // does this footprint touch an EDGE?
1119  bool touchesEdge = false;
1120  if (patchEdge) {
1121  log.debugf("Checking footprint for EDGE bits");
1122  MaskPtrT mask = img.getMask();
1123  bool edge = false;
1124  MaskPixelT edgebit = mask->getPlaneBitMask("EDGE");
1125  for (SpanList::const_iterator fwd=spans.begin();
1126  fwd != spans.end(); ++fwd) {
1127  int x0 = (*fwd)->getX0();
1128  int x1 = (*fwd)->getX1();
1129  typename MaskT::x_iterator xiter =
1130  mask->x_at(x0 - mask->getX0(), (*fwd)->getY() - mask->getY0());
1131  for (int x=x0; x<=x1; ++x, ++xiter) {
1132  if ((*xiter) & edgebit) {
1133  edge = true;
1134  break;
1135  }
1136  }
1137  if (edge)
1138  break;
1139  }
1140  if (edge) {
1141  log.debugf("Footprint includes an EDGE pixel.");
1142  touchesEdge = true;
1143  }
1144  }
1145 
1146  // The result image:
1147  ImagePtrT targetimg(new ImageT(sfoot->getBBox()));
1148 
1149  SpanList::const_iterator fwd = spans.begin();
1150  SpanList::const_iterator back = spans.end()-1;
1151 
1152  ImagePtrT theimg = img.getImage();
1153 
1154  for (; fwd <= back; fwd++, back--) {
1155  int fy = (*fwd)->getY();
1156  int by = (*back)->getY();
1157 
1158  for (int fx=(*fwd)->getX0(), bx=(*back)->getX1();
1159  fx <= (*fwd)->getX1();
1160  fx++, bx--) {
1161  // FIXME -- CURRENTLY WE IGNORE THE MASK PLANE! options
1162  // include ORing the mask bits, or being clever about
1163  // ignoring some masked pixels, or copying the mask bits
1164  // of the min pixel
1165 
1166  // We have already checked the bounding box, so this should always be satisfied
1167  assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(fx, fy)));
1168  assert(theimg->getBBox(image::PARENT).contains(geom::Point2I(bx, by)));
1169 
1170  // FIXME -- we could do this with image iterators instead.
1171  // But first profile to show that it's necessary and an
1172  // improvement.
1173  ImagePixelT pixf = theimg->get0(fx, fy);
1174  ImagePixelT pixb = theimg->get0(bx, by);
1175  ImagePixelT pix = std::min(pixf, pixb);
1176  if (minZero) {
1177  pix = std::max(pix, static_cast<ImagePixelT>(0));
1178  }
1179  targetimg->set0(fx, fy, pix);
1180  targetimg->set0(bx, by, pix);
1181 
1182  }
1183  }
1184 
1185 
1186  if (touchesEdge) {
1187  // Find spans whose mirrors fall outside the image bounds,
1188  // grow the footprint to include those spans, and plug in
1189  // their pixel values.
1190  geom::Box2I bb = sfoot->getBBox();
1191 
1192  // Actually, it's not necessarily the IMAGE bounds that count
1193  //-- the footprint may not go right to the image edge.
1194  //geom::Box2I imbb = img.getBBox();
1195  geom::Box2I imbb = foot.getBBox();
1196 
1197  log.debugf("Footprint touches EDGE: start bbox [%i,%i],[%i,%i]",
1198  bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1199  // original footprint spans
1200  const SpanList ospans = foot.getSpans();
1201  for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1202  int y = (*fwd)->getY();
1203  int x = (*fwd)->getX0();
1204  // mirrored coords
1205  int ym = cy + (cy - y);
1206  int xm = cx + (cx - x);
1207  if (!imbb.contains(geom::Point2I(xm, ym))) {
1208  bb.include(geom::Point2I(x, y));
1209  }
1210  x = (*fwd)->getX1();
1211  xm = cx + (cx - x);
1212  if (!imbb.contains(geom::Point2I(xm, ym))) {
1213  bb.include(geom::Point2I(x, y));
1214  }
1215  }
1216  log.debugf("Footprint touches EDGE: grown bbox [%i,%i],[%i,%i]",
1217  bb.getMinX(), bb.getMaxX(), bb.getMinY(), bb.getMaxY());
1218 
1219  // New template image
1220  ImagePtrT targetimg2(new ImageT(bb));
1221  copyWithinFootprint(*sfoot, targetimg, targetimg2);
1222 
1223  log.debugf("Symmetric footprint spans:");
1224  const SpanList sspans = sfoot->getSpans();
1225  for (fwd = sspans.begin(); fwd != sspans.end(); ++fwd) {
1226  log.debugf(" %s", (*fwd)->toString().c_str());
1227  }
1228 
1229  // copy original 'img' pixels for the portion of spans whose
1230  // mirrors are out of bounds.
1231  for (fwd = ospans.begin(); fwd != ospans.end(); ++fwd) {
1232  int y = (*fwd)->getY();
1233  int x0 = (*fwd)->getX0();
1234  int x1 = (*fwd)->getX1();
1235  // mirrored coords
1236  int ym = cy + (cy - y);
1237  int xm0 = cx + (cx - x0);
1238  int xm1 = cx + (cx - x1);
1239  bool in0 = imbb.contains(geom::Point2I(xm0, ym));
1240  bool in1 = imbb.contains(geom::Point2I(xm1, ym));
1241  if (in0 && in1) {
1242  // both endpoints of the symmetric span are in bounds; nothing to do
1243  continue;
1244  }
1245  // clip to the part of the span where the mirror is out of bounds
1246  if (in0) {
1247  // the mirror of x0 is in-bounds; move x0 to be the first pixel
1248  // whose mirror would be out-of-bounds
1249  x0 = cx + (cx - (imbb.getMinX() - 1));
1250  }
1251  if (in1) {
1252  x1 = cx + (cx - (imbb.getMaxX() + 1));
1253  }
1254  log.debugf("Span y=%i, x=[%i,%i] has mirror (%i,[%i,%i]) out-of-bounds; clipped to %i,[%i,%i]",
1255  y, (*fwd)->getX0(), (*fwd)->getX1(), ym, xm1, xm0, y, x0, x1);
1256  typename MaskedImageT::x_iterator initer =
1257  img.x_at(x0 - img.getX0(), y - img.getY0());
1258  typename ImageT::x_iterator outiter =
1259  targetimg2->x_at(x0 - targetimg2->getX0(), y - targetimg2->getY0());
1260  for (int x=x0; x<=x1; ++x, ++outiter, ++initer) {
1261  *outiter = initer.image();
1262  }
1263  sfoot->addSpan(y, x0, x1);
1264  }
1265  sfoot->normalize();
1266  targetimg = targetimg2;
1267  }
1268 
1269  *patchedEdges = touchesEdge;
1270  return std::pair<ImagePtrT, FootprintPtrT>(targetimg, sfoot);
1271 }
1272 
1277 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
1278 bool
1281  PTR(det::Footprint) sfoot,
1282  ImagePixelT thresh) {
1283  typedef typename det::Footprint::SpanList SpanList;
1284 
1286  "lsst.meas.deblender.hasSignificantFluxAtEdge");
1287 
1288  // Find edge template pixels with significant flux -- perhaps
1289  // because their symmetric pixels were outside the footprint?
1290  // (clipped by an image edge, etc)
1291  PTR(det::Footprint) edge = sfoot->findEdgePixels();
1292 
1293  const SpanList spans = edge->getSpans();
1294  for (SpanList::const_iterator sp = spans.begin(); sp != spans.end(); ++sp) {
1295  int const y = (*sp)->getY();
1296  int const x0 = (*sp)->getX0();
1297  int const x1 = (*sp)->getX1();
1298  int x;
1299  typename ImageT::const_x_iterator xiter;
1300  for (xiter = img->x_at(x0 - img->getX0(), y - img->getY0()), x=x0; x<=x1; ++x, ++xiter) {
1301  if (*xiter >= thresh) {
1302  return true;
1303  }
1304  }
1305  }
1306  return false;
1307 }
1308 
1313 template<typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
1314 std::shared_ptr<det::Footprint>
1317  PTR(det::Footprint) sfoot,
1318  ImagePixelT thresh) {
1320  "lsst.meas.deblender.getSignificantEdgePixels");
1321 
1322  sfoot->normalize(); // Algorithms require spans sorted by y
1323 
1324  PTR(det::Footprint) significant(new det::Footprint(sfoot->getPeaks().getSchema()));
1325 
1326  int const x0 = img->getX0(), y0 = img->getY0();
1327  CONST_PTR(det::Footprint) const edges = sfoot->findEdgePixels();
1328  for (det::Footprint::SpanList::const_iterator ss = edges->getSpans().begin();
1329  ss != edges->getSpans().end(); ++ss) {
1330  geom::Span const& span = **ss;
1331  int const y = span.getY();
1332  int x = span.getX0();
1333  typename ImageT::const_x_iterator iter = img->x_at(x - x0, y - y0);
1334  bool onSpan = false; // Are we in a span of interest
1335  int xSpan; // Starting x of span
1336  for (; x <= span.getX1(); ++x, ++iter) {
1337  if (*iter >= thresh) {
1338  onSpan = true;
1339  xSpan = x;
1340  } else if (onSpan) {
1341  onSpan = false;
1342  significant->addSpanInSeries(y, xSpan, x - 1);
1343  }
1344  }
1345  if (onSpan) {
1346  significant->addSpanInSeries(y, xSpan, span.getX1());
1347  }
1348  }
1349 
1350  return significant;
1351 }
1352 
1353 
1354 // Instantiate
1355 template class deblend::BaselineUtils<float>;
std::vector< Span::Ptr > SpanList
The Footprint&#39;s Span list.
Definition: Footprint.h:71
int y
static std::shared_ptr< lsst::afw::detection::Footprint > getSignificantEdgePixels(ImagePtrT, std::shared_ptr< lsst::afw::detection::Footprint >, ImagePixelT threshold)
Definition: Baseline.cc:1316
int iter
x_iterator row_begin(int y) const
Return an x_iterator to the start of the image.
Definition: MaskedImage.cc:757
int getMaxY() const
Definition: Box.h:129
Ref< MaskPixelT >::type mask()
Return (a reference to) the mask part of the Pixel pointed at by the iterator.
Definition: MaskedImage.h:153
void debugf(const char *fmt,...)
Definition: Log.h:535
Extent2I const getDimensions() const
Definition: Box.h:153
bool operator>=(const SpanList::const_iterator &other)
Definition: Baseline.cc:739
static void medianFilter(ImageT const &img, ImageT &outimg, int halfsize)
Definition: Baseline.cc:39
bool contains(Point2I const &point) const
Return true if the box contains the point.
int getX0() const
Return the starting x-value.
Definition: Span.h:77
RelativeSpanIterator(SpanList::const_iterator const &real, SpanList const &arr, int cx, int cy, bool forward=true)
Definition: Baseline.cc:715
A range of pixels within one row of an Image.
Definition: Span.h:54
void include(Point2I const &point)
Expand this to ensure that this-&gt;contains(point).
bool operator<(const SpanList::const_iterator &other)
Definition: Baseline.cc:736
static Log & getDefaultLog()
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
Definition: Image.h:158
bool operator==(RelativeSpanIterator &other)
Definition: Baseline.cc:746
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: Image.h:151
bool operator==(const SpanList::const_iterator &other)
Definition: Baseline.cc:727
geom::Box2I getBBox(ImageOrigin const origin=PARENT) const
Definition: MaskedImage.h:911
ImagePtr getImage(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage&#39;s image.
Definition: MaskedImage.h:875
MaskPixelT mask() const
Return the mask part of a Pixel.
Definition: Pixel.h:202
boost::shared_ptr< lsst::afw::detection::Footprint > FootprintPtrT
Definition: Baseline.h:33
#define CONST_PTR(...)
Definition: base.h:47
a place to record messages and descriptions of the state of processing.
Definition: Log.h:154
int getX0() const
Definition: Image.h:249
boost::shared_ptr< lsst::afw::image::Mask< MaskPixelT > > MaskPtrT
Definition: Baseline.h:30
int const x0
Definition: saturated.cc:45
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)
Definition: Baseline.cc:1083
An integer coordinate rectangle.
Definition: Box.h:53
A set of pixels in an Image, including those pixels&#39; actual values.
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
boost::shared_ptr< lsst::afw::image::Image< ImagePixelT > > ImagePtrT
Definition: Baseline.h:28
Iterator begin() const
Return an iterator to the first pixel in the Span.
Definition: Span.h:72
x_iterator x_at(int x, int y) const
Return an x_iterator at the point (x, y)
Definition: MaskedImage.h:1012
def log
Definition: log.py:83
int getIy() const
Convenience accessors for the keys in the minimal schema.
Definition: Peak.h:210
int getY() const
Return the y-value.
Definition: Span.h:81
x_iterator row_end(int y) const
Return an x_iterator to the end of the y&#39;th row.
Definition: Image.h:326
int getMinY() const
Definition: Box.h:125
static void _sum_templates(std::vector< ImagePtrT > timgs, ImagePtrT tsum)
Definition: Baseline.cc:499
MaskPtr getMask(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage&#39;s mask.
Definition: MaskedImage.h:885
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:78
SpanList::const_iterator _real
Definition: Baseline.cc:805
det::Footprint::SpanList SpanList
Definition: Baseline.cc:711
boost::shared_ptr< lsst::afw::detection::HeavyFootprint< ImagePixelT > MaskPixelT, VariancePixelT > HeavyFootprintPtrT
Definition: Baseline.h:36
int getIx() const
Convenience accessors for the keys in the minimal schema.
Definition: Peak.h:209
int getMinX() const
Definition: Box.h:124
int getHeight() const
Return the number of rows in the image.
Definition: Image.h:241
def deblend
Deblend a single footprint in a maskedImage.
Definition: baseline.py:245
bool operator<=(const SpanList::const_iterator &other)
Definition: Baseline.cc:733
double x
Ref< ImagePixelT >::type image()
Return (a reference to) the image part of the Pixel pointed at by the iterator.
Definition: MaskedImage.h:148
A set of pixels in an Image.
Definition: Footprint.h:62
int getWidth() const
Definition: Box.h:154
static void makeMonotonic(ImageT &img, lsst::afw::detection::PeakRecord const &pk)
Definition: Baseline.cc:117
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
SpanList::const_iterator _end
Definition: Baseline.cc:806
afw::table::Key< double > sigma1
boost::shared_ptr< lsst::afw::image::MaskedImage< ImagePixelT > MaskPixelT, VariancePixelT > MaskedImagePtrT
Definition: Baseline.h:26
lsst::afw::detection::Footprint Footprint
Definition: Source.h:60
#define PTR(...)
Definition: base.h:41
bool operator>(const SpanList::const_iterator &other)
Definition: Baseline.cc:742
bool operator!=(RelativeSpanIterator &other)
Definition: Baseline.cc:751
xy_locator xy_at(int x, int y) const
Definition: Image.h:353
void clip(Box2I const &other)
Shrink this to ensure that other.contains(*this).
x_iterator row_begin(int y) const
Definition: Image.h:321
int getMaxX() const
Definition: Box.h:128
int getX1() const
Return the ending x-value.
Definition: Span.h:79
Include files required for standard LSST Exception handling.
bool operator!=(const SpanList::const_iterator &other)
Definition: Baseline.cc:730
RelativeSpanIterator operator++()
Definition: Baseline.cc:755
boost::shared_ptr< Footprint > findEdgePixels() const
Find edge pixels on the footprint.
int const y0
Definition: saturated.cc:45
RelativeSpanIterator operator++(int dummy)
Definition: Baseline.cc:763
Record class that represents a peak in a Footprint.
Definition: Peak.h:40
void nearestFootprint(std::vector< boost::shared_ptr< Footprint >> const &foots, lsst::afw::image::Image< std::uint16_t >::Ptr argmin, lsst::afw::image::Image< std::uint16_t >::Ptr dist)
_view_t::xy_locator xy_locator
An xy_locator.
Definition: Image.h:139
static bool hasSignificantFluxAtEdge(ImagePtrT, std::shared_ptr< lsst::afw::detection::Footprint >, ImagePixelT threshold)
Definition: Baseline.cc:1280
int getWidth() const
Return the number of columns in the image.
Definition: Image.h:239
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)
Definition: Baseline.cc:288
T real(const T &x)
Definition: Integrate.h:193
Schema getSchema() const
Return the schema associated with the catalog&#39;s table.
Definition: Catalog.h:115
Iterator end() const
Return an iterator to one past the last pixel in the Span.
Definition: Span.h:75
void copyWithinFootprint(Footprint const &foot, boost::shared_ptr< ImageOrMaskedImageT > const input, boost::shared_ptr< ImageOrMaskedImageT > output)
geom::Box2I getBBox() const
Return the Footprint&#39;s bounding box.
Definition: Footprint.h:206
A const locator for the MaskedImage.
Definition: MaskedImage.h:116
int getY0() const
Definition: Image.h:257