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