49 #include "boost/format.hpp" 
   67 struct Threshold_traits {};
 
   68 struct ThresholdLevel_traits : 
public Threshold_traits {  
 
   70 struct ThresholdPixelLevel_traits : 
public Threshold_traits {  
 
   72 struct ThresholdBitmask_traits : 
public Threshold_traits {  
 
   75 template <
typename PixelT>
 
   78     explicit setIdImage(
std::uint64_t const id, 
bool overwriteId = 
false, 
long const idMask = 0x0)
 
   81               _withSetReplace(false),
 
   82               _overwriteId(overwriteId),
 
   87                     pex::exceptions::InvalidParameterError,
 
   88                     str(
boost::format(
"Id 0x%x sets bits in the protected mask 0x%x") % _id % _idMask));
 
   93                long const idMask = 0x0)
 
   96               _withSetReplace(true),
 
   97               _overwriteId(overwriteId),
 
   99               _pos(oldIds->
begin()) {
 
  102                     pex::exceptions::InvalidParameterError,
 
  103                     str(
boost::format(
"Id 0x%x sets bits in the protected mask 0x%x") % _id % _idMask));
 
  109             auto val = input & ~_idMask;
 
  111             if (
val != 0 && _withSetReplace) {
 
  112                 _pos = _oldIds->insert(_pos, 
val);
 
  115             input = (input & _idMask) + _id;
 
  124     bool _withSetReplace;
 
  134 template <
typename T>
 
  135 inline bool isBadPixel(T) {
 
  140 inline bool isBadPixel(
float val) {
 
  145 inline bool isBadPixel(
double val) {
 
  152 int nbit(
unsigned long i) {
 
  166 template <
typename T>
 
  167 class FindIdsInFootprint {
 
  169     explicit FindIdsInFootprint() : _ids(), _old(0) {}
 
  197         if (
a->getPeakValue() != 
b->getPeakValue()) {
 
  198             return (
a->getPeakValue() > 
b->getPeakValue());
 
  201         if (
a->getIx() != 
b->getIx()) {
 
  202             return (
a->getIx() < 
b->getIx());
 
  205         return (
a->getIy() < 
b->getIy());
 
  211 FootprintSet mergeFootprintSets(FootprintSet 
const &lhs,      
 
  213                                 FootprintSet 
const &rhs,      
 
  215                                 FootprintControl 
const &ctrl  
 
  219     bool const circular = ctrl.isCircular().first && ctrl.isCircular().second;
 
  220     bool const isotropic = ctrl.isIsotropic().second;  
 
  222     bool const left = ctrl.isLeft().first && ctrl.isLeft().second;
 
  223     bool const right = ctrl.isRight().first && ctrl.isRight().second;
 
  224     bool const up = ctrl.isUp().first && ctrl.isUp().second;
 
  225     bool const down = ctrl.isDown().first && ctrl.isDown().second;
 
  228     if (region != rhs.getRegion()) {
 
  229         throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
 
  230                           boost::format(
"The two FootprintSets must have the same region").str());
 
  233     auto idImage = std::make_shared<image::Image<IdPixelT>>(region);
 
  237     FootprintList 
const &lhsFootprints = *lhs.getFootprints();
 
  238     FootprintList 
const &rhsFootprints = *rhs.getFootprints();
 
  239     int const nLhs = lhsFootprints.size();
 
  240     int const nRhs = rhsFootprints.size();
 
  245     int const lhsIdNbit = nbit(nLhs);
 
  246     int const lhsIdMask = (lhsIdNbit == 0) ? 0x0 : (1 << lhsIdNbit) - 1;
 
  250                           (
boost::format(
"%d + %d footprints need too many bits; change IdPixelT typedef") %
 
  260     OldIdMap overwrittenIds;  
 
  262     auto grower = [&circular, &up, &down, &
left, &
right, &isotropic](
 
  266             auto tmpFoot = std::make_shared<Footprint>(foot->getSpans()->dilated(amount, 
element),
 
  270             int top = up ? amount : 0;
 
  271             int bottom = down ? amount : 0;
 
  272             int lLimit = 
left ? amount : 0;
 
  273             int rLimit = 
right ? amount : 0;
 
  275             auto yRange = top + bottom + 1;
 
  279             for (
auto dy = 1; dy <= top; ++dy) {
 
  280                 spanList.
push_back(geom::Span(dy, 0, 0));
 
  282             for (
auto dy = -1; dy >= -bottom; --dy) {
 
  283                 spanList.
push_back(geom::Span(dy, 0, 0));
 
  285             spanList.
push_back(geom::Span(0, -lLimit, rLimit));
 
  286             geom::SpanSet structure(
std::move(spanList));
 
  288                     std::make_shared<Footprint>(foot->getSpans()->dilated(structure), foot->getRegion());
 
  294     for (FootprintList::const_iterator 
ptr = lhsFootprints.begin(), 
end = lhsFootprints.end(); 
ptr != 
end;
 
  298         if (rLhs > 0 && foot->
getArea() > 0) {
 
  299             foot = grower(foot, rLhs);
 
  304                 ->clippedTo(idImage->getBBox())
 
  305                 ->applyFunctor(setIdImage<IdPixelT>(
id, &overwritten, 
true), *idImage);
 
  307         if (!overwritten.
empty()) {
 
  308             overwrittenIds.insert(overwrittenIds.end(), 
std::make_pair(
id, overwritten));
 
  313     id = (1 << lhsIdNbit);
 
  314     for (FootprintList::const_iterator 
ptr = rhsFootprints.begin(), 
end = rhsFootprints.end(); 
ptr != 
end;
 
  315          ++
ptr, 
id += (1 << lhsIdNbit)) {
 
  318         if (rRhs > 0 && foot->
getArea() > 0) {
 
  319             foot = grower(foot, rRhs);
 
  324                 ->clippedTo(idImage->getBBox())
 
  325                 ->applyFunctor(setIdImage<IdPixelT>(
id, &overwritten, 
true, lhsIdMask), *idImage);
 
  327         if (!overwritten.
empty()) {
 
  328             overwrittenIds.insert(overwrittenIds.end(), 
std::make_pair(
id, overwritten));
 
  332     FootprintSet 
fs(*idImage, Threshold(1), 1, 
false);  
 
  344     FindIdsInFootprint<IdPixelT> idFinder;
 
  345     for (FootprintList::iterator 
ptr = 
fs.getFootprints()->begin(), 
end = 
fs.getFootprints()->end();
 
  350         foot->
getSpans()->applyFunctor(idFinder, *idImage);
 
  355              idptr != idend; ++idptr) {
 
  356             unsigned int indx = *idptr;
 
  357             if ((indx & lhsIdMask) > 0) {
 
  359                 lhsFootprintIndxs.
insert(i);
 
  363                 OldIdMap::iterator mapPtr = overwrittenIds.find(indx);
 
  364                 if (mapPtr != overwrittenIds.end()) {
 
  369                         lhsFootprintIndxs.
insert((*
ptr & lhsIdMask) - 1);
 
  377                 rhsFootprintIndxs.
insert(i);
 
  381                 OldIdMap::iterator mapPtr = overwrittenIds.find(indx);
 
  382                 if (mapPtr != overwrittenIds.end()) {
 
  401             assert(i < lhsFootprints.size());
 
  402             PeakCatalog const &oldPeaks = lhsFootprints[i]->getPeaks();
 
  404             int const nold = peaks.
size();
 
  405             peaks.insert(peaks.end(), oldPeaks.begin(), oldPeaks.end());
 
  410                                peaks.getInternal().end(), SortPeaks());
 
  416             assert(i < rhsFootprints.size());
 
  417             PeakCatalog const &oldPeaks = rhsFootprints[i]->getPeaks();
 
  419             int const nold = peaks.
size();
 
  420             peaks.insert(peaks.end(), oldPeaks.begin(), oldPeaks.end());
 
  423                                peaks.getInternal().end(), SortPeaks());
 
  444 struct IdSpanCompare {
 
  445     bool operator()(IdSpan 
const &
a, IdSpan 
const &
b)
 const {
 
  448         } 
else if (
a.id > 
b.id) {
 
  451             return (
a.y < 
b.y) ? true : 
false;
 
  462     while (
id != aliases[
id]) {
 
  463         resolved = 
id = aliases[
id];
 
  472 template <
typename ImageT>
 
  475     auto spanSet = foot.getSpans();
 
  476     if (spanSet->size() == 0) {
 
  480     for (
auto const &spanIter : *spanSet) {
 
  481         auto y = spanIter.getY() - 
image.getY0();
 
  486         for (
auto x = spanIter.getMinX() - 
image.getX0(); 
x <= spanIter.getMaxX() - 
image.getX0(); ++
x) {
 
  511 template <
typename ImageT>
 
  512 class FindMaxInFootprint {
 
  514     explicit FindMaxInFootprint(
bool polarity)
 
  515             : _polarity(polarity),
 
  518               _min(
std::numeric_limits<double>::
max()),
 
  519               _max(-
std::numeric_limits<double>::
max()) {}
 
  537     void addRecord(
Footprint &foot)
 const { foot.addPeak(_x, _y, _polarity ? _max : _min); }
 
  545 template <
typename ImageT, 
typename ThresholdT>
 
  547     findPeaksInFootprint(img, polarity, foot->
getPeaks(), *foot, 1);
 
  556         FindMaxInFootprint<typename ImageT::Pixel> maxFinder(polarity);
 
  558         maxFinder.addRecord(*foot);
 
  563 template <
typename ImageT>
 
  572 template <
typename ImagePixelT, 
typename IterT>
 
  573 static inline bool inFootprint(ImagePixelT pixVal, IterT, 
bool polarity, 
double thresholdVal,
 
  574                                ThresholdLevel_traits) {
 
  575     return (polarity ? pixVal : -pixVal) >= thresholdVal;
 
  578 template <
typename ImagePixelT, 
typename IterT>
 
  579 static inline bool inFootprint(ImagePixelT pixVal, IterT var, 
bool polarity, 
double thresholdVal,
 
  580                                ThresholdPixelLevel_traits) {
 
  581     return (polarity ? pixVal : -pixVal) >= thresholdVal * ::sqrt(*var);
 
  584 template <
typename ImagePixelT, 
typename IterT>
 
  585 static inline bool inFootprint(ImagePixelT pixVal, IterT, 
bool, 
double thresholdVal,
 
  586                                ThresholdBitmask_traits) {
 
  587     return (pixVal & 
static_cast<long>(thresholdVal));
 
  593 template <
typename IterT>
 
  594 static inline IterT advancePtr(IterT varPtr, Threshold_traits) {
 
  598 template <
typename IterT>
 
  599 static inline IterT advancePtr(IterT varPtr, ThresholdPixelLevel_traits) {
 
  607 template <
typename ImagePixelT, 
typename MaskPixelT, 
typename VariancePixelT, 
typename ThresholdTraitT>
 
  608 static void findFootprints(
 
  613         double const footprintThreshold,                    
 
  614         double const includeThresholdMultiplier,  
 
  624     double includeThreshold = footprintThreshold * includeThresholdMultiplier;  
 
  626     int const row0 = img.
getY0();
 
  627     int const col0 = img.
getX0();
 
  642     aliases.
reserve(1 + height / 20);  
 
  655     for (
int y = 0; 
y != height; ++
y) {
 
  656         if (idc == id1.begin() + 1) {
 
  657             idc = id2.
begin() + 1;
 
  658             idp = id1.
begin() + 1;
 
  660             idc = id1.
begin() + 1;
 
  661             idp = id2.
begin() + 1;
 
  666         bool good = (includeThresholdMultiplier == 1.0); 
 
  669         x_var_iterator varPtr = (var == NULL) ? NULL : var->
row_begin(
y);
 
  670         for (
int x = 0; 
x < width; ++
x, ++pixPtr, varPtr = advancePtr(varPtr, ThresholdTraitT())) {
 
  671             ImagePixelT 
const pixVal = *pixPtr;
 
  673             if (isBadPixel(pixVal) ||
 
  674                 !inFootprint(pixVal, varPtr, polarity, footprintThreshold, ThresholdTraitT())) {
 
  682                 if (idc[
x - 1] != 0) {
 
  684                 } 
else if (idp[
x - 1] != 0) {
 
  686                 } 
else if (idp[
x] != 0) {
 
  688                 } 
else if (idp[
x + 1] != 0) {
 
  703                 if (idp[
x + 1] != 0 && idp[
x + 1] != 
id) {
 
  706                     idc[
x] = 
id = idp[
x + 1];
 
  709                 if (!good && inFootprint(pixVal, varPtr, polarity, includeThreshold, ThresholdTraitT())) {
 
  722     for (
unsigned int i = 0; i < spans.
size(); i++) {
 
  728     if (spans.
size() > 0) {
 
  735     if (spans.
size() > 0) {
 
  738         for (
unsigned int i = 0; i <= spans.
size(); i++) {  
 
  739             if (i == spans.
size() || spans[i].
id != 
id) {
 
  742                 for (; i0 < i; i0++) {
 
  743                     good |= spans[i0].good;
 
  745                             geom::Span(spans[i0].
y + row0, spans[i0].x0 + col0, spans[i0].x1 + col0));
 
  747                 auto tempSpanSet = std::make_shared<geom::SpanSet>(
std::move(tempSpanList));
 
  748                 auto fp = std::make_shared<Footprint>(tempSpanSet, _region);
 
  750                 if (good && fp->getArea() >= 
static_cast<std::size_t>(npixMin)) {
 
  751                     _footprints->push_back(fp);
 
  755             if (i < spans.
size()) {
 
  764         typedef FootprintSet::FootprintList::iterator fiterator;
 
  765         for (fiterator 
ptr = _footprints->begin(), 
end = _footprints->end(); 
ptr != 
end; ++
ptr) {
 
  766             findPeaks(*
ptr, img, polarity, ThresholdTraitT());
 
  771 template <
typename ImagePixelT>
 
  773                            int const npixMin, 
bool const setPeaks)
 
  774         : _footprints(new FootprintList()), _region(img.getBBox()) {
 
  775     typedef float VariancePixelT;
 
  777     findFootprints<ImagePixelT, image::MaskPixel, VariancePixelT, ThresholdLevel_traits>(
 
  778             _footprints.get(), _region, img, NULL, threshold.getValue(img), threshold.getIncludeMultiplier(),
 
  779             threshold.getPolarity(), npixMin, setPeaks);
 
  784 template <
typename MaskPixelT>
 
  786         : _footprints(new FootprintList()), _region(msk.getBBox()) {
 
  787     switch (threshold.getType()) {
 
  789             findFootprints<MaskPixelT, MaskPixelT, float, ThresholdBitmask_traits>(
 
  790                     _footprints.get(), _region, msk, NULL, threshold.getValue(),
 
  791                     threshold.getIncludeMultiplier(), threshold.getPolarity(), npixMin, 
false);
 
  795             findFootprints<MaskPixelT, MaskPixelT, float, ThresholdLevel_traits>(
 
  796                     _footprints.get(), _region, msk, NULL, threshold.getValue(),
 
  797                     threshold.getIncludeMultiplier(), threshold.getPolarity(), npixMin, 
false);
 
  801             throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
 
  802                               "You must specify a numerical threshold value with a Mask");
 
  806 template <
typename ImagePixelT, 
typename MaskPixelT>
 
  808                            Threshold 
const &threshold, 
std::string const &planeName, 
int const npixMin,
 
  810         : _footprints(new FootprintList()),
 
  815     switch (threshold.getType()) {
 
  817             findFootprints<ImagePixelT, MaskPixelT, VariancePixelT, ThresholdPixelLevel_traits>(
 
  819                     threshold.getValue(maskedImg), threshold.getIncludeMultiplier(), threshold.getPolarity(),
 
  823             findFootprints<ImagePixelT, MaskPixelT, VariancePixelT, ThresholdLevel_traits>(
 
  825                     threshold.getValue(maskedImg), threshold.getIncludeMultiplier(), threshold.getPolarity(),
 
  830     if (planeName == 
"") {
 
  837     mask->addMaskPlane(planeName);
 
  839     MaskPixelT 
const bitPlane = 
mask->getPlaneBitMask(planeName);
 
  843     for (
auto const &fIter : *_footprints) {
 
  844         fIter->getSpans()->setMask(*(maskedImg.
getMask()), bitPlane);
 
  849         : _footprints(
std::
make_shared<FootprintList>()), _region(region) {}
 
  852     _footprints->reserve(rhs._footprints->size());
 
  853     for (FootprintSet::FootprintList::const_iterator 
ptr = rhs._footprints->begin(),
 
  854                                                      end = rhs._footprints->end();
 
  856         _footprints->push_back(std::make_shared<Footprint>(**
ptr));
 
  875     FootprintControl 
const ctrl(
true, isotropic);
 
  876     FootprintSet fs = mergeFootprintSets(*
this, tGrow, rhs, rGrow, ctrl);
 
  883     for (FootprintSet::FootprintList::iterator 
ptr = _footprints->begin(), 
end = _footprints->end();
 
  885         (*ptr)->setRegion(region);
 
  890         : _footprints(new FootprintList), _region(rhs._region) {
 
  892         FootprintSet 
fs = rhs;
 
  896         throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
 
  897                           (
boost::format(
"I cannot grow by negative numbers: %d") % r).str());
 
  900     FootprintControl 
const ctrl(
true, isotropic);
 
  901     FootprintSet 
fs = mergeFootprintSets(FootprintSet(rhs.getRegion()), 0, rhs, r, ctrl);
 
  906         : _footprints(new FootprintList), _region(rhs._region) {
 
  908         FootprintSet 
fs = rhs;
 
  911     } 
else if (ngrow < 0) {
 
  912         throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
 
  913                           str(
boost::format(
"I cannot grow by negative numbers: %d") % ngrow));
 
  916     FootprintSet 
fs = mergeFootprintSets(FootprintSet(rhs.getRegion()), 0, rhs, ngrow, ctrl);
 
  921         : _footprints(new FootprintList()), _region(fs1._region) {
 
  923     throw LSST_EXCEPT(pex::exceptions::LogicError, 
"NOT IMPLEMENTED");
 
  927     auto im = std::make_shared<image::Image<FootprintIdPixel>>(_region);
 
  931     for (
auto const &fIter : *_footprints) {
 
  933         fIter->getSpans()->applyFunctor(setIdImage<FootprintIdPixel>(
id), *im);
 
  939 template <
typename ImagePixelT, 
typename MaskPixelT>
 
  941                              HeavyFootprintCtrl 
const *ctrl) {
 
  942     HeavyFootprintCtrl ctrl_s = HeavyFootprintCtrl();
 
  948     for (FootprintList::iterator 
ptr = _footprints->begin(), 
end = _footprints->end(); 
ptr != 
end; ++
ptr) {
 
  949         ptr->reset(
new HeavyFootprint<ImagePixelT, MaskPixelT>(**
ptr, mimg, ctrl));
 
  954     for (FootprintList::const_iterator i = _footprints->begin(); i != _footprints->end(); ++i) {
 
  966 #define INSTANTIATE(PIXEL)                                                                              \ 
  967     template FootprintSet::FootprintSet(image::Image<PIXEL> const &, Threshold const &, int const,      \ 
  969     template FootprintSet::FootprintSet(image::MaskedImage<PIXEL, image::MaskPixel> const &,            \ 
  970                                         Threshold const &, std::string const &, int const, bool const); \ 
  971     template void FootprintSet::makeHeavy(image::MaskedImage<PIXEL, image::MaskPixel> const &,          \ 
  972                                           HeavyFootprintCtrl const *)