![]() |
|
|||
File indexing completed on 2025-10-17 07:58:41
0001 // This file is part of the ACTS project. 0002 // 0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project 0004 // 0005 // This Source Code Form is subject to the terms of the Mozilla Public 0006 // License, v. 2.0. If a copy of the MPL was not distributed with this 0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 0008 0009 /// This file implements the tools for a hough transform. 0010 0011 #pragma once 0012 0013 #include "Acts/Utilities/Grid.hpp" 0014 0015 #include <array> 0016 #include <span> 0017 #include <unordered_set> 0018 0019 namespace Acts::HoughTransformUtils { 0020 0021 /// this type is responsible for encoding the parameters of our hough space 0022 using CoordType = double; 0023 0024 /// Type alias for hit count/weight values in Hough space 0025 // this type is used to encode hit counts. 0026 // Floating point to allow hit weights to be applied 0027 using YieldType = float; 0028 0029 /// @brief this function represents a mapping of a coordinate point in detector space to a line in 0030 /// hough space. Given the value of the first hough coordinate, it shall return 0031 /// the corresponding second coordinate according to the line parametrisation. 0032 /// Should be implemented by the user. 0033 /// @tparam PointType: The class representing a point in detector space (can differ between implementations) 0034 template <class PointType> 0035 using LineParametrisation = 0036 std::function<CoordType(CoordType, const PointType&)>; 0037 0038 /// @brief struct to define the ranges of the hough histogram. 0039 /// Used to move between parameter and bin index coordinates. 0040 /// Disconnected from the hough plane binning to be able to re-use 0041 /// a plane with a given binning for several parameter ranges 0042 struct HoughAxisRanges { 0043 /// Minimum value of the first hough coordinate 0044 CoordType xMin = 0.0f; // minimum value of the first coordinate 0045 /// Maximum value of the first hough coordinate 0046 CoordType xMax = 0.0f; // maximum value of the first coordinate 0047 /// Minimum value of the second hough coordinate 0048 CoordType yMin = 0.0f; // minimum value of the second coordinate 0049 /// Maximum value of the second hough coordinate 0050 CoordType yMax = 0.0f; // maximum value of the second coordinate 0051 }; 0052 0053 /// convenience functions to link bin indices to axis coordinates 0054 0055 /// @brief find the bin index corresponding to a certain abscissa 0056 /// of the coordinate axis, based on the axis limits and binning. 0057 /// @param min: Start of axis range 0058 /// @param max: End of axis range 0059 /// @param nSteps: Number of bins in axis 0060 /// @param val: value to find the corresponding bin for 0061 /// @return the bin number. 0062 /// No special logic to prevent over-/underflow, checking these is 0063 /// left to the caller 0064 inline int binIndex(double min, double max, unsigned nSteps, double val) { 0065 return static_cast<int>((val - min) / (max - min) * nSteps); 0066 } 0067 // Returns the lower bound of the bin specified by step 0068 /// @param min: Start of axis range 0069 /// @param max: End of axis range 0070 /// @param nSteps: Number of bins in axis 0071 /// @param binIndex: The index of the bin 0072 /// @return the parameter value at the lower bin edge. 0073 /// No special logic to prevent over-/underflow, checking these is 0074 /// left to the caller 0075 inline double lowerBinEdge(double min, double max, unsigned nSteps, 0076 std::size_t binIndex) { 0077 return min + (max - min) * binIndex / nSteps; 0078 } 0079 // Returns the lower bound of the bin specified by step 0080 /// @param min: Start of axis range 0081 /// @param max: End of axis range 0082 /// @param nSteps: Number of bins in axis 0083 /// @param binIndex: The index of the bin 0084 /// @return the parameter value at the bin center. 0085 /// No special logic to prevent over-/underflow, checking these is 0086 /// left to the caller 0087 inline double binCenter(double min, double max, unsigned nSteps, 0088 std::size_t binIndex) { 0089 return min + (max - min) * 0.5 * (2 * binIndex + 1) / nSteps; 0090 } 0091 0092 /// @brief data class for the information to store for each 0093 /// cell of the hough histogram. 0094 /// @tparam identifier_t: Type of the identifier to associate to the hits 0095 /// Should be sortable. Used to uniquely identify each 0096 /// hit and to eventually return the list of hits per cell 0097 template <class identifier_t> 0098 class HoughCell { 0099 public: 0100 /// @brief construct the cell as empty 0101 HoughCell() = default; 0102 /// @brief add an entry to this cell 0103 /// @param identifier: Identifier of the hit (used to distinguish hits from another) 0104 /// @param layer: Layer of the hit (used when counting layers) 0105 /// @param weight: Optional weight to assign to the hit 0106 void fill(const identifier_t& identifier, unsigned int layer, 0107 YieldType weight = 1.); 0108 /// @brief access the number of layers with hits compatible with this cell 0109 /// @return The (weighted) number of layers with hits in this cell 0110 YieldType nLayers() const { return m_nLayers; } 0111 /// @brief access the number of unique hits compatible with this cell 0112 /// @return The (weighted) number of unique hits in this cell 0113 YieldType nHits() const { return m_nHits; } 0114 /// @brief access the span of layers compatible with this cell 0115 /// @return Span containing the layer indices with hits in this cell 0116 std::span<const unsigned, std::dynamic_extent> getLayers() const; 0117 /// Access the span of unique hits compatible with this cell. 0118 /// @return Span containing the identifiers of hits in this cell 0119 std::span<const identifier_t, std::dynamic_extent> getHits() const; 0120 0121 /// @brief reset this cell, removing any existing content. 0122 void reset(); 0123 0124 private: 0125 /// (weighted) number of layers with hits on this cell 0126 YieldType m_nLayers{0}; 0127 /// (weighted) number of unique hits on this cell 0128 YieldType m_nHits{0}; 0129 0130 /// index for the hits -- keeps track of vector's size 0131 std::size_t m_iHit{0}; 0132 /// index for the layers -- keeps track of vector's size 0133 std::size_t m_iLayer{0}; 0134 0135 /// a batch to resize the vector of the hits or the layers 0136 std::size_t m_assignBatch{20}; 0137 0138 /// vector of layers with hits on this cell 0139 std::vector<unsigned> m_layers{std::vector<unsigned>(m_assignBatch)}; 0140 0141 /// vector of hits on this cell 0142 std::vector<identifier_t> m_hits{std::vector<identifier_t>(m_assignBatch)}; 0143 }; 0144 0145 /// @brief Configuration - number of bins in each axis. 0146 /// The Hough plane is agnostic of how the bins map to 0147 /// coordinates, allowing to re-use a plane for several 0148 /// (sub) detectors of different dimensions if the bin number 0149 /// remains applicable 0150 struct HoughPlaneConfig { 0151 /// Number of bins in the first hough coordinate 0152 std::size_t nBinsX = 0; // number of bins in the first coordinate 0153 /// Number of bins in the second hough coordinate 0154 std::size_t nBinsY = 0; // number of bins in the second coordinate 0155 }; 0156 0157 /// @brief Representation of the hough plane - the histogram used 0158 /// for the hough transform with methods to fill and evaluate 0159 /// the histogram. Templated to a class used as identifier for the hits 0160 template <class identifier_t> 0161 class HoughPlane { 0162 public: 0163 /// @brief hough histogram representation as a 2D-indexable vector of hough cells 0164 using Axis = 0165 Acts::Axis<Acts::AxisType::Equidistant, Acts::AxisBoundaryType::Bound>; 0166 /// Type alias for Hough histogram grid 0167 using HoughHist = Grid<HoughCell<identifier_t>, Axis, Axis>; 0168 /// Type alias for histogram index type 0169 using Index = typename HoughHist::index_t; 0170 0171 /// @brief instantiate the (empty) hough plane 0172 /// @param cfg: configuration 0173 explicit HoughPlane(const HoughPlaneConfig& cfg); 0174 0175 /// fill and reset methods to modify the grid content 0176 0177 /// @brief add one measurement to the hough plane 0178 /// @tparam PointType: Type of the objects to use when adding measurements (e.g. experiment EDM object) 0179 /// @param measurement: The measurement to add 0180 /// @param axisRanges: Ranges of the hough axes, used to map the bin numbers to parameter values 0181 /// @param linePar: The function y(x) parametrising the hough space line for a given measurement 0182 /// @param widthPar: The function dy(x) parametrising the width of the y(x) curve 0183 /// for a given measurement 0184 /// @param identifier: The unique identifier for the given hit 0185 /// @param layer: A layer index for this hit 0186 /// @param weight: An optional weight to assign to this hit 0187 template <class PointType> 0188 void fill(const PointType& measurement, const HoughAxisRanges& axisRanges, 0189 LineParametrisation<PointType> linePar, 0190 LineParametrisation<PointType> widthPar, 0191 const identifier_t& identifier, unsigned layer = 0, 0192 YieldType weight = 1.0f); 0193 /// @brief resets the contents of the grid. Can be used to avoid reallocating the histogram 0194 /// when switching regions / (sub)detectors 0195 void reset(); 0196 0197 //// user-facing accessors 0198 0199 /// @brief get the layers with hits in one cell of the histogram 0200 /// @param xBin: bin index in the first coordinate 0201 /// @param yBin: bin index in the second coordinate 0202 /// @return the set of layer indices that have hits for this cell 0203 std::unordered_set<unsigned> layers(std::size_t xBin, 0204 std::size_t yBin) const { 0205 return m_houghHist.atLocalBins({xBin, yBin}).layers(); 0206 } 0207 0208 /// @brief get the (weighted) number of layers with hits in one cell of the histogram 0209 /// @param xBin: bin index in the first coordinate 0210 /// @param yBin: bin index in the second coordinate 0211 /// @return the (weighed) number of layers that have hits for this cell 0212 YieldType nLayers(std::size_t xBin, std::size_t yBin) const { 0213 return m_houghHist.atLocalBins({xBin, yBin}).nLayers(); 0214 } 0215 0216 /// @brief get the identifiers of all hits in one cell of the histogram 0217 /// @param xBin: bin index in the first coordinate 0218 /// @param yBin: bin index in the second coordinate 0219 /// @return the list of identifiers of the hits for this cell 0220 /// Can include duplicates if a hit was filled more than once 0221 std::span<const identifier_t, std::dynamic_extent> hitIds( 0222 std::size_t xBin, std::size_t yBin) const { 0223 return m_houghHist.atLocalBins({xBin, yBin}).getHits(); 0224 } 0225 /// @brief get the identifiers of all hits in one cell of the histogram 0226 /// @param xBin: bin index in the first coordinate 0227 /// @param yBin: bin index in the second coordinate 0228 /// @return the list of identifiers of the hits for this cell 0229 /// Guaranteed to not duplicate identifiers 0230 std::unordered_set<const identifier_t> uniqueHitIds(std::size_t xBin, 0231 std::size_t yBin) const { 0232 const auto hits_span = m_houghHist.atLocalBins({xBin, yBin}).getHits(); 0233 return std::unordered_set<identifier_t>(hits_span.begin(), hits_span.end()); 0234 } 0235 /// @brief access the (weighted) number of hits in one cell of the histogram from bin's coordinates 0236 /// @param xBin: bin index in the first coordinate 0237 /// @param yBin: bin index in the second coordinate 0238 /// @return the (weighted) number of hits for this cell 0239 YieldType nHits(std::size_t xBin, std::size_t yBin) const { 0240 return m_houghHist.atLocalBins({xBin, yBin}).nHits(); 0241 } 0242 0243 /// @brief access the (weighted) number of hits in one cell of the histogram from globalBin index 0244 /// @param globalBin: global bin index 0245 /// @return the (weighted) number of hits for this cell 0246 YieldType nHits(std::size_t globalBin) const { 0247 return m_houghHist.at(globalBin).nHits(); 0248 } 0249 0250 /// @brief get the number of bins on the first coordinate 0251 /// @return Number of bins in the X direction 0252 std::size_t nBinsX() const { return m_cfg.nBinsX; } 0253 /// @brief get the number of bins on the second coordinate 0254 /// @return Number of bins in the Y direction 0255 std::size_t nBinsY() const { return m_cfg.nBinsY; } 0256 0257 /// @brief get the maximum number of (weighted) hits seen in a single 0258 /// cell across the entire histrogram. 0259 /// @return Maximum number of hits found in any single cell 0260 YieldType maxHits() const { return m_maxHits; } 0261 0262 /// @brief get the list of cells with non-zero content. 0263 /// Useful for peak-finders in sparse data 0264 /// to avoid looping over all cells 0265 /// @return Reference to set of global bin indices with non-zero content 0266 const std::unordered_set<std::size_t>& getNonEmptyBins() const { 0267 return m_touchedBins; 0268 } 0269 0270 /// @brief get the coordinates of the bin given the global bin index 0271 /// @param globalBin Global bin index to convert to coordinates 0272 /// @return Local bin coordinates (x,y) corresponding to global bin index 0273 Index axisBins(std::size_t globalBin) const { 0274 return m_houghHist.localBinsFromGlobalBin(globalBin); 0275 } 0276 0277 /// @brief get the globalBin index given the coordinates of the bin 0278 /// @param indexBin Bin coordinates to convert to global index 0279 /// @return Global bin index corresponding to local bin coordinates 0280 std::size_t globalBin(Index indexBin) const { 0281 return m_houghHist.globalBinFromLocalBins(indexBin); 0282 } 0283 0284 /// @brief get the bin indices of the cell containing the largest number 0285 /// of (weighted) hits across the entire histogram 0286 /// @return Pair of (x,y) bin indices where maximum hits are found 0287 std::pair<std::size_t, std::size_t> locMaxHits() const { 0288 return m_maxLocHits; 0289 } 0290 0291 /// @brief get the maximum number of (weighted) layers with hits seen 0292 /// in a single cell across the entire histrogram. 0293 /// @return Maximum number of layers found in any single cell 0294 YieldType maxLayers() const { return m_maxLayers; } 0295 0296 /// @brief get the bin indices of the cell containing the largest number 0297 /// of (weighted) layers with hits across the entire histogram 0298 /// @return Pair of (x,y) bin indices where maximum layers are found 0299 std::pair<std::size_t, std::size_t> locMaxLayers() const { 0300 return m_maxLocLayers; 0301 } 0302 0303 private: 0304 /// @brief Helper method to fill a bin of the hough histogram. 0305 /// Updates the internal helper data structures (maximum tracker etc). 0306 /// @param binX: bin number along x 0307 /// @param binY: bin number along y 0308 /// @param identifier: hit identifier 0309 /// @param layer: layer index 0310 /// @param w: optional hit weight 0311 void fillBin(std::size_t binX, std::size_t binY, 0312 const identifier_t& identifier, unsigned layer, double w = 1.0f); 0313 0314 YieldType m_maxHits = 0.0f; // track the maximum number of hits seen 0315 YieldType m_maxLayers = 0.0f; // track the maximum number of layers seen 0316 0317 /// track the location of the maximum in hits 0318 std::pair<std::size_t, std::size_t> m_maxLocHits = {0, 0}; 0319 /// track the location of the maximum in layers 0320 std::pair<std::size_t, std::size_t> m_maxLocLayers = {0, 0}; 0321 0322 std::size_t m_assignBatch{20}; 0323 0324 /// track the bins with non-trivial content 0325 std::unordered_set<std::size_t> m_touchedBins{}; 0326 0327 std::size_t m_iBin = 0; 0328 0329 HoughPlaneConfig m_cfg; // the configuration object 0330 HoughHist m_houghHist; // the histogram data object 0331 }; 0332 0333 /// example peak finders. 0334 namespace PeakFinders { 0335 /// configuration for the LayerGuidedCombinatoric peak finder 0336 struct LayerGuidedCombinatoricConfig { 0337 /// Minimum number of layers required to form a peak 0338 YieldType threshold = 3.0f; // min number of layers to obtain a maximum 0339 /// Size of window for local maximum detection 0340 int localMaxWindowSize = 0; // Only create candidates from a local maximum 0341 }; 0342 0343 /// @brief Peak finder inspired by ATLAS ITk event filter developments. 0344 /// Builds peaks based on layer counts and allows for subsequent resolution 0345 /// of the combinatorics by building multiple candidates per peak if needed. 0346 /// In flat regions, peak positions are moved towards smaller values of the 0347 /// second and first coordinate. 0348 /// @tparam identifier_t: The identifier type to use. Should match the one used in the hough plane. 0349 template <class identifier_t> 0350 class LayerGuidedCombinatoric { 0351 public: 0352 /// @brief data class representing the found maxima. 0353 /// Here, we just have a list of cluster identifiers 0354 struct Maximum { 0355 /// Set of hit identifiers contributing to this peak 0356 std::unordered_set<identifier_t> hitIdentifiers = 0357 {}; // identifiers of contributing hits 0358 }; 0359 /// @brief constructor 0360 /// @param cfg: Configuration object 0361 explicit LayerGuidedCombinatoric(const LayerGuidedCombinatoricConfig& cfg); 0362 0363 /// @brief main peak finder method. 0364 /// @param plane: Filled hough plane to search 0365 /// @return vector of found maxima 0366 std::vector<Maximum> findPeaks(const HoughPlane<identifier_t>& plane) const; 0367 0368 private: 0369 /// @brief check if a given bin is a local maximum. 0370 /// @param plane: The filled hough plane 0371 /// @param xBin: x bin index 0372 /// @param yBin: y bin index 0373 /// @return true if a maximum, false otherwise 0374 bool passThreshold(const HoughPlane<identifier_t>& plane, std::size_t xBin, 0375 std::size_t yBin) const; // did we pass extensions? 0376 0377 LayerGuidedCombinatoricConfig m_cfg; // configuration data object 0378 }; 0379 /// @brief Configuration for the IslandsAroundMax peak finder 0380 struct IslandsAroundMaxConfig { 0381 /// Minimum number of weighted hits required for a peak 0382 YieldType threshold = 0383 3.0f; // min number of weigted hits required in a maximum 0384 /// Fraction of global maximum below which peaks are ignored 0385 YieldType fractionCutoff = 0386 0; // Fraction of the global maximum at which to cut off maxima 0387 /// Minimum spacing between peaks in parameter space 0388 std::pair<CoordType, CoordType> minSpacingBetweenPeaks = { 0389 0.0f, 0.0f}; // minimum distance of a new peak from existing peaks in 0390 // parameter space 0391 }; 0392 /// @brief Peak finder inspired by ATLAS muon reconstruction. 0393 /// Looks for regions above a given fraction of the global maximum 0394 /// hit count and connects them into islands comprising adjacent bins 0395 /// above the threshold. Peak positions are averaged across cells in the island, 0396 /// weighted by hit counts 0397 /// @tparam identifier_t: The identifier type to use. Should match the one used in the hough plane. 0398 template <class identifier_t> 0399 class IslandsAroundMax { 0400 public: 0401 /// @brief data struct representing a local maximum. 0402 /// Comes with a position estimate and a list of hits within the island 0403 struct Maximum { 0404 /// X coordinate of the peak maximum 0405 CoordType x = 0; 0406 /// Y coordinate of the peak maximum 0407 CoordType y = 0; 0408 /// Width of the peak in X direction 0409 CoordType wx = 0; 0410 /// Width of the peak in Y direction 0411 CoordType wy = 0; 0412 /// Set of hit identifiers contributing to this peak 0413 std::unordered_set<identifier_t> hitIdentifiers = 0414 {}; // identifiers of contributing hits 0415 }; 0416 /// @brief constructor. 0417 /// @param cfg: configuration object 0418 explicit IslandsAroundMax(const IslandsAroundMaxConfig& cfg); 0419 0420 /// @brief main peak finder method. 0421 /// @param plane: The filled hough plane to search 0422 /// @param ranges: The axis ranges used for mapping between parameter space and bins. 0423 /// @return List of the found maxima 0424 std::vector<Maximum> findPeaks(const HoughPlane<identifier_t>& plane, 0425 const HoughAxisRanges& ranges); 0426 0427 private: 0428 /// @brief method to incrementally grow an island by adding adjacent cells 0429 /// Performs a breadth-first search for neighbours above threshold and adds 0430 /// them to candidate. Stops when no suitable neighbours are left. 0431 /// @param houghPlane: The current hough Plane we are looking for maxima 0432 /// @param inMaximum: List of cells found in the island. Incrementally populated by calls to the method 0433 /// @param toExplore: List of the global Bin indices of neighbour cell candidates left to explore. Method will not do anything once this is empty 0434 /// @param threshold: the threshold to apply to check if a cell should be added to an island 0435 /// @param yieldMap: A map of the hit content of above-threshold cells. Used cells will be set to empty content to avoid re-use by subsequent calls 0436 void extendMaximum(const HoughPlane<identifier_t>& houghPlane, 0437 std::vector<std::array<std::size_t, 2>>& inMaximum, 0438 std::vector<std::size_t>& toExplore, YieldType threshold, 0439 std::unordered_map<std::size_t, YieldType>& yieldMap); 0440 0441 IslandsAroundMaxConfig m_cfg; // configuration data object 0442 0443 /// @brief array of steps to consider when exploring neighbouring cells. 0444 const std::array<std::pair<int, int>, 8> m_stepDirections{ 0445 std::make_pair(-1, -1), std::make_pair(0, -1), std::make_pair(1, -1), 0446 std::make_pair(-1, 0), std::make_pair(1, 0), std::make_pair(-1, 1), 0447 std::make_pair(0, 1), std::make_pair(1, 1)}; 0448 }; 0449 } // namespace PeakFinders 0450 } // namespace Acts::HoughTransformUtils 0451 0452 #include "HoughTransformUtils.ipp"
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |