34 #include "boost/format.hpp"
60 struct compareSpanByYX :
61 public std::binary_function<Span::ConstPtr, Span::ConstPtr, bool> {
62 int operator()(Span::ConstPtr a, Span::ConstPtr
b) {
84 ) : lsst::daf::base::Citizen(typeid(this)),
88 _peaks(PeakTable::makeMinimalSchema()),
94 lsst::pex::exceptions::InvalidParameterError,
95 str(
boost::format(
"Number of spans requested is -ve: %d") % nspan));
105 afw::table::Schema
const & peakSchema,
108 ) : lsst::daf::base::Citizen(typeid(this)),
111 _bbox(geom::Box2I()),
118 lsst::pex::exceptions::InvalidParameterError,
119 str(
boost::format(
"Number of spans requested is -ve: %d") % nspan));
128 ) : lsst::daf::base::Citizen(typeid(this)),
132 _peaks(PeakTable::makeMinimalSchema()),
140 for (
int i = y0; i <= y1; ++i) {
150 ) : lsst::daf::base::Citizen(typeid(this)),
154 _peaks(PeakTable::makeMinimalSchema()),
157 int const r2 =
static_cast<int>(radius*radius + 0.5);
158 int const r =
static_cast<int>(std::sqrt(static_cast<double>(r2)));
160 for (
int i = -r; i <= r; ++i) {
161 int hlen =
static_cast<int>(std::sqrt(static_cast<double>(r2 - i*i)));
162 addSpan(center.getY() + i, center.getX() - hlen, center.getX() + hlen);
168 geom::ellipses::Ellipse
const & ellipse,
170 ) : lsst::daf::base::Citizen(typeid(this)),
173 _bbox(geom::Box2I()),
174 _peaks(PeakTable::makeMinimalSchema()),
178 geom::ellipses::PixelRegion pr(ellipse);
180 geom::ellipses::PixelRegion::Iterator spanIter = pr.begin(), end = pr.end();
184 if (!spanIter->isEmpty()) {
192 Footprint::SpanList
const & spans,
194 ) : lsst::daf::base::Citizen(typeid(this)),
197 _bbox(geom::Box2I()),
198 _peaks(PeakTable::makeMinimalSchema()),
202 _spans.reserve(spans.size());
203 for(SpanList::const_iterator i(spans.begin()); i != spans.end(); ++i) {
209 : lsst::daf::base::Citizen(typeid(this)),
213 _peaks(other.getPeaks().getTable(), other.getPeaks().begin(), other.getPeaks().end(), true),
214 _region(other._region)
217 _spans.reserve(other._spans.size());
218 for(SpanList::const_iterator i(other._spans.begin());
219 i != other._spans.end(); ++i
224 _normalized = other._normalized;
228 Footprint::~Footprint() {
232 PTR(PeakRecord)
Footprint::addPeak(
float fx,
float fy,
float value) {
233 PTR(PeakRecord) p = getPeaks().addNew();
238 p->setPeakValue(value);
247 SortPeaks(afw::table::Key<float>
const & key) : _key(key) {}
250 return a.
get(_key) > b.
get(_key);
254 afw::table::Key<float> _key;
259 void Footprint::sortPeaks(afw::table::Key<float>
const & key) {
260 getPeaks().sort(SortPeaks(key.isValid() ? key : PeakTable::getPeakValueKey()));
266 bool Footprint::contains(
271 for (Footprint::SpanList::const_iterator siter = _spans.begin(); siter != _spans.end(); ++siter) {
272 if ((*siter)->contains(pix.getX(), pix.getY())) {
285 template<
typename MaskT>
293 for (Footprint::SpanList::const_iterator siter =
294 getSpans().begin(); siter != getSpans().end(); siter++) {
295 PTR(Span) const span = *siter;
296 int const
y = span->getY() - mask.getY0();
297 if (
y < 0 ||
y >= height) {
301 int x0 = span->getX0() - mask.
getX0();
302 int x1 = span->getX1() - mask.
getX0();
303 x0 = (x0 < 0) ? 0 : (x0 >= width ? width - 1 :
x0);
304 x1 = (x1 < 0) ? 0 : (x1 >= width ? width - 1 : x1);
307 end = mask.
x_at(x1 + 1,
y); ptr != end; ++ptr) {
318 struct ClipSpansPredicate :
public std::unary_function<PTR(Span) const&, bool> {
323 bool operator()(
PTR(Span)
const& spanPtr)
const {
324 Span
const& span = *spanPtr;
325 int const y = span.getY();
332 struct ClipPeaksPredicate :
public std::unary_function<PeakRecord const&, bool> {
337 bool operator()(
PTR(PeakRecord)
const& peak)
const {
344 _spans.erase(std::remove_if(_spans.begin(), _spans.end(), ClipSpansPredicate(bbox)), _spans.end());
345 for (SpanList::const_iterator ss = _spans.begin(); ss != _spans.end(); ++ss) {
347 span.getX0() = std::max(span.getX0(), bbox.
getMinX());
348 span.getX1() = std::min(span.getX1(), bbox.
getMaxX());
352 _peaks.getInternal().erase(std::remove_if(_peaks.getInternal().begin(), _peaks.getInternal().end(),
353 ClipPeaksPredicate(bbox)), _peaks.getInternal().end());
355 if (_spans.empty()) {
369 if (_spans.empty()) {
379 sort(_spans.begin(), _spans.end(), compareSpanByYX());
381 Footprint::SpanList::iterator ptr = _spans.begin(), end = _spans.end();
382 Span *lspan = ptr->get();
385 _area = lspan->getWidth();
386 int minX = lspan->_x0, minY=
y, maxX=x1;
390 for (; ptr != end; ++ptr) {
391 Span *rspan = ptr->get();
392 if (rspan->_y == y) {
393 if (rspan->_x0 <= x1 + 1) {
394 if (rspan->_x1 > x1) {
396 _area += rspan->_x1 - x1;
398 x1 = lspan->_x1 = rspan->_x1;
400 if(x1 > maxX) maxX = x1;
403 ptr = _spans.erase(ptr);
413 _area += rspan->getWidth();
414 if(rspan->_x1 > maxX) maxX = rspan->_x1;
417 _area += rspan->getWidth();
424 if(lspan->_x0 < minX) minX = lspan->_x0;
425 if(x1 > maxX) maxX = x1;
432 Span
const& Footprint::addSpan(
438 return addSpan(y, x1, x0);
441 PTR(Span) sp(new Span(y, x0, x1));
442 _spans.push_back(sp);
444 _area += sp->getWidth();
456 return addSpan(span._y, span._x0, span._x1);
459 const Span& Footprint::addSpan(
464 return addSpan(span._y + dy, span._x0 + dx, span._x1 + dx);
467 const Span& Footprint::addSpanInSeries(
473 return addSpanInSeries(y, x1, x0);
475 if (_spans.size() == 0) {
476 const Span& s = addSpan(y, x0, x1);
481 PTR(Span) lastspan = _spans.back();
482 if ((y == lastspan->getY()) &&
483 (x0 == (lastspan->getX1() + 1))) {
486 _area += (1 + x1 -
x0);
490 if (!((y > lastspan->getY()) ||
491 (x0 > (lastspan->getX1() + 1)))) {
493 lsst::pex::exceptions::InvalidParameterError,
494 str(
boost::format(
"addSpanInSeries: new span %i,[%i,%i] is NOT in series after last span "
496 y % x0 % x1 % lastspan->getY() % lastspan->getX0() % lastspan->getX1()));
498 const Span& s = addSpan(y, x0, x1);
503 void Footprint::shift(
507 for (SpanList::iterator i = _spans.begin(); i != _spans.end(); ++i){
522 double xc = 0, yc = 0;
523 for (Footprint::SpanList::const_iterator siter = _spans.begin(); siter != _spans.end(); ++siter) {
525 int const y = span->getY();
526 int const x0 = span->getX0();
527 int const x1 = span->getX1();
528 int const npix = x1 - x0 + 1;
531 xc += npix*0.5*(x1 + x0);
534 assert(static_cast<std::
size_t>(n) == _area);
536 return geom::
Point2D(xc/_area, yc/_area);
539 geom::ellipses::Quadrupole
543 double const xc = cen.getX();
544 double const yc = cen.getY();
546 double sumxx = 0, sumxy = 0, sumyy = 0;
547 for (Footprint::SpanList::const_iterator siter = _spans.begin(); siter != _spans.end(); ++siter) {
549 int const y = span->getY();
550 int const x0 = span->getX0();
551 int const x1 = span->getX1();
552 int const npix = x1 - x0 + 1;
554 for (
int x = x0;
x <= x1; ++
x) {
555 sumxx += (
x - xc)*(
x - xc);
557 sumxy += npix*(0.5*(x1 +
x0) - xc)*(y - yc);
558 sumyy += npix*(y - yc)*(y - yc);
561 return geom::ellipses::Quadrupole(sumxx/_area, sumyy/_area, sumxy/_area);
571 template<
bool overwriteId,
typename PixelT>
574 Footprint::SpanList
const& _spans,
576 std::uint64_t
const id,
579 std::set<std::uint64_t> *oldIds=NULL
596 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
598 "Footprint's host Image of size (%dx%d)") %
603 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
604 str(
boost::format(
"Id 0x%x sets bits in the protected mask 0x%x") %
id % mask));
607 typename std::set<std::uint64_t>::const_iterator pos;
609 pos = oldIds->begin();
611 for (Footprint::SpanList::const_iterator spi = _spans.begin(); spi != _spans.end(); ++spi) {
614 int const sy0 = span->getY() - y0;
615 if (sy0 < 0 || sy0 >= height) {
619 int sx0 = span->getX0() -
x0;
623 int sx1 = span->getX1() -
x0;
624 int const swidth = (sx1 >=
width) ? width - sx0 : sx1 - sx0 + 1;
627 end = ptr + swidth; ptr != end; ++ptr) {
629 long val = *ptr & ~mask;
630 if (val != 0 and oldIds != NULL) {
631 pos = oldIds->insert(pos, val);
633 *ptr = (*ptr & mask) +
id;
642 template<
typename PixelT>
646 int const ix0 = img.
getX0();
647 int const iy0 = img.
getY0();
653 _spans.reserve(old.size());
656 for (SpanList::iterator s = old.begin(); s != old.end(); ++s) {
657 int const y = (*s)->getY();
658 int const x0 = (*s)->getX0();
659 int const x1 = (*s)->getX1();
660 typename ImageT::x_iterator img_it = img.
row_begin(y - iy0) + (x0 - ix0);
663 for (leftx = x0; leftx <= x1; ++leftx, ++img_it) {
664 if (*img_it != zero) {
673 img_it = img.
row_begin(y - iy0) + (x1 - ix0);
674 for (rightx = x1; rightx >= leftx; --rightx, --img_it) {
675 if (*img_it != zero) {
679 addSpanInSeries(y, leftx, rightx);
684 template<
typename PixelT>
686 Footprint::insertIntoImage(
688 std::uint64_t
const id,
692 static_cast<void>(doInsertIntoImage<false>(_region, _spans, idImage,
id, region));
695 template<
typename PixelT>
697 Footprint::insertIntoImage(
699 std::uint64_t
const id,
702 std::set<std::uint64_t> *oldIds,
706 if (
id > std::size_t(std::numeric_limits<PixelT>::max())) {
708 lsst::pex::exceptions::OutOfRangeError,
709 "id out of range for image type"
713 doInsertIntoImage<true>(_region, _spans, idImage,
id, region, mask, oldIds);
715 doInsertIntoImage<false>(_region, _spans, idImage,
id, region, mask, oldIds);
719 void Footprint::include(std::vector<
PTR(
Footprint)>
const & others,
bool ignoreSelf) {
720 if (others.empty())
return;
727 for (std::vector<
PTR(
Footprint)>::const_iterator i = others.begin(); i != others.end(); ++i) {
730 std::uint16_t bits = 0x1;
735 for (std::vector<
PTR(
Footprint)>::const_iterator i = others.begin(); i != others.end(); ++i) {
738 FootprintSet fpSet(mask, Threshold(bits, Threshold::BITMASK));
739 if (fpSet.getFootprints()->empty()) {
741 }
else if (fpSet.getFootprints()->size() == 1u) {
742 _spans.swap(fpSet.getFootprints()->front()->getSpans());
745 for (std::vector<
PTR(
Footprint)>::const_iterator i = fpSet.getFootprints()->begin();
746 i != fpSet.getFootprints()->end(); ++i) {
747 _spans.insert(_spans.end(), (**i).getSpans().begin(), (**i).getSpans().end());
755 class FootprintFactory :
public table::io::PersistableFactory {
758 virtual PTR(table::io::Persistable)
759 read(InputArchive const & archive, CatalogVector const & catalogs)
const {
762 result->readSpans(catalogs.front());
763 result->readPeaks(catalogs.back());
767 explicit FootprintFactory(std::
string const &
name) : table::io::PersistableFactory(
name) {}
774 class FootprintPersistenceHelper {
776 table::Schema spanSchema;
777 table::Key<int> spanY;
778 table::Key<int> spanX0;
779 table::Key<int> spanX1;
781 static FootprintPersistenceHelper
const &
get() {
782 static FootprintPersistenceHelper instance;
787 FootprintPersistenceHelper (
const FootprintPersistenceHelper&) =
delete;
788 FootprintPersistenceHelper& operator=(
const FootprintPersistenceHelper&) =
delete;
791 FootprintPersistenceHelper (FootprintPersistenceHelper&&) =
delete;
792 FootprintPersistenceHelper& operator=(FootprintPersistenceHelper&&) =
delete;
795 FootprintPersistenceHelper() :
797 spanY(spanSchema.addField<int>(
"y",
"row position of span",
"pixel")),
798 spanX0(spanSchema.addField<int>(
"x0",
"first column of span (inclusive)",
"pixel")),
799 spanX1(spanSchema.addField<int>(
"x1",
"first column of span (inclusive)",
"pixel"))
801 spanSchema.getCitizen().markPersistent();
805 std::string getFootprintPersistenceName() {
return "Footprint"; }
809 FootprintFactory registration(getFootprintPersistenceName());
813 std::string Footprint::getPersistenceName()
const {
return getFootprintPersistenceName(); }
815 std::string Footprint::getPythonModule()
const {
return "lsst.afw.detection"; }
817 void Footprint::write(OutputArchiveHandle & handle)
const {
818 FootprintPersistenceHelper
const & keys = FootprintPersistenceHelper::get();
820 spanCat.reserve(_spans.size());
821 for (SpanList::const_iterator i = _spans.begin(); i != _spans.end(); ++i) {
822 PTR(afw::table::BaseRecord) record = spanCat.addNew();
823 record->set(keys.spanY, (**i).getY());
824 record->set(keys.spanX0, (**i).getX0());
825 record->set(keys.spanX1, (**i).getX1());
827 handle.saveCatalog(spanCat);
828 afw::table::
BaseCatalog peakCat = handle.makeCatalog(_peaks.getSchema());
829 peakCat.insert(peakCat.end(), _peaks.begin(), _peaks.end(), true);
830 handle.saveCatalog(peakCat);
834 FootprintPersistenceHelper
const & keys = FootprintPersistenceHelper::get();
836 addSpan(i->get(keys.spanY), i->get(keys.spanX0), i->get(keys.spanX1));
841 if (!peakCat.getSchema().contains(PeakTable::makeMinimalSchema())) {
843 afw::table::SchemaMapper mapper(peakCat.getSchema());
844 mapper.addMinimalSchema(PeakTable::makeMinimalSchema());
845 afw::table::Key<float> oldX = peakCat.getSchema()[
"x"];
846 afw::table::Key<float> oldY = peakCat.getSchema()[
"y"];
847 afw::table::Key<float> oldPeakValue = peakCat.getSchema()[
"value"];
848 mapper.addMapping(oldX,
"f.x");
849 mapper.addMapping(oldY,
"f.y");
850 mapper.addMapping(oldPeakValue,
"peakValue");
852 _peaks.
reserve(peakCat.size());
854 PTR(PeakRecord) newPeak = _peaks.addNew();
855 newPeak->assign(*i, mapper);
856 newPeak->setIx(
int(newPeak->getFx()));
857 newPeak->setIy(
int(newPeak->getFy()));
862 _peaks.reserve(peakCat.size());
863 for (afw::table::
BaseCatalog::const_iterator i = peakCat.begin(); i != peakCat.end(); ++i) {
864 _peaks.addNew()->assign(*i);
872 _region = other._region;
876 _spans.reserve(other._spans.size());
877 for(SpanList::const_iterator i(other._spans.begin());
878 i != other._spans.end(); ++i
883 _normalized = other._normalized;
887 _peaks =
PeakCatalog(other.getPeaks().getTable(), other.getPeaks().begin(), other.getPeaks().end(),
true);
891 template<
typename MaskT>
892 void Footprint::intersectMask(
902 SpanList::iterator s(_spans.begin());
903 while((*s)->getY() < maskBBox.
getMinY() && s != _spans.end()){
909 SpanList maskedSpans;
911 for( ; s != _spans.end(); ++s) {
936 for(
int x = x0;
x <= x1; ++
x, ++mIter) {
937 if((*mIter & bitmask) != 0) {
943 PTR(Span) maskedSpan(new Span(y, x0,
x- 1));
944 maskedSpans.push_back(maskedSpan);
945 maskedArea += maskedSpan->getWidth();
954 PTR(Span) maskedSpan(new Span(y, x0, x1));
955 maskedSpans.push_back(maskedSpan);
956 maskedArea += maskedSpan->getWidth();
960 _spans = maskedSpans;
961 _bbox.clip(maskBBox);
968 geom::Box2I const& region,
986 for (
int y = tBoxI.getBeginY(); y < tBoxI.getEndY(); ++y) {
990 for (
int x = tBoxI.getBeginX(); x < tBoxI.getEndX(); ++
x) {
992 int const xSource =
std::floor(0.5 + p.getX());
993 int const ySource =
std::floor(0.5 + p.getY());
1000 }
else if (inSpan) {
1002 fpNew->addSpan(y, start, x - 1);
1006 fpNew->addSpan(y, start, tBoxI.getMaxX());
1012 PeakCatalog::const_iterator
iter = this->getPeaks().begin();
1013 iter != this->getPeaks().end();
1017 fpNew->addPeak(tp.getX(), tp.getY(),
iter->getPeakValue());
1021 fpNew->clipTo(region);
1029 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
"Footprint isn't normalized");
1031 int const width = getBBox().getWidth(), height = getBBox().getHeight();
1032 if (height <= 2 || _spans.size() <= 2) {
1034 return std::make_shared<Footprint>(*this);
1040 int const xStart = getBBox().getMinX(), yStart = getBBox().getMinY();
1041 std::vector<
bool> rowBefore(width, false);
1042 std::vector<
bool> rowNow(width, false);
1043 std::vector<
bool> rowAfter(width, false);
1046 int const yEnd = _spans.back()->getY();
1049 SpanList::const_iterator readAhead = _spans.begin();
1050 for (; readAhead != _spans.end() && (*readAhead)->getY() == yStart; ++readAhead) {
1051 std::fill(rowNow.begin() + (*readAhead)->getX0() - xStart,
1052 rowNow.begin() + (*readAhead)->getX1() + 1 - xStart,
1055 for (; readAhead != _spans.end() && (*readAhead)->getY() == yStart + 1; ++readAhead) {
1056 std::fill(rowAfter.begin() + (*readAhead)->getX0() - xStart,
1057 rowAfter.begin() + (*readAhead)->getX1() + 1 - xStart,
1061 for (SpanList::const_iterator ss = _spans.begin(); ss != _spans.end(); ++ss) {
1062 int const y = (*ss)->getY();
1063 if (y == yStart || y == yEnd) {
1065 edges->addSpanInSeries(y, (*ss)->getX0(), (*ss)->getX1());
1070 rowBefore.assign(rowNow.begin(), rowNow.end());
1071 rowNow.assign(rowAfter.begin(), rowAfter.end());
1073 std::fill(rowAfter.begin(), rowAfter.end(),
false);
1074 for (; readAhead != _spans.end() && (*readAhead)->getY() <=
y; ++readAhead) {}
1075 for (; readAhead != _spans.end() && (*readAhead)->getY() == y + 1; ++readAhead) {
1076 std::fill(rowAfter.begin() + (*readAhead)->getX0() - xStart,
1077 rowAfter.begin() + (*readAhead)->getX1() + 1 - xStart,
1084 int x0 = (*ss)->getX0();
1086 for (
int x = x0 + 1, i = x0 + 1 - xStart; x < (*ss)->getX1(); ++
x, ++i) {
1088 if (rowBefore[i] && rowAfter[i]) {
1091 edges->addSpanInSeries(y, x0, x - 1);
1093 }
else if (!rowBefore[i] || !rowAfter[i]) {
1100 int const x1 = (*ss)->getX1();
1102 edges->addSpanInSeries(y, x0, x1);
1104 edges->addSpanInSeries(y, x1, x1);
1118 bool _checkNormalized(
Footprint const& foot) {
1121 if (copy.getArea() != foot.getArea()) {
1124 if (copy.getSpans().size() != foot.getSpans().size()) {
1127 Footprint::SpanList
const& spansa = foot.getSpans();
1128 Footprint::SpanList
const& spansb = copy.getSpans();
1129 Footprint::SpanList::const_iterator spa = spansa.begin();
1130 Footprint::SpanList::const_iterator spb = spansb.begin();
1131 for (; spa != spansa.end(); ++spa, ++spb) {
1132 if ((*spa)->getY() != (*spb)->getY()) {
1135 if ((*spa)->getX0() != (*spb)->getX0()) {
1138 if ((*spa)->getX1() != (*spb)->getX1()) {
1147 template<
typename MaskT>
1150 typename lsst::afw::
image::Mask<MaskT>::Ptr const& mask,
1159 template<typename MaskT>
1161 image::Mask<MaskT> *mask,
1166 int const width =
static_cast<int>(mask->getWidth());
1167 int const height =
static_cast<int>(mask->getHeight());
1169 for (Footprint::SpanList::const_iterator siter = foot.getSpans().begin();
1170 siter != foot.getSpans().end(); ++siter) {
1172 int const y = span->getY() - mask->getY0();
1173 if (y < 0 || y >= height) {
1177 int x0 = span->getX0() - mask->getX0();
1178 int x1 = span->getX1() - mask->getX0();
1179 x0 = (x0 < 0) ? 0 : (x0 >= width ? width - 1 :
x0);
1180 x1 = (x1 < 0) ? 0 : (x1 >= width ? width - 1 : x1);
1183 end = mask->x_at(x1 + 1, y); ptr != end; ++ptr) {
1193 template<
typename MaskT>
1199 int const width =
static_cast<int>(mask->
getWidth());
1200 int const height =
static_cast<int>(mask->
getHeight());
1202 for (Footprint::SpanList::const_iterator siter = foot.getSpans().begin();
1203 siter != foot.getSpans().end(); ++siter) {
1205 int const y = span->getY() - mask->getY0();
1206 if (y < 0 || y >= height) {
1210 int x0 = span->getX0() - mask->
getX0();
1211 int x1 = span->getX1() - mask->
getX0();
1212 x0 = (x0 < 0) ? 0 : (x0 >= width ? width - 1 :
x0);
1213 x1 = (x1 < 0) ? 0 : (x1 >= width ? width - 1 : x1);
1216 end = mask->
x_at(x1 + 1, y); ptr != end; ++ptr) {
1226 template<
typename MaskT>
1232 for (std::vector<
PTR(
Footprint)>::const_iterator fiter = footprints.begin();
1233 fiter != footprints.end(); ++fiter) {
1242 template<
typename MaskT>
1253 template<
typename ImageT>
1254 class SetFootprint :
public FootprintFunctor<ImageT> {
1256 SetFootprint(ImageT
const&
image,
1257 typename ImageT::Pixel value) :
1258 FootprintFunctor<ImageT>(image),
_value(value) {}
1261 void operator()(
typename ImageT::xy_locator loc,
int,
int) {
1265 typename ImageT::Pixel
_value;
1269 template<
typename ImageT>
1273 typename ImageT::Pixel
const value
1275 SetFootprint<ImageT> setit(*image, value);
1281 template<
typename ImageT>
1285 typename ImageT::Pixel
const value
1290 template<
typename ImageT>
1294 typename ImageT::Pixel
const value
1296 SetFootprint<ImageT> setit(*image, value);
1297 for (std::vector<
PTR(
Footprint)>::const_iterator fiter = footprints.begin(),
1298 end = footprints.end(); fiter != end; ++fiter) {
1299 setit.apply(**fiter);
1309 template <
typename IDPixelT>
1310 static void set_footprint_id(
1316 for (Footprint::SpanList::const_iterator i = foot.getSpans().begin();
1317 i != foot.getSpans().end(); ++i) {
1319 for (typename image::Image<IDPixelT>::x_iterator ptr =
1320 idImage->x_at(span->getX0() + dx, span->getY() + dy),
1321 end = ptr + span->getWidth(); ptr != end; ++ptr) {
1327 template <
typename IDPixelT>
1329 set_footprint_array_ids(
1332 bool const relativeIDs
1336 for (std::vector<
PTR(
Footprint)>::const_iterator fiter = footprints.begin();
1337 fiter != footprints.end(); ++fiter) {
1346 set_footprint_id<IDPixelT>(idImage, *foot,
id);
1350 template void set_footprint_array_ids<int>(
1352 std::vector<PTR(Footprint)>
const& footprints,
1353 bool const relativeIDs);
1362 template <
typename IDImageT>
1363 typename std::shared_ptr<image::Image<IDImageT> > setFootprintArrayIDs(
1365 bool const relativeIDs
1367 std::vector<PTR(Footprint)>::const_iterator fiter = footprints.begin();
1368 if (fiter == footprints.end()) {
1370 lsst::pex::exceptions::InvalidParameterError,
1371 "You didn't provide any footprints"
1376 typename image::Image<IDImageT>::Ptr idImage(
1377 new image::Image<IDImageT>(foot->getRegion())
1383 set_footprint_array_ids<IDImageT>(idImage, footprints, relativeIDs);
1388 template image::Image<
int>::Ptr setFootprintArrayIDs(
1390 bool const relativeIDs);
1394 template <typename IDImageT>
1395 typename std::shared_ptr<image::Image<IDImageT> > setFootprintID(
1404 set_footprint_id<IDImageT>(idImage, *foot,
id);
1418 class StructuringElement
1422 typedef std::vector<Span>::const_iterator const_iterator;
1423 StructuringElement(
Shape shape,
int radius);
1424 StructuringElement(
int left,
int right,
int up,
int down);
1425 const_iterator begin()
const {
return _widths.begin(); }
1426 const_iterator end()
const {
return _widths.end(); }
1427 int getYRange()
const {
return _yRange; }
1430 std::vector<Span> _widths;
1439 StructuringElement::StructuringElement(
Shape shape,
int radius) {
1440 _yRange = 2*radius + 1;
1441 _widths.reserve(_yRange);
1444 for (
auto dy = -radius; dy <= radius; dy++) {
1445 int dx =
static_cast<int>(sqrt(radius*radius - dy*dy));
1446 _widths.push_back(Span(dy, -dx, dx));
1449 case Shape::DIAMOND:
1450 for (
auto dy = -radius; dy <= radius; dy++) {
1451 int dx = radius - abs(dy);
1452 _widths.push_back(Span(dy, -dx, dx));
1462 StructuringElement::StructuringElement(
int left,
int right,
int up,
int down) {
1463 _yRange = up + down + 1;
1464 _widths.reserve(_yRange);
1465 for (
auto dy = 1; dy <= up; dy++) {
1466 _widths.push_back(Span(dy, 0, 0));
1468 for (
auto dy = -1; dy >= -down; dy--) {
1469 _widths.push_back(Span(dy, 0, 0));
1471 _widths.push_back(Span(0, -left, right));
1480 StructuringElement const& element
1488 std::map<
int, std::set<std::pair<
int,
int>>> spans;
1492 for (auto spanIter = foot.getSpans().cbegin(); spanIter != foot.getSpans().cend(); ++spanIter) {
1493 for (
auto elementIter = element.begin(); elementIter != element.end(); ++elementIter) {
1494 int const xmin = (*spanIter)->getX0() + elementIter->getX0();
1495 int const xmax = (*spanIter)->getX1() + elementIter->getX1();
1496 int const yval = (*spanIter)->getY() + elementIter->getY();
1497 spans[yval].insert(std::make_pair(xmin, xmax));
1501 std::set<std::pair<int, int>> newSpans;
1502 for (
auto span = spans[yval].cbegin(); span != spans[yval].cend(); ++span) {
1503 int const start = span->first;
1504 int end = span->second;
1508 while (span != spans[yval].cend() && span->first <= (end+1)) {
1509 end = std::max(end, span++->second);
1511 newSpans.insert(std::make_pair(start, end));
1520 for (
auto y = spans.cbegin(); y != spans.cend(); ++
y) {
1521 for (
auto x = y->second.cbegin(); x != y->second.cend(); ++
x) {
1522 grown->addSpanInSeries(y->first, x->first, x->second);
1527 grown->getPeaks() =
PeakCatalog(foot.getPeaks().getTable(), foot.getPeaks().begin(),
1528 foot.getPeaks().end(),
true);
1543 int m,
y, xmin, xmax;
1550 bool comparePrimaryRun(PrimaryRun
const& first, PrimaryRun
const& second) {
1551 if (first.y != second.y) {
1552 return first.y < second.y;
1553 }
else if (first.m != second.m) {
1554 return first.m < second.m;
1556 return first.xmin < second.xmin;
1560 class ComparePrimaryRunY{
1562 bool operator()(PrimaryRun
const& pr,
int yval) {
1565 bool operator()(
int yval, PrimaryRun
const& pr) {
1570 class ComparePrimaryRunM{
1572 bool operator()(PrimaryRun
const& pr,
int mval) {
1575 bool operator()(
int mval, PrimaryRun
const& pr) {
1584 PTR(Footprint) shrinkFootprintImpl(
1585 Footprint const& foot,
1586 StructuringElement const& element
1589 PTR(Footprint) shrunk(new Footprint(0, foot.getRegion()));
1592 std::vector<PrimaryRun> primaryRuns;
1593 for (auto spanIter = foot.getSpans().begin(); spanIter != foot.getSpans().end(); ++spanIter) {
1595 for (
auto it = element.begin(); it != element.end(); ++it, ++
m) {
1596 if ((it->getX1() - it->getX0()) <= ((*spanIter)->getX1() - (*spanIter)->getX0())) {
1597 int xmin = (*spanIter)->getX0() - it->getX0();
1598 int xmax = (*spanIter)->getX1() - it->getX1();
1599 int y = (*spanIter)->getY() - it->getY();
1600 primaryRuns.push_back(PrimaryRun({
m,
y, xmin, xmax}));
1607 std::sort(primaryRuns.begin(), primaryRuns.end(), comparePrimaryRun);
1609 for (
int y = primaryRuns.front().y; y <= primaryRuns.back().y; ++
y) {
1610 auto yRange = std::equal_range(primaryRuns.begin(), primaryRuns.end(),
y, ComparePrimaryRunY());
1615 if (std::distance(yRange.first, yRange.second) < element.getYRange()) {
1624 std::list<PrimaryRun> goodRuns;
1626 for (
int m = 0; m < element.getYRange(); ++
m) {
1627 auto mRange = std::equal_range(yRange.first, yRange.second, m, ComparePrimaryRunM());
1628 if (mRange.first == mRange.second) {
1635 std::list<PrimaryRun> candidateRuns;
1636 int start_x = mRange.first->xmin;
1637 int end_x = mRange.first->xmax;
1638 for (
auto run = mRange.first+1;
run != mRange.second; ++
run) {
1639 if (
run->xmin > end_x) {
1641 candidateRuns.push_back(PrimaryRun{
m,
y, start_x, end_x});
1642 start_x =
run->xmin;
1649 candidateRuns.push_back(PrimaryRun{
m,
y, start_x, end_x});
1658 std::list<PrimaryRun> newlist;
1659 for (
auto good = goodRuns.begin(); good != goodRuns.end(); ++good) {
1660 for (
auto cand = candidateRuns.begin(); cand != candidateRuns.end(); ++cand) {
1661 int start = std::max(good->xmin, cand->xmin);
1662 int end = std::min(good->xmax, cand->xmax);
1664 newlist.push_back(PrimaryRun({
m,
y, start, end}));
1672 for (
auto run = goodRuns.begin();
run != goodRuns.end(); ++
run) {
1673 shrunk->addSpan(
run->y,
run->xmin,
run->xmax);
1677 shrunk->normalize();
1682 for (
auto peakIter = foot.getPeaks().begin(); peakIter != foot.getPeaks().end(); peakIter++) {
1683 if (shrunk->contains(peakIter->getI())) {
1684 shrunk->getPeaks().addNew()->assign(*peakIter);
1694 PTR(Footprint) _mergeFootprints(Footprint const& aFoot, Footprint const& bFoot) {
1695 PTR(Footprint) foot(new Footprint());
1700 if (aPeak.empty()) {
1701 if (!bPeak.empty()) {
1702 peaks =
PeakCatalog(bPeak.getTable(), bPeak.begin(), bPeak.end(),
true);
1705 if (bPeak.empty()) {
1706 peaks =
PeakCatalog(aPeak.getTable(), aPeak.begin(), aPeak.end(),
true);
1708 if (aPeak.getSchema() == bPeak.getSchema()) {
1711 peaks.
reserve(aPeak.size() + bPeak.size());
1712 peaks.insert(peaks.end(), aPeak.begin(), aPeak.end(),
true);
1713 peaks.insert(peaks.end(), bPeak.begin(), bPeak.end(),
true);
1716 pex::exceptions::InvalidParameterError,
1717 "Cannot merge Footprints when Peaks have different Schemas"
1723 Footprint::SpanList
const& aSpans = aFoot.getSpans();
1724 Footprint::SpanList
const& bSpans = bFoot.getSpans();
1725 Footprint::SpanList::const_iterator aSpan = aSpans.begin();
1726 Footprint::SpanList::const_iterator bSpan = bSpans.begin();
1727 Footprint::SpanList::const_iterator aEnd = aSpans.end();
1728 Footprint::SpanList::const_iterator bEnd = bSpans.end();
1730 foot->getSpans().reserve(std::max(aSpans.size(), bSpans.size()));
1732 while ((aSpan != aEnd) && (bSpan != bEnd)) {
1733 int y = (*aSpan)->getY();
1734 int x0 = (*aSpan)->getX0();
1735 int x1 = (*aSpan)->getX1();
1736 int yb = (*bSpan)->getY();
1737 int xb0 = (*bSpan)->getX0();
1738 int xb1 = (*bSpan)->getX1();
1740 if ((y < yb) || (y == yb && (x1 < (xb0-1)))) {
1742 foot->addSpanInSeries(y, x0, x1);
1746 if ((yb < y) || (y == yb && (xb1 < (x0-1)))) {
1748 foot->addSpanInSeries(yb, xb0, xb1);
1755 x0 = std::min(x0, xb0);
1756 x1 = std::max(x1, xb1);
1761 if ((aSpan != aEnd) &&
1762 ((*aSpan)->getY() ==
y) &&
1763 ((*aSpan)->getX0() <= (x1+1))) {
1765 x1 = std::max(x1, (*aSpan)->getX1());
1769 if ((bSpan != bEnd) &&
1770 ((*bSpan)->getY() ==
y) &&
1771 ((*bSpan)->getX0() <= (x1+1))) {
1773 x1 = std::max(x1, (*bSpan)->getX1());
1779 foot->addSpanInSeries(y, x0, x1);
1784 for (; aSpan != aEnd; ++aSpan) {
1785 foot->addSpanInSeries((*aSpan)->getY(), (*aSpan)->getX0(), (*aSpan)->getX1());
1788 for (; bSpan != bEnd; ++bSpan) {
1789 foot->addSpanInSeries((*bSpan)->getY(), (*bSpan)->getX0(), (*bSpan)->getX1());
1798 return _mergeFootprints(foot1, foot2);
1802 if (!foot1.isNormalized() || !foot2.isNormalized()) {
1804 lsst::pex::exceptions::InvalidParameterError,
1805 "mergeFootprints(const Footprints) requires normalize()d Footprints.");
1807 return _mergeFootprints(foot1, foot2);
1820 typedef std::uint16_t dtype;
1821 typedef std::uint16_t itype;
1823 const itype nil = 0xffff;
1829 int const x0 = bbox.
getMinX();
1830 int const y0 = bbox.
getMinY();
1832 for (
size_t i=0; i<foots.size(); ++i) {
1834 set_footprint_id<itype>(argmin, *foots[i], i, -
x0, -
y0);
1835 set_footprint_id<dtype>(dist, *foots[i], 1, -
x0, -
y0);
1839 int const width = dist->
getWidth();
1842 for (
int y = 0; y !=
height; ++
y) {
1845 for (
int x = 0; x !=
width; ++
x, ++dim.x(), ++aim.x()) {
1846 if (dim(0, 0) == 1) {
1853 dim(0, 0) = width +
height;
1857 dtype ndist = dim(0,-1) + 1;
1858 if (ndist < dim(0,0)) {
1860 aim(0,0) = aim(0,-1);
1865 dtype ndist = dim(-1,0) + 1;
1866 if (ndist < dim(0,0)) {
1868 aim(0,0) = aim(-1,0);
1875 for (
int y = height - 1; y >= 0; --
y) {
1878 for (
int x = width - 1; x >= 0; --
x, --dim.x(), --aim.x()) {
1881 if (y + 1 < height) {
1882 dtype ndist = dim(0,1) + 1;
1883 if (ndist < dim(0,0)) {
1885 aim(0,0) = aim(0,1);
1889 if (x + 1 < width) {
1890 dtype ndist = dim(1,0) + 1;
1891 if (ndist < dim(0,0)) {
1893 aim(0,0) = aim(1,0);
1901 Footprint const& foot,
1905 if (nGrow <= 0 || foot.getNpix() == 0 ) {
1914 Shape shape = isotropic ? Shape::CIRCLE : Shape::DIAMOND;
1915 return growFootprintImpl(foot, StructuringElement(shape, nGrow));
1930 if (nGrow <= 0 || foot.getNpix() == 0 ) {
1934 return growFootprintImpl(foot, StructuringElement(left ? nGrow: 0, right ? nGrow : 0,
1935 up ? nGrow : 0, down ? nGrow : 0));
1940 Footprint const& foot,
1945 Shape shape = isotropic ? Shape::CIRCLE : Shape::DIAMOND;
1946 return shrinkFootprintImpl(foot, StructuringElement(shape, nShrink));
1952 typedef std::uint16_t ImageT;
1960 foot.insertIntoImage(*idImage, 1, fpBBox);
1962 std::vector<geom::Box2I> bboxes;
1977 while (y0 < height) {
1979 for (
int y = y0; y !=
height; ++
y) {
1986 int const x0 = first - begin;
1987 int const x1 = last - begin;
1989 std::fill(first, last + 1, 0);
1996 if (std::find(idImage->at(x0, y), idImage->at(x1 + 1, y), 0) != idImage->at(x1 + 1, y)) {
1999 std::fill(idImage->at(x0, y), idImage->at(x1 + 1, y), 0);
2005 bboxes.push_back(bbox);
2017 template<
typename ImageOrMaskedImageT>
2020 PTR(ImageOrMaskedImageT)
const input,
2021 PTR(ImageOrMaskedImageT) output) {
2022 Footprint::SpanList spans = foot.getSpans();
2024 int const inX0 = input->getX0(), inY0 = input->getY0();
2025 int const outX0 = output->getX0(), outY0 = output->getY0();
2027 int const xMin = std::max(inX0, outX0);
2028 int const xMax = std::min(input->getWidth() + inX0, output->getWidth() + outX0) - 1;
2029 for (Footprint::SpanList::iterator sp = spans.begin();
2030 sp != spans.end(); ++sp) {
2031 int const y = (*sp)->getY();
2032 int const x0 = (*sp)->getX0();
2033 int const x1 = (*sp)->getX1();
2035 int const yInput = y - inY0, yOutput = y - outY0;
2036 if (yInput < 0 || yInput >= input->getHeight() || yOutput < 0 || yOutput >= output->getHeight()) {
2040 int const xStart = std::max(x0, xMin);
2041 int const xStop = std::min(x1, xMax);
2043 typename ImageOrMaskedImageT::const_x_iterator initer = input->x_at(xStart - inX0, yInput);
2044 typename ImageOrMaskedImageT::x_iterator outiter = output->x_at(xStart - outX0, yOutput);
2045 for (
int x = xStart; x <= xStop; ++
x, ++initer, ++outiter) {
2060 psArray *pmGrowFootprintArray(psArray
const *footprints,
2062 assert (footprints->n == 0 || pmIsFootprint(footprints->data[0]));
2064 if (footprints->n == 0) {
2065 return psArrayAlloc(0);
2071 psImage *idImage = pmSetFootprintArrayIDs(footprints,
true);
2075 psKernel *circle = psKernelAlloc(-r, r, -r, r);
2076 assert (circle->image->numRows == 2*r + 1 && circle->image->numCols == circle->image->numRows);
2077 for (
int i = 0; i <= r; ++i) {
2078 for (
int j = 0; j <= r; ++j) {
2079 if (i*i + j*j <= r*r) {
2080 circle->kernel[i][j] =
2081 circle->kernel[i][-j] =
2082 circle->kernel[-i][j] =
2083 circle->kernel[-i][-j] = 1;
2088 psImage *grownIdImage = psImageConvolveDirect(idImage, circle);
2091 psArray *grown = pmFindFootprints(grownIdImage, 0.5, 1);
2092 assert (grown != NULL);
2094 psFree(grownIdImage);
2099 psArray
const *peaks = pmFootprintArrayToPeaks(footprints);
2100 pmPeaksAssignToFootprints(grown, peaks);
2101 psFree((psArray *)peaks);
2113 psArray *pmMergeFootprintArrays(psArray
const *footprints1,
2114 psArray
const *footprints2,
2115 int const includePeaks) {
2116 assert (footprints1->n == 0 || pmIsFootprint(footprints1->data[0]));
2117 assert (footprints2->n == 0 || pmIsFootprint(footprints2->data[0]));
2119 if (footprints1->n == 0 || footprints2->n == 0) {
2120 psArray
const *old = (footprints1->n == 0) ? footprints2 : footprints1;
2122 psArray *merged = psArrayAllocEmpty(old->n);
2123 for (
int i = 0; i < old->n; ++i) {
2124 psArrayAdd(merged, 1, old->data[i]);
2134 pmFootprint *fp1 = footprints1->data[0];
2135 pmFootprint *fp2 = footprints2->data[0];
2136 if (fp1->region.x0 != fp2->region.x0 ||
2137 fp1->region.x1 != fp2->region.x1 ||
2138 fp1->region.y0 != fp2->region.y0 ||
2139 fp1->region.y1 != fp2->region.y1) {
2140 psError(PS_ERR_BAD_PARAMETER_SIZE,
true,
2141 "The two pmFootprint arrays correspnond to different-sized regions");
2149 psImage *idImage = pmSetFootprintArrayIDs(footprints1,
true);
2150 set_footprint_array_ids(idImage, footprints2,
true);
2152 psArray *merged = pmFindFootprints(idImage, 0.5, 1);
2153 assert (merged != NULL);
2159 if (includePeaks & 0x1) {
2160 psArray
const *peaks = pmFootprintArrayToPeaks(footprints1);
2161 pmPeaksAssignToFootprints(merged, peaks);
2162 psFree((psArray *)peaks);
2165 if (includePeaks & 0x2) {
2166 psArray
const *peaks = pmFootprintArrayToPeaks(footprints2);
2167 pmPeaksAssignToFootprints(merged, peaks);
2168 psFree((psArray *)peaks);
2181 pmPeaksAssignToFootprints(psArray *footprints,
2182 psArray
const *peaks) {
2183 assert (footprints != NULL);
2184 assert (footprints->n == 0 || pmIsFootprint(footprints->data[0]));
2185 assert (peaks != NULL);
2186 assert (peaks->n == 0 || pmIsPeak(peaks->data[0]));
2188 if (footprints->n == 0) {
2190 return psError(PS_ERR_BAD_PARAMETER_SIZE,
true,
"Your list of footprints is empty");
2198 psImage *ids = pmSetFootprintArrayIDs(footprints,
true);
2199 assert (ids != NULL);
2200 assert (ids->type.type == PS_TYPE_S32);
2201 int const y0 = ids->y0;
2202 int const x0 = ids->x0;
2203 int const numRows = ids->numRows;
2204 int const numCols = ids->numCols;
2206 for (
int i = 0; i < peaks->n; ++i) {
2207 pmPeak *peak = peaks->data[i];
2208 int const x = peak->x -
x0;
2209 int const y = peak->y -
y0;
2211 assert (x >= 0 && x < numCols && y >= 0 && y < numRows);
2212 int id = ids->data.S32[
y][x -
x0];
2215 pmFootprint *nfp = pmFootprintAlloc(1, ids);
2216 pmFootprintAddSpan(nfp, y, x, x);
2217 psArrayAdd(footprints, 1, nfp);
2222 assert (
id >= 1 && id <= footprints->n);
2223 pmFootprint *fp = footprints->data[
id - 1];
2224 psArrayAdd(fp->peaks, 5, peak);
2231 for (
int i = 0; i < footprints->n; ++i) {
2232 pmFootprint *fp = footprints->data[i];
2233 fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
2235 for (
int j = 1; j < fp->peaks->n; ++j) {
2236 if (fp->peaks->data[j] == fp->peaks->data[j-1]) {
2237 (void)psArrayRemoveIndex(fp->peaks, j);
2253 psErrorCode pmFootprintCullPeaks(psImage
const *img,
2256 float const nsigma_delta,
2258 float const min_threshold) {
2259 assert (img != NULL);
2260 assert (img->type.type == PS_TYPE_F32);
2261 assert (weight != NULL);
2262 assert (weight->type.type == PS_TYPE_F32);
2263 assert (img->y0 == weight->y0 && img->x0 == weight->x0);
2264 assert (fp != NULL);
2266 if (fp->peaks == NULL || fp->peaks->n == 0) {
2271 subRegion.x0 = fp->bbox.x0;
2272 subRegion.x1 = fp->bbox.x1 + 1;
2273 subRegion.y0 = fp->bbox.y0;
2274 subRegion.y1 = fp->bbox.y1 + 1;
2275 psImage
const *subImg = psImageSubset((psImage *)img, subRegion);
2276 psImage
const *subWt = psImageSubset((psImage *)weight, subRegion);
2277 assert (subImg != NULL && subWt != NULL);
2285 psArray *brightPeaks = psArrayAlloc(0);
2286 psFree(brightPeaks->data);
2287 brightPeaks->data = psMemIncrRefCounter(fp->peaks->data);
2291 for (
int i = 1; i < fp->peaks->n; ++i) {
2292 pmPeak
const *peak = fp->peaks->data[i];
2293 int x = peak->x - subImg->x0;
2294 int y = peak->y - subImg->y0;
2299 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);
2300 float const stdev = std::sqrt(subWt->data.F32[y][x]);
2301 float threshold = subImg->data.F32[
y][
x] - nsigma_delta*
stdev;
2302 if (std::isnan(threshold) || threshold < min_threshold) {
2303 #if 1 // min_threshold is assumed to be below the detection threshold,
2305 (void)psArrayRemoveIndex(fp->peaks, i);
2309 #error n.b. We will be running LOTS of checks at this threshold, so only find the footprint once
2310 threshold = min_threshold;
2313 if (threshold > subImg->data.F32[y][x]) {
2314 threshold = subImg->data.F32[
y][
x] - 10*FLT_EPSILON;
2317 int const peak_id = 1;
2319 pmFootprint *peakFootprint = pmFindFootprintAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x);
2321 psImage *idImg = pmSetFootprintID(peakFootprint, peak_id);
2322 psFree(peakFootprint);
2325 for (j = 0; j < i; ++j) {
2326 pmPeak
const *peak2 = fp->peaks->data[j];
2327 int x2 = peak2->x - subImg->x0;
2328 int y2 = peak2->y - subImg->y0;
2329 int const peak2_id = idImg->data.S32[y2][x2];
2331 if (peak2_id == peak_id) {
2333 (void)psArrayRemoveIndex(fp->peaks, i);
2346 psFree(brightPeaks);
2347 psFree((psImage *)subImg);
2348 psFree((psImage *)subWt);
2357 pmFootprintArrayCullPeaks(psImage
const *img,
2358 psImage
const *weight,
2359 psArray *footprints,
2360 float const nsigma_delta,
2362 float const min_threshold) {
2363 for (
int i = 0; i < footprints->n; ++i) {
2364 pmFootprint *fp = footprints->data[i];
2365 if (pmFootprintCullPeaks(img, weight, fp, nsigma_delta, min_threshold) != PS_ERR_NONE) {
2366 return psError(PS_ERR_UNKNOWN,
false,
"Culling pmFootprint %d", fp->id);
2377 psArray *pmFootprintArrayToPeaks(psArray
const *footprints) {
2378 assert(footprints != NULL);
2379 assert(footprints->n == 0 || pmIsFootprint(footprints->data[0]));
2382 for (
int i = 0; i < footprints->n; ++i) {
2383 pmFootprint
const *fp = footprints->data[i];
2384 npeak += fp->peaks->n;
2387 psArray *peaks = psArrayAllocEmpty(npeak);
2389 for (
int i = 0; i < footprints->n; ++i) {
2390 pmFootprint
const *fp = footprints->data[i];
2391 for (
int j = 0; j < fp->peaks->n; ++j) {
2392 psArrayAdd(peaks, 1, fp->peaks->data[j]);
2407 void Footprint::intersectMask(
2413 PTR(Footprint) const& foot,
2414 image::Mask<image::
MaskPixel>::Ptr const& mask,
2420 CONST_PTR(std::vector<
PTR(Footprint)>) const& footprints,
2425 std::vector<
PTR(Footprint)> const& footprints,
2429 Footprint const& foot, image::
MaskPixel const bitmask);
2432 Footprint const& foot, image::
MaskPixel const bitmask);
2434 #define INSTANTIATE_NUMERIC(TYPE) \
2436 TYPE setImageFromFootprint(image::Image<TYPE> *image, \
2437 Footprint const& footprint, \
2438 TYPE const value); \
2440 TYPE setImageFromFootprintList(image::Image<TYPE> *image, \
2441 std::vector<PTR(Footprint)> const& footprints, \
2442 TYPE const value); \
2444 TYPE setImageFromFootprintList(image::Image<TYPE> *image, \
2445 CONST_PTR(std::vector<PTR(Footprint)>) footprints, \
2446 TYPE const value); \
2448 void copyWithinFootprint(Footprint const&, \
2449 PTR(lsst::afw::image::Image<TYPE>) const, \
2450 PTR(lsst::afw::image::Image<TYPE>)); \
2452 void copyWithinFootprint(Footprint const&, \
2453 PTR(lsst::afw::image::MaskedImage<TYPE>) const, \
2454 PTR(lsst::afw::image::MaskedImage<TYPE>)); \
2456 void Footprint::clipToNonzero(lsst::afw::image::Image<TYPE> const&); \
2459 INSTANTIATE_NUMERIC(
float);
2460 INSTANTIATE_NUMERIC(
double);
2462 INSTANTIATE_NUMERIC(std::uint16_t);
2463 INSTANTIATE_NUMERIC(
int);
2464 INSTANTIATE_NUMERIC(std::uint64_t);
2467 #define INSTANTIATE_MASK(PIXEL) \
2469 void Footprint::insertIntoImage( \
2470 lsst::afw::image::Image<PIXEL>& idImage, \
2471 std::uint64_t const id, \
2472 geom::Box2I const& region=geom::Box2I() \
2475 void Footprint::insertIntoImage( \
2476 lsst::afw::image::Image<PIXEL>& idImage, \
2477 std::uint64_t const id, \
2478 bool const overwriteId, long const idMask, \
2479 std::set<std::uint64_t> *oldIds, \
2480 geom::Box2I const& region=geom::Box2I() \
2483 PIXEL Footprint::overlapsMask(image::Mask<PIXEL> const& mask) const
2485 INSTANTIATE_MASK(std::uint16_t);
2486 INSTANTIATE_MASK(
int);
2487 INSTANTIATE_MASK(std::uint64_t);
Declare the Kernel class and subclasses.
A coordinate class intended to represent absolute positions.
table::Key< std::string > name
for(FootprintList::const_iterator ptr=feet->begin(), end=feet->end();ptr!=end;++ptr)
void include(Point2I const &point)
Expand this to ensure that this->contains(point).
tbl::Key< double > weight
x_iterator x_at(int x, int y) const
Return an x_iterator to the point (x, y) in the image.
CatalogT< BaseRecord > BaseCatalog
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Include files required for standard LSST Exception handling.
void include(Point2D const &point)
Expand this to ensure that this->contains(point).
geom::Point2D skyToPixel(geom::Angle sky1, geom::Angle sky2) const
Convert from sky coordinates (e.g.
boost::shared_ptr< Footprint > footprintAndMask(boost::shared_ptr< Footprint > const &foot, typename image::Mask< MaskT >::Ptr const &mask, MaskT const bitmask)
Return a Footprint that's the intersection of a Footprint with a Mask.
Extent2I const getDimensions() const
lsst::afw::detection::Footprint Footprint
geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Implementation of the WCS standard for a any projection.
void swap(Mask< PixelT > &a, Mask< PixelT > &b)
boost::shared_ptr< coord::Coord > pixelToSky(double pix1, double pix2) const
Convert from pixel position to sky coordinates (e.g.
int getX0() const
Return the image's column-origin.
A coordinate class intended to represent absolute positions.
An integer coordinate rectangle.
table::Key< table::Array< Kernel::Pixel > > image
boost::shared_ptr< Footprint > shrinkFootprint(Footprint const &foot, int nGrow, bool isotropic)
Shrink a footprint isotropically by nGrow pixels, returning a new Footprint.
afw::geom::ellipses::Quadrupole Shape
metadata import lsst afw display as afwDisplay n
boost::shared_ptr< Footprint > growFootprint(Footprint const &foot, int nGrow, bool isotropic=true)
Grow a Footprint by nGrow pixels, returning a new Footprint.
CatalogIterator< typename Internal::const_iterator > const_iterator
void ImageT ImageT int float saturatedPixelValue int const width
afw::table::CatalogT< PeakRecord > PeakCatalog
bool contains(Point2I const &point) const
Return true if the box contains the point.
geom::Box2I const & _bbox
void shift(Extent2I const &offset)
Shift the position of the box by the given offset.
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
int getHeight() const
Return the number of rows in the image.
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
void ImageT ImageT int float saturatedPixelValue int const height
MaskT clearMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
(AND ~bitmask) all the Mask's pixels that are in the Footprint; that is, set to zero in the Mask-inte...
ImageT::Pixel setImageFromFootprint(ImageT *image, Footprint const &footprint, typename ImageT::Pixel const value)
Set all image pixels in a Footprint to a given value.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
std::vector< lsst::afw::geom::Box2I > footprintToBBoxList(Footprint const &foot)
Return a list of BBoxs, whose union contains exactly the pixels in foot, neither more nor less...
Extent< int, N > floor(Extent< double, N > const &input)
Return the component-wise floor (round towards more negative).
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask's pixels that are in the Footprint.
def run
Exit with the status code resulting from running the provided test suite.
afw::table::Key< double > b
Point< double, 2 > Point2D
xy_locator xy_at(int x, int y) const
Return an xy_locator at the point (x, y) in the image.
bool isEmpty() const
Return true if the box contains no points.
x_iterator row_begin(int y) const
Return an x_iterator to the start of the y'th row.
void reserve(size_type n)
Increase the capacity of the catalog to the given size.
A floating-point coordinate rectangle geometry.
#define CONST_PTR(...)
A shared pointer to a const object.
boost::shared_ptr< Footprint > mergeFootprints(Footprint const &foot1, Footprint const &foot2)
Merges two Footprints – appends their peaks, and unions their spans, returning a new Footprint...
Record class that represents a peak in a Footprint.
void nearestFootprint(std::vector< boost::shared_ptr< Footprint >> const &foots, lsst::afw::image::Image< std::uint16_t >::Ptr argmin, lsst::afw::image::Image< std::uint16_t >::Ptr dist)
Given a vector of Footprints, fills the output "argmin" and "dist" images to contain the Manhattan di...
int getWidth() const
Return the number of columns in the image.
A class to represent a 2-dimensional array of pixels.
Extent< int, 2 > Extent2I
Utility functions for kernels.
void copyWithinFootprint(Footprint const &foot, boost::shared_ptr< ImageOrMaskedImageT > const input, boost::shared_ptr< ImageOrMaskedImageT > output)
Copies pixels from input image to output image within the Footprint's area.
ImageT::Pixel setImageFromFootprintList(ImageT *image, boost::shared_ptr< std::vector< boost::shared_ptr< Footprint >> const > footprints, typename ImageT::Pixel const value)
Set all image pixels in a set of Footprints to a given value.
MaskT setMaskFromFootprintList(lsst::afw::image::Mask< MaskT > *mask, std::vector< boost::shared_ptr< Footprint >> const &footprints, MaskT const bitmask)
OR bitmask into all the Mask's pixels which are in the set of Footprints.
int getY0() const
Return the image's row-origin.