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