33 #include "lsst/afw/table/io/Persistable.cc" 52 bool comparePrimaryRun(PrimaryRun
const&
first, PrimaryRun
const&
second) {
53 if (first.y != second.y) {
54 return first.y < second.y;
55 }
else if (first.m != second.m) {
56 return first.m < second.m;
58 return first.xmin < second.xmin;
62 class ComparePrimaryRunY {
64 bool operator()(PrimaryRun
const& pr,
int yval) {
return pr.y < yval; }
65 bool operator()(
int yval, PrimaryRun
const& pr) {
return yval < pr.y; }
68 class ComparePrimaryRunM {
70 bool operator()(PrimaryRun
const& pr,
int mval) {
return pr.m < mval; }
71 bool operator()(
int mval, PrimaryRun
const& pr) {
return mval < pr.m; }
80 bool spansOverlap(Span
const&
a, Span
const&
b,
bool compareY =
true) {
83 yTruth = a.getY() == b.getY();
85 return (yTruth && ((a.getMaxX() >= b.getMinX() && a.getMinX() <= b.getMinX()) ||
86 (b.getMaxX() >= a.getMinX() && b.getMinX() <= a.getMinX())))
98 bool spansContiguous(Span
const& a, Span
const& b,
bool compareY =
true) {
101 yTruth = a.getY() == b.getY();
103 return (yTruth && ((a.getMaxX() + 1 >= b.getMinX() && a.getMinX() <= b.getMinX()) ||
104 (b.getMaxX() + 1 >= a.getMinX() && b.getMinX() <= a.getMinX())))
120 template <
typename T,
bool invert>
124 auto maskBBox = mask.
getBBox();
125 for (
auto const& spn : spanSet) {
128 bool started =
false;
131 if (y < maskBBox.getMinY() || y > maskBBox.getMaxY()) {
138 int startX =
std::max(spn.getMinX(), maskBBox.getMinX());
139 int endX =
std::min(spn.getMaxX(), maskBBox.getMaxX());
140 for (
int x = startX;
x <= endX; ++
x) {
142 bool pixelCompare = mask.
get0(
x, y) & bitmask;
146 pixelCompare = !pixelCompare;
163 }
else if (started) {
171 return std::make_shared<SpanSet>(
std::move(newVec));
178 SpanSet::SpanSet() : _spanVector(), _bbox(), _area(0) {}
187 for (
int i = beginY; i < _bbox.
getEndY(); ++i) {
188 _spanVector.push_back(
Span(i, beginX, maxX));
195 if (_spanVector.empty()) {
209 if (_spanVector.size() == 0) {
220 void SpanSet::_runNormalize() {
226 std::sort(_spanVector.begin(), _spanVector.end());
231 newSpans.
reserve(_spanVector.size());
233 newSpans.push_back(*_spanVector.begin());
239 for (
auto iter = ++(_spanVector.begin()); iter != _spanVector.end(); ++iter) {
240 auto& newSpansEnd = newSpans.back();
241 if (spansContiguous(newSpansEnd, *iter)) {
242 newSpansEnd =
Span(newSpansEnd.getY(),
std::min(newSpansEnd.getMinX(), iter->getMinX()),
243 std::max(newSpansEnd.getMaxX(), iter->getMaxX()));
245 newSpans.push_back(
Span(*iter));
253 void SpanSet::_initialize() {
265 int minX = _spanVector[0].getMinX();
266 int maxX = _spanVector[0].getMaxX();
269 for (
const auto&
span : _spanVector) {
270 if (
span.getMinX() < minX) {
271 minX =
span.getMinX();
273 if (
span.getMaxX() > maxX) {
274 maxX =
span.getMaxX();
277 _area +=
span.getMaxX() -
span.getMinX() + 1;
322 void SpanSet::_label(
325 auto currentIndex = spn.
getY();
326 if (currentIndex > 0) {
328 for (
auto const& tup : sortMap[currentIndex - 1]) {
329 if (!labelVector[tup.first] && spansOverlap(spn, *(tup.second),
false)) {
330 labelVector[tup.first] = currentLabel;
331 _label(*(tup.second), labelVector, currentLabel, sortMap);
335 if (currentIndex <= _spanVector.back().getY() - 1) {
337 for (
auto& tup : sortMap[currentIndex + 1]) {
338 if (!labelVector[tup.first] && spansOverlap(spn, *(tup.second),
false)) {
339 labelVector[tup.first] = currentLabel;
340 _label(*(tup.second), labelVector, currentLabel, sortMap);
353 for (
auto const& spn : _spanVector) {
357 for (
auto const& currentSpan : _spanVector) {
358 if (!labelVector[index]) {
359 labelVector[index] = currentLabel;
360 _label(currentSpan, labelVector, currentLabel, sortMap);
375 auto labeledPair = _makeLabels();
380 return labeledPair.second <= 2;
384 auto labeledPair = _makeLabels();
385 auto labels = labeledPair.first;
386 auto numberOfLabels = labeledPair.second;
394 if (numberOfLabels == 1) {
395 subRegions.
push_back(std::make_shared<SpanSet>());
398 subRegions.
reserve(numberOfLabels - 1);
402 for (
std::size_t i = 0; i < _spanVector.size(); ++i) {
403 subSpanLists[labels[i] - 1].
push_back(_spanVector[i]);
406 for (
std::size_t i = 0; i < numberOfLabels - 1; ++i) {
407 subRegions.
push_back(std::make_shared<SpanSet>(subSpanLists[i]));
414 setMask(tempMask, static_cast<image::MaskPixel>(1));
416 erodedSpanSet->clearMask(tempMask, static_cast<image::MaskPixel>(1));
422 return makeShift(x, y);
427 return makeShift(offset.getX(), offset.getY());
433 tempVec.
reserve(_spanVector.size());
434 for (
auto const& spn : _spanVector) {
437 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
445 for (
auto const& spn : _spanVector) {
452 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
457 for (
auto const& otherSpan : other) {
458 for (
auto const& spn : _spanVector) {
459 if (spansOverlap(otherSpan, spn)) {
473 for (
auto const& otherSpn : other) {
475 for (
auto const& spn : _spanVector) {
495 for (
auto& spn : _spanVector) {
506 double xc = 0, yc = 0;
507 for (
auto const& spn : _spanVector) {
508 int const y = spn.
getY();
511 int const npix = x1 - x0 + 1;
514 xc += npix * 0.5 * (x1 + x0);
525 double const xc = cen.getX();
526 double const yc = cen.getY();
528 double sumxx = 0, sumxy = 0, sumyy = 0;
529 for (
auto const& spn : _spanVector) {
530 int const y = spn.
getY();
531 int const x0 = spn.
getX0();
532 int const x1 = spn.
getX1();
533 int const npix = x1 - x0 + 1;
535 for (
int x = x0; x <= x1; ++
x) {
536 sumxx += (x - xc) * (x - xc);
538 sumxy += npix * (0.5 * (x1 + x0) - xc) * (y - yc);
539 sumyy += npix * (y - yc) * (y - yc);
549 return dilated(*stencilToSpanSet);
554 if (other.
size() == 0) {
555 return std::make_shared<SpanSet>(_spanVector.begin(), _spanVector.end(),
false);
561 for (
auto const& spn : _spanVector) {
562 for (
auto const& otherSpn : other) {
563 int const xmin = spn.
getMinX() + otherSpn.getMinX();
564 int const xmax = spn.
getMaxX() + otherSpn.getMaxX();
565 int const yval = spn.
getY() + otherSpn.getY();
566 tempVec.push_back(
Span(yval, xmin, xmax));
570 return std::make_shared<SpanSet>(
std::move(tempVec));
577 return eroded(*stencilToSpanSet);
582 if (other.
size() == 0 || this->
size() == 0) {
583 return std::make_shared<SpanSet>(_spanVector.begin(), _spanVector.end(),
false);
591 for (
auto const& spn : _spanVector) {
593 for (
auto const& otherSpn : other) {
594 if ((otherSpn.getMaxX() - otherSpn.getMinX()) <= (spn.
getMaxX() - spn.
getMinX())) {
597 int y = spn.
getY() - otherSpn.getY();
608 for (
int y = primaryRuns.
front().y; y <= primaryRuns.
back().y; ++
y) {
616 auto otherYRange = other.
back().getY() - other.
front().getY() + 1;
617 if (
std::distance(yRange.first, yRange.second) < otherYRange) {
628 for (
int m = 0;
m < otherYRange; ++
m) {
629 auto mRange =
std::equal_range(yRange.first, yRange.second,
m, ComparePrimaryRunM());
630 if ((mRange.first == mRange.second)) {
637 int startX = mRange.first->xmin;
638 int endX = mRange.first->xmax;
639 for (
auto run = mRange.first + 1;
run != mRange.second; ++
run) {
640 if (
run->xmin > endX) {
642 candidateRuns.
push_back(PrimaryRun{
m,
y, startX, endX});
650 candidateRuns.
push_back(PrimaryRun{
m,
y, startX, endX});
659 for (
auto& good : goodRuns) {
660 for (
auto& cand : candidateRuns) {
661 int start =
std::max(good.xmin, cand.xmin);
672 for (
auto&
run : goodRuns) {
676 return std::make_shared<SpanSet>(
std::move(tempVec));
681 return _spanVector == other._spanVector;
686 return _spanVector != other._spanVector;
695 for (
auto dy = -r; dy <= r; ++dy) {
696 int dx =
static_cast<int>(sqrt(r * r - dy * dy));
697 tempVec.
push_back(
Span(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX()));
701 for (
auto dy = -r; dy <= r; ++dy) {
702 int dx = r -
abs(dy);
703 tempVec.
push_back(
Span(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX()));
707 for (
auto dy = -r; dy <= r; ++dy) {
709 tempVec.
push_back(
Span(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX()));
713 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
718 return std::make_shared<SpanSet>(pr.
begin(), pr.
end());
724 return std::make_shared<SpanSet>();
727 if (other == *
this) {
728 return std::make_shared<SpanSet>(this->_spanVector);
731 auto otherIter = other.
begin();
732 for (
auto const& spn : _spanVector) {
733 while (otherIter != other.
end() && otherIter->getY() <= spn.
getY()) {
734 if (spansOverlap(spn, *otherIter)) {
737 auto newSpan =
Span(spn.
getY(), newMin, newMax);
738 tempVec.push_back(newSpan);
743 return std::make_shared<SpanSet>(
std::move(tempVec));
749 return std::make_shared<SpanSet>(this->
begin(), this->
end());
752 if (other == *
this) {
753 return std::make_shared<SpanSet>();
762 auto otherIter = other.
begin();
763 for (
auto const& spn : _spanVector) {
765 bool spanStarted =
false;
767 while (otherIter != other.
end() && otherIter->getY() <= spn.
getY()) {
768 if (spansOverlap(spn, *otherIter)) {
784 if (spn.
getMinX() < otherIter->getMinX()) {
785 tempVec.push_back(
Span(spn.
getY(), spn.
getMinX(), otherIter->getMinX() - 1));
791 if (spn.
getMaxX() > otherIter->getMaxX()) {
793 spanBottom = otherIter->getMaxX() + 1;
802 if (spn.
getMaxX() > otherIter->getMaxX()) {
804 spanBottom = otherIter->getMaxX() + 1;
808 if (otherIter->getMaxX() > spn.
getMaxX()) {
822 tempVec.push_back(
Span(spn));
825 return std::make_shared<SpanSet>(
std::move(tempVec));
836 tempVec.
insert(tempVec.
end(), _spanVector.begin(), _spanVector.end());
839 return std::make_shared<SpanSet>(
std::move(tempVec));
862 for (
auto const& tc : toPoints) {
877 newBoxPoints.
clear();
882 auto oldBoxPointIter = oldBoxPoints.cbegin();
883 for (
int x = newBBoxI.
getBeginX(); x < newBBoxI.
getEndX(); ++
x, ++oldBoxPointIter) {
884 auto p = *oldBoxPointIter;
885 int const xSource =
std::floor(0.5 + p.getX());
886 int const ySource =
std::floor(0.5 + p.getY());
902 return std::make_shared<SpanSet>(
std::move(tempVec));
905 template <
typename ImageT>
914 auto setterFunc = [](
lsst::geom::Point2I const& point, ImageT& out, ImageT in) { out = in; };
918 tmpSpan->applyFunctor(setterFunc, image, val);
924 "Footprint Bounds Outside image, set doClip to true");
928 template <
typename T>
931 auto targetArray = target.
getArray();
935 T bitmask) { maskVal |= bitmask; };
939 template <
typename T>
942 auto targetArray = target.
getArray();
946 T bitmask) { maskVal &= ~bitmask; };
950 template <
typename T>
952 return maskIntersect<T, false>(*
this,
other, bitmask);
955 template <
typename T>
957 return maskIntersect<T, true>(*
this,
other, bitmask);
960 template <
typename T>
962 auto comparator = [bitmask](T pixelValue) {
return (pixelValue & bitmask); };
963 auto spanSetFromMask =
fromMask(other, comparator);
964 return union_(*spanSetFromMask);
969 class SpanSetPersistenceHelper {
976 static SpanSetPersistenceHelper
const&
get() {
977 static SpanSetPersistenceHelper instance;
982 SpanSetPersistenceHelper(
const SpanSetPersistenceHelper&) =
delete;
983 SpanSetPersistenceHelper&
operator=(
const SpanSetPersistenceHelper&) =
delete;
986 SpanSetPersistenceHelper(SpanSetPersistenceHelper&&) =
delete;
987 SpanSetPersistenceHelper&
operator=(SpanSetPersistenceHelper&&) =
delete;
990 SpanSetPersistenceHelper()
992 spanY(spanSetSchema.addField<
int>(
"y",
"The row of the span",
"pixel")),
993 spanX0(spanSetSchema.addField<
int>(
"x0",
"First column of span (inclusive)",
"pixel")),
994 spanX1(spanSetSchema.addField<
int>(
"x1",
"Second column of span (inclusive)",
"pixel")) {
995 spanSetSchema.getCitizen().markPersistent();
999 std::string getSpanSetPersistenceName() {
return "SpanSet"; }
1001 class SpanSetFactory :
public table::io::PersistableFactory {
1004 CatalogVector
const& catalogs)
const override {
1008 auto spansCatalog = catalogs.front();
1010 auto const&
keys = SpanSetPersistenceHelper::get();
1013 tempVec.
reserve(spansCatalog.size());
1014 for (
auto const&
val : spansCatalog) {
1017 return std::make_shared<SpanSet>(
std::move(tempVec));
1019 explicit SpanSetFactory(
std::string const&
name) : table::io::PersistableFactory(name) {}
1024 SpanSetFactory registration(getSpanSetPersistenceName());
1028 std::string SpanSet::getPersistenceName()
const {
return getSpanSetPersistenceName(); }
1031 auto const&
keys = SpanSetPersistenceHelper::get();
1032 auto spanCat = handle.makeCatalog(
keys.spanSetSchema);
1033 spanCat.reserve(
size());
1034 for (
auto const&
val : *
this) {
1035 auto record = spanCat.addNew();
1036 record->set(
keys.spanY,
val.getY());
1037 record->set(
keys.spanX0,
val.getX0());
1038 record->set(
keys.spanX1,
val.getX1());
1040 handle.saveCatalog(spanCat);
1045 #define INSTANTIATE_IMAGE_TYPE(T) \ 1046 template void SpanSet::setImage<T>(image::Image<T> & image, T val, \ 1047 lsst::geom::Box2I const& region = lsst::geom::Box2I(), \ 1048 bool doClip = false) const; 1050 #define INSTANTIATE_MASK_TYPE(T) \ 1051 template void SpanSet::setMask<T>(image::Mask<T> & target, T bitmask) const; \ 1052 template void SpanSet::clearMask<T>(image::Mask<T> & target, T bitmask) const; \ 1053 template std::shared_ptr<SpanSet> SpanSet::intersect<T>(image::Mask<T> const& other, T bitmask) const; \ 1054 template std::shared_ptr<SpanSet> SpanSet::intersectNot<T>(image::Mask<T> const& other, T bitmask) \ 1056 template std::shared_ptr<SpanSet> SpanSet::union_<T>(image::Mask<T> const& other, T bitmask) const; An ellipse core with quadrupole moments as parameters.
std::shared_ptr< SpanSet > union_(SpanSet const &other) const
Create a new SpanSet that contains all points from two SpanSets.
std::shared_ptr< geom::SpanSet > findEdgePixels() const
Select pixels within the SpanSet which touch its edge.
Angle abs(Angle const &a)
std::vector< std::shared_ptr< geom::SpanSet > > split() const
Split a discontinuous SpanSet into multiple SpanSets which are contiguous.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
bool operator!=(SpanSet const &other) const
Stencil
An enumeration class which describes the shapes.
std::shared_ptr< SpanSet > intersect(SpanSet const &other) const
Determine the common points between two SpanSets, and create a new SpanSet.
bool contains(SpanSet const &other) const
Check if a SpanSet instance entirely contains another SpanSet.
A floating-point coordinate rectangle geometry.
const_iterator end() const
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, UnaryPredicate comparator=details::AnyBitSetFunctor< T >())
Create a SpanSet from a mask.
A compact representation of a collection of pixels.
A range of pixels within one row of an Image.
void include(Point2D const &point) noexcept
Expand this to ensure that this->contains(point).
void applyFunctor(Functor &&func, Args &&... args) const
Apply functor on individual elements from the supplied parameters.
std::shared_ptr< SpanSet > shiftedBy(int x, int y) const
Return a new SpanSet shifted by specified amount.
bool isEmpty() const noexcept
Return true if the box contains no points.
std::shared_ptr< SpanSet > dilated(int r, Stencil s=Stencil::CIRCLE) const
Perform a set dilation operation, and return a new object.
#define INSTANTIATE_IMAGE_TYPE(T)
typename ndarray::Array< T, N, C >::Reference::Reference Reference
table::Schema spanSetSchema
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
const_iterator begin() const
std::shared_ptr< SpanSet > intersectNot(SpanSet const &other) const
Determine the common points between a SpanSet and the logical inverse of a second SpanSet and return ...
int getMaxX() const noexcept
Maximum x-value.
Relationship invert(Relationship r)
Given the relationship between two sets A and B (i.e.
bool isContiguous() const
Defines if the SpanSet is simply contiguous.
std::vector< Point2I > getCorners() const
Get the corner points.
ellipses::Quadrupole computeShape() const
Compute the shape parameters for the distribution of points in the SpanSet.
int getEndY() const noexcept
void setImage(image::Image< ImageT > &image, ImageT val, lsst::geom::Box2I const ®ion=lsst::geom::Box2I(), bool doClip=false) const
Set the values of an Image at points defined by the SpanSet.
lsst::geom::Point2D computeCentroid() const
Compute the point about which the SpanSet's first moment is zero.
bool contains(int x) const noexcept
Point< double, 2 > Point2D
int getBeginY() const noexcept
lsst::geom::Box2I getBBox() const
Return a new integer box which is the minimum size to contain the pixels.
Point2I const getMin() const noexcept
A base class for image defects.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Represent a 2-dimensional array of bitmask pixels.
int getMaxY() const noexcept
int getBeginX() const noexcept
int getWidth() const noexcept
const_reference front() const
Key< Flag > const & target
int getMaxX() const noexcept
int getMinX() const noexcept
Minimum x-value.
int getMinX() const noexcept
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Reports attempts to access elements outside a valid range of indices.
SpanSet()
Default constructor.
size_type getArea() const
Return the number of pixels in the SpanSet.
int getEndX() const noexcept
void setMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Set a Mask at pixels defined by the SpanSet.
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
bool overlaps(Box2I const &other) const noexcept
Return true if any points in other are also in this.
#define INSTANTIATE_MASK_TYPE(T)
const_reference back() const
io::OutputArchiveHandle OutputArchiveHandle
std::shared_ptr< SpanSet > clippedTo(lsst::geom::Box2I const &box) const
Return a new SpanSet which has all pixel values inside specified box.
std::shared_ptr< SpanSet > transformedBy(lsst::geom::LinearTransform const &t) const
Return a new SpanSet who's pixels are the product of applying the specified transformation.
void clearMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Unset a Mask at pixels defined by the SpanSet.
SpanSet & operator=(SpanSet const &)=default
int getX1() const noexcept
Return the ending x-value.
ItemVariant const * other
bool overlaps(SpanSet const &other) const
Specifies if this SpanSet overlaps with another SpanSet.
int getY() const noexcept
Return the y-value.
details::ImageNdGetter< T, inA, inB > ndImage(ndarray::Array< T, inA, inB > const &array, lsst::geom::Point2I xy0=lsst::geom::Point2I())
Marks a ndarray to be interpreted as an image when applying a functor from a SpanSet.
bool operator==(SpanSet const &other) const
Compute equality between two SpanSets.
An integer coordinate rectangle.
PixelConstReference get0(int x, int y) const
A class to represent a 2-dimensional array of pixels.
std::shared_ptr< SpanSet > eroded(int r, Stencil s=Stencil::CIRCLE) const
Perform a set erosion, and return a new object.
int getMinY() const noexcept
int getX0() const noexcept
Return the starting x-value.
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
T emplace_back(T... args)