File indexing completed on 2025-01-18 09:11:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <algorithm>
0010 #include <tuple>
0011
0012 template <class identifier_t>
0013 template <class PointType>
0014 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::fill(
0015 const PointType& measurement, const HoughAxisRanges& axisRanges,
0016 LineParametrisation<PointType> linePar,
0017 LineParametrisation<PointType> widthPar, const identifier_t& identifier,
0018 unsigned layer, YieldType weight) {
0019
0020 for (std::size_t xBin = 0; xBin < m_cfg.nBinsX; xBin++) {
0021
0022 auto x = binCenter(axisRanges.xMin, axisRanges.xMax, m_cfg.nBinsX, xBin);
0023
0024 CoordType y = linePar(x, measurement);
0025 CoordType dy = widthPar(x, measurement);
0026
0027 int yBinDown =
0028 binIndex(axisRanges.yMin, axisRanges.yMax, m_cfg.nBinsY, y - dy);
0029 int yBinUp =
0030 binIndex(axisRanges.yMin, axisRanges.yMax, m_cfg.nBinsY, y + dy);
0031
0032 for (int yBin = yBinDown; yBin <= yBinUp; ++yBin) {
0033
0034 if (yBin >= static_cast<int>(m_cfg.nBinsY) || yBin < 0) {
0035 continue;
0036 }
0037 fillBin(xBin, yBin, identifier, layer, weight);
0038 }
0039 }
0040 }
0041
0042 template <class identifier_t>
0043 std::span<const identifier_t, std::dynamic_extent>
0044 Acts::HoughTransformUtils::HoughCell<identifier_t>::getHits() const {
0045 std::span<const identifier_t, std::dynamic_extent> hits(m_hits.begin(),
0046 m_iHit);
0047 return hits;
0048 }
0049
0050 template <class identifier_t>
0051 std::span<const unsigned, std::dynamic_extent>
0052 Acts::HoughTransformUtils::HoughCell<identifier_t>::getLayers() const {
0053 std::span<const unsigned, std::dynamic_extent> layers(m_layers.begin(),
0054 m_iLayer);
0055
0056 return layers;
0057 }
0058
0059 template <class identifier_t>
0060 void Acts::HoughTransformUtils::HoughCell<identifier_t>::fill(
0061 const identifier_t& identifier, unsigned layer, YieldType weight) {
0062
0063
0064 if (m_iHit != 0 && m_hits[m_iHit - 1] == identifier) {
0065 return;
0066 }
0067
0068 if (m_iHit == m_hits.size()) {
0069 m_hits.resize(m_hits.size() + m_assignBatch);
0070 }
0071
0072 if (m_iLayer == m_layers.size()) {
0073 m_layers.resize(m_layers.size() + m_assignBatch);
0074 }
0075
0076 m_hits[m_iHit] = identifier;
0077 m_layers[m_iLayer] = layer;
0078
0079 m_iHit += 1;
0080 m_iLayer += 1;
0081
0082 m_nHits += weight;
0083 m_nLayers += weight;
0084 }
0085
0086 template <class identifier_t>
0087 void Acts::HoughTransformUtils::HoughCell<identifier_t>::reset() {
0088 m_nHits = 0;
0089 m_nLayers = 0;
0090
0091 m_iLayer = 0;
0092 m_iHit = 0;
0093 }
0094
0095 template <class identifier_t>
0096 Acts::HoughTransformUtils::HoughPlane<identifier_t>::HoughPlane(
0097 const HoughPlaneConfig& cfg)
0098 : m_cfg(cfg),
0099 m_houghHist(Axis(0, m_cfg.nBinsX, m_cfg.nBinsX),
0100 Axis(0, m_cfg.nBinsY, m_cfg.nBinsY)) {
0101
0102
0103
0104 }
0105 template <class identifier_t>
0106 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::fillBin(
0107 std::size_t binX, std::size_t binY, const identifier_t& identifier,
0108 unsigned layer, double w) {
0109
0110
0111 m_touchedBins.insert(globalBin({binX, binY}));
0112
0113
0114 m_houghHist.atLocalBins({binX, binY}).fill(identifier, layer, w);
0115
0116 YieldType layers = nLayers(binX, binY);
0117 YieldType hits = nHits(binX, binY);
0118 if (layers > m_maxLayers) {
0119 m_maxLayers = layers;
0120 m_maxLocLayers = {binX, binY};
0121 }
0122 if (hits > m_maxHits) {
0123 m_maxHits = hits;
0124 m_maxLocHits = {binX, binY};
0125 }
0126 }
0127
0128 template <class identifier_t>
0129 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::reset() {
0130
0131
0132 for (auto bin : getNonEmptyBins()) {
0133 m_houghHist.at(bin).reset();
0134 }
0135
0136 m_maxHits = 0.;
0137 m_maxLayers = 0.;
0138
0139 m_iBin = 0;
0140 m_touchedBins.clear();
0141 }
0142
0143 template <class identifier_t>
0144 Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<identifier_t>::
0145 LayerGuidedCombinatoric(const LayerGuidedCombinatoricConfig& cfg)
0146 : m_cfg(cfg) {}
0147
0148 template <class identifier_t>
0149 std::vector<typename Acts::HoughTransformUtils::PeakFinders::
0150 LayerGuidedCombinatoric<identifier_t>::Maximum>
0151 Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<
0152 identifier_t>::findPeaks(const HoughPlane<identifier_t>& plane) const {
0153
0154 std::vector<PeakFinders::LayerGuidedCombinatoric<identifier_t>::Maximum>
0155 maxima;
0156
0157 for (auto nbin : plane.getNonEmptyBins()) {
0158
0159
0160 std::array<std::size_t, 2> xy = plane.axisBins(nbin);
0161
0162 if (passThreshold(plane, xy[0], xy[1])) {
0163
0164 Maximum max;
0165 max.hitIdentifiers = plane.hitIds(xy[0], xy[1]);
0166 maxima.push_back(max);
0167 }
0168 }
0169 return maxima;
0170 }
0171
0172 template <class identifier_t>
0173 bool Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<
0174 identifier_t>::passThreshold(const HoughPlane<identifier_t>& plane,
0175 std::size_t xBin, std::size_t yBin) const {
0176
0177 if (plane.nLayers(xBin, yBin) < m_cfg.threshold) {
0178 return false;
0179 }
0180
0181 if (m_cfg.localMaxWindowSize == 0) {
0182 return true;
0183 }
0184
0185
0186
0187 for (int dXbin = -m_cfg.localMaxWindowSize; dXbin <= m_cfg.localMaxWindowSize;
0188 dXbin++) {
0189 for (int dYbin = -m_cfg.localMaxWindowSize;
0190 dYbin <= m_cfg.localMaxWindowSize; dYbin++) {
0191
0192 if (dYbin == 0 && dXbin == 0) {
0193 continue;
0194 }
0195
0196 if (static_cast<int>(xBin) + dXbin < 0 ||
0197 static_cast<int>(yBin) + dYbin < 0) {
0198 continue;
0199 }
0200 if (xBin + dXbin >= plane.nBinsX() || yBin + dYbin >= plane.nBinsY()) {
0201 continue;
0202 }
0203
0204 if (plane.nLayers(xBin + dXbin, yBin + dYbin) >
0205 plane.nLayers(xBin, yBin)) {
0206 return false;
0207 }
0208
0209 if (plane.nLayers(xBin + dXbin, yBin + dYbin) <
0210 plane.nLayers(xBin, yBin)) {
0211 continue;
0212 }
0213
0214
0215
0216
0217
0218 if (plane.nHits(xBin + dXbin, yBin + dYbin) > plane.nHits(xBin, yBin)) {
0219 return false;
0220 }
0221
0222
0223 if (plane.nHits(xBin + dXbin, yBin + dYbin) == plane.nHits(xBin, yBin) &&
0224 (dYbin < 0 || (dYbin == 0 && dXbin < 0))) {
0225 return false;
0226 }
0227 }
0228 }
0229 return true;
0230 }
0231 template <class identifier_t>
0232 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0233 identifier_t>::IslandsAroundMax(const IslandsAroundMaxConfig& cfg)
0234 : m_cfg(cfg) {}
0235
0236 template <class identifier_t>
0237 std::vector<typename Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0238 identifier_t>::Maximum>
0239 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0240 identifier_t>::findPeaks(const HoughPlane<identifier_t>& plane,
0241 const HoughAxisRanges& ranges) {
0242
0243 YieldType max = plane.maxHits();
0244
0245 YieldType min = std::max(m_cfg.threshold, m_cfg.fractionCutoff * max);
0246
0247 const std::unordered_set<std::size_t>& nonEmptyBins{plane.getNonEmptyBins()};
0248 std::vector<std::size_t> candidates;
0249 candidates.reserve(nonEmptyBins.size());
0250 std::vector<Maximum> maxima;
0251 maxima.reserve(nonEmptyBins.size());
0252
0253 std::unordered_map<std::size_t, YieldType> yieldMap;
0254
0255
0256 for (const std::size_t nbin : nonEmptyBins) {
0257
0258
0259
0260
0261 if (plane.nHits(nbin) > min) {
0262 candidates.push_back(nbin);
0263 yieldMap[nbin] = plane.nHits(nbin);
0264 }
0265 }
0266
0267 std::ranges::sort(candidates, std::greater{}, [&yieldMap](std::size_t c) {
0268 return std::make_tuple(yieldMap[c], c);
0269 });
0270
0271
0272
0273 std::vector<std::size_t> toExplore;
0274 std::vector<std::array<std::size_t, 2>> solution;
0275
0276
0277 for (auto& cand : candidates) {
0278
0279
0280 if (yieldMap[cand] < min) {
0281 continue;
0282 }
0283
0284 std::array<std::size_t, 2> xy = plane.axisBins(cand);
0285
0286 CoordType xCand =
0287 binCenter(ranges.xMin, ranges.xMax, plane.nBinsX(), xy[0]);
0288 CoordType yCand =
0289 binCenter(ranges.yMin, ranges.yMax, plane.nBinsY(), xy[1]);
0290
0291 bool goodSpacing = true;
0292 for (auto& found : maxima) {
0293 if (std::abs(xCand - found.x) < m_cfg.minSpacingBetweenPeaks.first ||
0294 std::abs(yCand - found.y) < m_cfg.minSpacingBetweenPeaks.second) {
0295 goodSpacing = false;
0296 break;
0297 }
0298 }
0299 if (!goodSpacing) {
0300 continue;
0301 }
0302
0303 toExplore.clear();
0304 solution.clear();
0305
0306
0307 toExplore.push_back(cand);
0308
0309 while (!toExplore.empty()) {
0310 extendMaximum(plane, solution, toExplore, min, yieldMap);
0311 }
0312
0313 if (solution.empty()) {
0314 continue;
0315 }
0316
0317 Maximum maximum;
0318 CoordType max_x = 0;
0319 CoordType max_y = 0;
0320 CoordType pos_den = 0;
0321 CoordType ymax = -std::numeric_limits<CoordType>::max();
0322 CoordType ymin = std::numeric_limits<CoordType>::max();
0323 CoordType xmax = -std::numeric_limits<CoordType>::max();
0324 CoordType xmin = std::numeric_limits<CoordType>::max();
0325
0326
0327
0328 for (auto& [xBin, yBin] : solution) {
0329 auto hidIds = plane.hitIds(xBin, yBin);
0330 maximum.hitIdentifiers.insert(std::make_move_iterator(hidIds.begin()),
0331 std::make_move_iterator(hidIds.end()));
0332 CoordType xHit =
0333 binCenter(ranges.xMin, ranges.xMax, plane.nBinsX(), xBin);
0334 CoordType yHit =
0335 binCenter(ranges.yMin, ranges.yMax, plane.nBinsY(), yBin);
0336 YieldType nHits = plane.nHits(xBin, yBin);
0337 max_x += xHit * nHits;
0338 max_y += yHit * nHits;
0339 pos_den += nHits;
0340 if (xHit > xmax) {
0341 xmax = xHit;
0342 }
0343 if (yHit > ymax) {
0344 ymax = yHit;
0345 }
0346 if (xHit < xmin) {
0347 xmin = xHit;
0348 }
0349 if (yHit < ymin) {
0350 ymin = yHit;
0351 }
0352 }
0353
0354 maximum.x = max_x / pos_den;
0355 maximum.y = max_y / pos_den;
0356
0357 maximum.wx = 0.5 * (xmax - xmin);
0358 maximum.wy = 0.5 * (ymax - ymin);
0359 maxima.push_back(maximum);
0360 }
0361 return maxima;
0362 }
0363
0364 template <class identifier_t>
0365 void Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<identifier_t>::
0366 extendMaximum(
0367 const Acts::HoughTransformUtils::HoughPlane<identifier_t>& houghPlane,
0368 std::vector<std::array<std::size_t, 2>>& inMaximum,
0369 std::vector<std::size_t>& toExplore, YieldType threshold,
0370 std::unordered_map<std::size_t, YieldType>& yieldMap) {
0371
0372
0373
0374 const std::size_t candidate = toExplore.back();
0375 YieldType& yield{yieldMap[candidate]};
0376 toExplore.pop_back();
0377
0378 if (yield < threshold) {
0379 return;
0380 }
0381
0382 auto nextCand = houghPlane.axisBins(candidate);
0383
0384 inMaximum.push_back(nextCand);
0385
0386 yieldMap[candidate] = -1.0f;
0387
0388
0389
0390 for (auto step : m_stepDirections) {
0391 std::array<unsigned long, 2> newCandxy = {nextCand[0] + step.first,
0392 nextCand[1] + step.second};
0393
0394 if (newCandxy[0] >= houghPlane.nBinsX() ||
0395 newCandxy[1] >= houghPlane.nBinsY()) {
0396 continue;
0397 }
0398 std::size_t newCand = houghPlane.globalBin({newCandxy[0], newCandxy[1]});
0399
0400
0401
0402 if (yieldMap[newCand] > threshold) {
0403 toExplore.push_back(newCand);
0404 }
0405 }
0406 }