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