LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
HoughBaseAlg.h
Go to the documentation of this file.
1 // HoughBaseAlg.h
3 //
4 // HoughBaseAlg class
5 //
6 // Ben Carls (bcarls@fnal.gov)
7 // Some optimization by Gianluca Petrillo (petrillo@fnal.gov)
8 //
9 // Hough transform algorithm
10 // ============================================================================
11 //
12 // This implementation is a pattern recognition algorithm trying to detect
13 // straight lines in a image.
14 // In our application, the image is a hitmap on a wire plane, represented by
15 // wire number as one coordinate and drift time as the other.
16 // For each hit coordinate, all straight lines through that coordinate are
17 // recorded on counters, one for each line. If a counter rises to two, it
18 // mesans that there are two hits who can cast that line, i.e. there are two
19 // hits on that line.
20 // A line can be represented by two independent parameters, therefore we need a
21 // two-dimension parameter space to represent all of them (two degrees of
22 // freedom).
23 // Since there are infinite straight lines, each counter represents not just
24 // one line but a small region of parameter space.
25 // Passing by one point constraints one of the two parameters, therefore the
26 // parameter set of a generic line passing by a given point has one degree of
27 // freedom.
28 // We follow the custom of choosing as parameters of an arbitrary line passing
29 // through a point (x, y) the angle (from "x" axis) of the line, and the
30 // distance of the line from the chosen point. Fixing the point, we can assign
31 // freedom to the angle (that has a limited range by definition) and then
32 // the distance will be defined by some functional form d(angle).
33 // The shape (d vs. a) of the set of parameters of all lines passing by a point
34 // is a sinusoidal curve. We can define the angle to be between 0 and pi
35 // (half a period) and the distance potentially covers the whole real axis
36 // (but actually it will be never larger than the distance of the selected
37 // point from the origin).
38 //
39 // The implementation of the algorithm is based on a "accumulator", the set
40 // of counters of how many hits are passed by a given line (represented by
41 // its tow parameters). The accumulator is a two-dimensional container of
42 // counters, with the first dimension given by the angle and the second by the
43 // distance.
44 // In this scenario, all angles are sampled, therefore each angle will have
45 // at least one count per hit (somewhere at some distance d).
46 // Each angle will see one entry per hit.
47 // We choose to have a large number of sampled angles (the current standard
48 // configuration says 10800), therefore most of the counters will be empty.
49 // The sinusoidal shape can be steep enough that got example the angle a(1)
50 // has d(a1)=30 and the next angle (a2) has d(a2)=50. In this case we cover
51 // also the distances between 31 and 50, (assigning them, as an approximation,
52 // to a2). In this way we don't leave gaps and make sure that each two
53 // sinusoidal curves cross in at least one point, or, equivalently, that we
54 // can always find at least one straight line throw any two points.
55 // This translates in having very often the counts at a given angle clustered
56 // around some distances.
57 //
58 // We need to discretize the angles and the distances. Tests show that for a
59 // "natural" plane size of 9600 (TDC counts) x ~3000 (wires), we need to use
60 // O(10000) angles and to oversample the distance, that typically goes in the
61 // range [0-10000], by some factor (5 in the default parameters).
62 // The oversampling factor is just an artifact of the fact that we use integral
63 // distances but we want to have a resolution better than "1" -- we just
64 // multiply the distance by e.g. 5 and we get that the distace "1" actually
65 // means 1/5 = 0.2.
66 // Note that the algorithm is usually applied to subsets of that plane rather
67 // than on the full plane, making the typical distance range somehow smaller.
68 //
69 // The fastest data structure for the accumulator is a two-dimensional array.
70 // The proper size of this array would be some gigabyte, that makes this
71 // approach unfeasible. Since the dimension of angles has a very clear number
72 // of "bins" (covering always a fixed 0-pi range), but for each given angle
73 // the counters actually used are a few, a sparse structure (associative
74 // container, or "map") is used to describe all the counters at a given angle,
75 // with key the parameter r (discretized).
76 // Since all the angles always have data, the outer container is a vector
77 // whose index is the parameter a (also discretized).
78 // Therefore, for a given line (a, r), we can find how many hits pass though
79 // it by finding the associative container of the angle a from a vector,
80 // and in there looking for an entry with d as key: accum[a][d].
81 //
82 // Optimization
83 // ----------------------------------------------------------------------------
84 //
85 // Given the constraints and data structure described above, it turns out that
86 // a lot of time is spent creating new counters. On each hit, and each angle,
87 // one or more elements of the associative containers must be created.
88 // In total, millions of counter instances ar used at once.
89 // The standard C++ implementation of it, std::map, dynamically a new node
90 // each time a new counter is required, and in the end it frees them one by
91 // one. Both operations are very time-demanding.
92 // We used a custom memory allocator (BulkAllocator) that prepares memory
93 // for chunks of nodes and then returns a preallocated space at each request
94 // for a new node. The allocator is designed to be fast, giving up features:
95 // nodes are never really freed, that saves a lot of book-keeping.
96 // A lot of tricky aspects of it are documented in its own header file.
97 // Also freeing the memory is fast, since it implies the deletion of a few
98 // (very large) chunks rather than millions.
99 // The other aspect taking a lot of time is the lookup of a counter: where is
100 // counter (a,d)? the location of a is fast (constant time, from a vector).
101 // The location of d is the next best thing, a binary tree with log(N) access
102 // time. Unfortunately a balanced tree needs to be rebalanced often, and that
103 // takes a lot of time. Also, N may be "small" (O(1000)), but there are still
104 // million insertions and look ups.
105 // We use here a replacement of the plain map. Since it often happens that,
106 // to "fill the gaps", sequential counters are allocated and increased,
107 // we have blocks of couners allocated together (in the current version, 64
108 // of them). This can save memory in case of crowded spaces: the overhead
109 // for each node is 40 bytes, whether it is a single counter or a block of
110 // 64). Look up within the same block becomes constant-time.
111 // Also, to access sequences of counters, special code is used so that we
112 // take advantage of the result from the previous look up to perform the next
113 // one, including also the insertion of a new counter block after an existing
114 // one.
115 // Finally, the algorithm acts when it finds a relatively small number of
116 // aligned hits, afterward removing the hits already clustered. The hit count
117 // keeps small all the time: we use a signed char as basic data type for
118 // the counters, allowing a maximum of 127 aligned hits. This saves a lot of
119 // memory, at the cost of a small slow-down for large (e.g. 64-bit) bus
120 // architectures. No check is performed for overflow; that can also be
121 // implemented at a small cost.
122 //
123 //
125 #ifndef HOUGHBASEALG_H
126 #define HOUGHBASEALG_H
127 
128 #include <vector>
129 #include <array>
130 #include <map>
131 #include <utility> // std::pair<>
132 
133 #include <TMath.h>
134 
135 #include "fhiclcpp/ParameterSet.h"
137 
139 //--- BEGIN issue #19494 -------------------------------------------------------
140 // BulkAllocator.h is currently broken; see issue #19494.
141 // When the issue is solved, this may or may not be restored, depending on the
142 // solution.
143 #if 0
145 #endif // 0
146 //--- END issue #19494 ---------------------------------------------------------
147 
149 
150 namespace art { class Event; }
151 
152 namespace recob {
153  class Hit;
154  class Cluster;
155 }
156 
157  struct houghCorner
158  {
159  double strength=0;
160  double p0=0;
161  double p1=0;
162  houghCorner(double strengthTemp=0,
163  double p0Temp=0,
164  double p1Temp=0)
165  {
166  strength=strengthTemp;
167  p0=p0Temp;
168  p1=p1Temp;
169  }
170 
171  bool operator < (const houghCorner& houghCornerComp) const
172  {
173  return (strength < houghCornerComp.strength);
174  }
175  };
176 
177 
178  // This stores information about merged lines
179  struct mergedLines
180  {
181  double totalQ=0;
182  double pMin0=0;
183  double pMin1=0;
184  double pMax0=0;
185  double pMax1=0;
186  int clusterNumber=-999999;
187  double showerLikeness=0;
188  mergedLines (double totalQTemp=0,
189  double pMin0Temp=0,
190  double pMin1Temp=0,
191  double pMax0Temp=0,
192  double pMax1Temp=0,
193  double clusterNumberTemp=-999999,
194  double showerLikenessTemp=0)
195  {
196  totalQ=totalQTemp;
197  pMin0=pMin0Temp;
198  pMin1=pMin1Temp;
199  pMax0=pMax0Temp;
200  pMax1=pMax1Temp;
201  clusterNumber=clusterNumberTemp;
202  showerLikeness=showerLikenessTemp;
203  }
204  };
205 
206 
207 
208  struct protoTrack
209  {
210  int clusterNumber=999999;
211  int planeNumber=999999;
212  int oldClusterNumber=999999;
213  float clusterSlope=999999;
214  float clusterIntercept=999999;
215  float totalQ=-999999;
216  float pMin0=999999;
217  float pMin1=999999;
218  float pMax0=-999999;
219  float pMax1=-999999;
220  float iMinWire=999999;
221  float iMaxWire=-999999;
222  float minWire=999999;
223  float maxWire=-999999;
224  float isolation=-999999;
225  float showerLikeness=-999999;
226  bool merged=false;
227  bool showerMerged=false;
228  bool mergedLeft=false;
229  bool mergedRight=false;
230  std::vector<art::Ptr<recob::Hit>> hits;
232  }
233 
234  void Init(unsigned int num=999999,
235  unsigned int pnum=999999,
236  float slope=999999,
237  float intercept=999999,
238  float totalQTemp=-999999,
239  float Min0=999999,
240  float Min1=999999,
241  float Max0=-999999,
242  float Max1=-999999,
243  int iMinWireTemp=999999,
244  int iMaxWireTemp=-999999,
245  int minWireTemp=999999,
246  int maxWireTemp=-999999,
248  {
249  clusterNumber = num;
250  planeNumber = pnum;
251  oldClusterNumber = num;
252  clusterSlope = slope;
253  clusterIntercept = intercept;
254  totalQ=totalQTemp;
255  pMin0 = Min0;
256  pMin1 = Min1;
257  pMax0 = Max0;
258  pMax1 = Max1;
259  iMinWire = iMinWireTemp;
260  iMaxWire = iMaxWireTemp;
261  minWire = minWireTemp;
262  maxWire = maxWireTemp;
263  merged = false;
264  showerMerged = false;
265  showerLikeness = 0;
266  hits.swap(hitsTemp);
267  }
268  };
269 
270 
271 namespace cluster {
272 
273 
286  template <
287  typename KEY,
288  typename COUNTER,
289  size_t SIZE,
290  typename ALLOC = std::allocator<std::pair<KEY,std::array<COUNTER, SIZE>>>,
291  unsigned int SUBCOUNTERS=1
292  >
294  public lar::CountersMap<KEY, COUNTER, SIZE, ALLOC, SUBCOUNTERS>
295  {
296  public:
297 
299  using CounterMap_t
303 
304  // import useful types
305  using BaseMap_t = typename Base_t::BaseMap_t;
307  using Key_t = typename Base_t::Key_t;
311 
313  using PairValue_t = std::pair<const_iterator, SubCounter_t>;
314 
317 
320 
321 
329  { return Base_t::set(key, value); }
330 
336  SubCounter_t increment(Key_t key) { return Base_t::increment(key); }
337 
343  SubCounter_t decrement(Key_t key) { return Base_t::decrement(key); }
344 
345 
354  SubCounter_t set(Key_t key_begin, Key_t key_end, SubCounter_t value)
355  { return unchecked_set_range(key_begin, key_end, value); }
356 
363  void increment(Key_t key_begin, Key_t key_end);
364 
365 
387  { return unchecked_add_range_max(key_begin, key_end, +1); }
388 
389 
404  PairValue_t increment_and_get_max
405  (Key_t key_begin, Key_t key_end, SubCounter_t current_max)
406  { return unchecked_add_range_max(key_begin, key_end, +1, current_max); }
407 
408 
415  void decrement(Key_t key_begin, Key_t key_end);
416 
417 
436  PairValue_t get_max(SubCounter_t current_max) const;
437 
450  PairValue_t get_max() const;
451 
452 
453  protected:
454 
456 
457 
458  private:
459 
460  SubCounter_t unchecked_set_range(
461  Key_t key_begin, Key_t key_end, SubCounter_t value,
462  typename BaseMap_t::iterator start
463  );
464  SubCounter_t unchecked_set_range
465  (Key_t key_begin, Key_t key_end, SubCounter_t value);
466  PairValue_t unchecked_add_range_max(
467  Key_t key_begin, Key_t key_end, SubCounter_t delta,
468  typename BaseMap_t::iterator start,
470  );
471  PairValue_t unchecked_add_range_max(
472  Key_t key_begin, Key_t key_end, SubCounter_t delta,
474  );
475 
476  }; // class HoughTransformCounters
477 
478 
479 #define FC_DEVELOP 0
480 
482  public:
483 
484  HoughTransform();
485  ~HoughTransform();
486 
487  void Init
488  (unsigned int dx, unsigned int dy, float rhores, unsigned int numACells);
489  std::array<int,3> AddPointReturnMax(int x, int y);
490  bool SubtractPoint(int x, int y);
491  int GetCell(int row, int col) const;
492  void SetCell(int row, int col, int value) { m_accum[row].set(col, value); }
493  void GetAccumSize(int &numRows, int &numCols)
494  {
495  numRows = m_accum.size();
496  numCols = (int) m_rowLength;
497  }
498  int NumAccumulated() { return m_numAccumulated; }
499  void GetEquation( float row, float col, float &rho, float &theta) const;
500  int GetMax(int & xmax, int & ymax) const;
501 
502  void reconfigure(fhicl::ParameterSet const& pset);
503 
504  private:
505 
508 
509  //--- BEGIN issue #19494 ---------------------------------------------------
510  // BulkAllocator.h is currently broken; see issue #19494 and comment above.
511 #if 0
514  BulkPairAllocator_t;
519 #else // !0
521 #endif // 0?
522  //--- END issue #19494 -----------------------------------------------------
523 
525  typedef std::vector<DistancesMap_t> HoughImage_t;
526 
527 
528  unsigned int m_dx;
529  unsigned int m_dy;
530  unsigned int m_rowLength;
531  unsigned int m_numAngleCells;
533  // Note, m_accum is a vector of associative containers,
534  // the vector elements are called by rho, theta is the container key,
535  // the number of hits is the value corresponding to the key
536  HoughImage_t m_accum;
538  std::vector<double> m_cosTable;
539  std::vector<double> m_sinTable;
540 
541  std::array<int,3> DoAddPointReturnMax(int x, int y, bool bSubtract = false);
542 
543 
544  }; // class HoughTransform
545 
546 
547 
548 
549 
550  class HoughBaseAlg {
551 
552  public:
553 
555  struct ChargeInfo_t {
556  float integral = 0.0F;
557  float integral_stddev = 0.0F;
558  float summedADC = 0.0F;
559  float summedADC_stddev = 0.0F;
560 
561  ChargeInfo_t(float in, float in_stdev, float sum, float sum_stdev):
562  integral(in), integral_stddev(in_stdev),
563  summedADC(sum), summedADC_stddev(sum_stdev)
564  {}
565  }; // ChargeInfo_t
566 
567 
568  HoughBaseAlg(fhicl::ParameterSet const& pset);
569  virtual ~HoughBaseAlg();
570 
571  size_t FastTransform(const std::vector<art::Ptr<recob::Cluster> > & clusIn,
572  std::vector<recob::Cluster> & ccol,
573  std::vector< art::PtrVector<recob::Hit> > & clusHitsOut,
574  art::Event const& evt,
575  std::string const& label);
576 
577  size_t Transform(std::vector<art::Ptr<recob::Hit> > const& hits,
578  std::vector<unsigned int> *fpointId_to_clusterId,
579  unsigned int clusterId, // The id of the cluster we are examining
580  unsigned int *nClusters,
581  std::vector<protoTrack> *protoTracks);
582 
583 
584  // interface to look for lines only on a set of hits,without slope and totalQ arrays
585  size_t FastTransform(
588  );
589 
590  // interface to look for lines only on a set of hits
591  size_t FastTransform(
594  std::vector<double> & slope,
595  std::vector<ChargeInfo_t> & totalQ
596  );
597 
598 
599  size_t Transform(std::vector<art::Ptr<recob::Hit> > const& hits);
600 
601  size_t Transform(std::vector< art::Ptr<recob::Hit> > const& hits,
602  double & slope,
603  double & intercept);
604 
605  virtual void reconfigure(fhicl::ParameterSet const& pset);
606 
607  protected:
608 
609  void HLSSaveBMPFile(char const*, unsigned char*, int, int);
610 
611  private:
612 
613  int fMaxLines;
614  int fMinHits;
615  int fSaveAccumulator;
618  float fMaxDistance;
622  float fMaxSlope;
627  int fMissedHits;
629  float fMissedHitsDistance;
632 
633  protected:
634 
635  friend class HoughTransformClus;
636  };
637 
638 
639 }// namespace
640 
641 #endif // HOUGHBASEALG_H
Float_t x
Definition: compare.C:6
typename Traits_t::CounterBlock_t CounterBlock_t
Definition: CountersMap.h:165
float fRhoResolutionFactor
Factor determining the resolution in rho.
Definition: HoughBaseAlg.h:625
Reconstruction base classes.
intermediate_table::iterator iterator
KEY Key_t
type of counter key in the map
Definition: CountersMap.h:147
std::vector< double > m_cosTable
Definition: HoughBaseAlg.h:538
Float_t y
Definition: compare.C:6
typename Base_t::CounterKey_t CounterKey_t
Definition: HoughBaseAlg.h:455
unsigned int m_numAngleCells
Definition: HoughBaseAlg.h:531
std::vector< DistancesMap_t > HoughImage_t
Type of the Hough transform (angle, distance) map with custom allocator.
Definition: HoughBaseAlg.h:525
Cluster finding and building.
std::pair< const_iterator, SubCounter_t > PairValue_t
Pair identifying a counter and its current value.
Definition: HoughBaseAlg.h:313
mergedLines(double totalQTemp=0, double pMin0Temp=0, double pMin1Temp=0, double pMax0Temp=0, double pMax1Temp=0, double clusterNumberTemp=-999999, double showerLikenessTemp=0)
Definition: HoughBaseAlg.h:188
Data structure collecting charge information to be filled in cluster.
Definition: HoughBaseAlg.h:555
unsigned int m_rowLength
Definition: HoughBaseAlg.h:530
void SetCell(int row, int col, int value)
Definition: HoughBaseAlg.h:492
int fMaxLines
Max number of lines that can be found.
Definition: HoughBaseAlg.h:613
ChargeInfo_t(float in, float in_stdev, float sum, float sum_stdev)
Definition: HoughBaseAlg.h:561
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
bool operator<(ProductInfo const &a, ProductInfo const &b)
Definition: ProductInfo.h:44
typename Traits_t::template BaseMap_t< typename std::allocator_traits< Allocator_t >::template rebind_alloc< typename Traits_t::MapValue_t > > BaseMap_t
Type of the map used in the implementation.
Definition: CountersMap.h:171
intermediate_table::const_iterator const_iterator
void GetAccumSize(int &numRows, int &numCols)
Definition: HoughBaseAlg.h:493
HoughTransformCounters(Allocator_t alloc)
Constructor, specifies an allocator.
Definition: HoughBaseAlg.h:319
Int_t col[ntarg]
Definition: Style.C:29
Aggressive allocator reserving a lot of memory in advance.
Definition: BulkAllocator.h:92
float fMaxSlope
Max slope a line can have.
Definition: HoughBaseAlg.h:622
Memory allocator for large amount of (small) objects.
SubCounter_t decrement(Key_t key)
Decrements by 1 the specified counter.
Definition: HoughBaseAlg.h:343
HoughTransformCounters()
Default constructor (empty map)
Definition: HoughBaseAlg.h:316
int fRhoZeroOutRange
Range in rho over which to zero out area around previously found lines in the accumulator.
Definition: HoughBaseAlg.h:623
double strength
Definition: HoughBaseAlg.h:159
CountersMap with access optimized for Hough Transform algorithm.
Definition: HoughBaseAlg.h:293
ALLOC Allocator_t
type of the single counter
Definition: CountersMap.h:149
Structure with the index of the counter, split as needed.
Definition: CountersMap.h:296
ifstream in
Definition: comparison.C:7
std::string value(boost::any const &)
HoughTransformCounters< int, signed char, 64 > BaseMap_t
rho -> # hits (for convenience)
Definition: HoughBaseAlg.h:507
Int_t min
Definition: plot.C:26
std::vector< art::Ptr< recob::Hit > > hits
Definition: HoughBaseAlg.h:230
HoughImage_t m_accum
column (map key)=rho, row (vector index)=theta
Definition: HoughBaseAlg.h:536
SubCounter_t increment(Key_t key)
Increments by 1 the specified counter.
Definition: HoughBaseAlg.h:336
void Init(unsigned int num=999999, unsigned int pnum=999999, float slope=999999, float intercept=999999, float totalQTemp=-999999, float Min0=999999, float Min1=999999, float Max0=-999999, float Max1=-999999, int iMinWireTemp=999999, int iMaxWireTemp=-999999, int minWireTemp=999999, int maxWireTemp=-999999, std::vector< art::Ptr< recob::Hit >> hitsTemp=std::vector< art::Ptr< recob::Hit >>())
Definition: HoughBaseAlg.h:234
HLT enums.
Map storing counters in a compact way.
Definition: CountersMap.h:138
std::vector< double > m_sinTable
Definition: HoughBaseAlg.h:539
Counter_t SubCounter_t
Type of the subcounter (that is, the actual counter)
Definition: CountersMap.h:162
Map of counters, stored compactly.
TCEvent evt
Definition: DataStructs.cxx:5
int fThetaZeroOutRange
Range in theta over which to zero out area around previously found lines in the accumulator.
Definition: HoughBaseAlg.h:624
typename Base_t::const_iterator const_iterator
Definition: HoughBaseAlg.h:310
PairValue_t increment_and_get_max(Key_t key_begin, Key_t key_end)
Increments by 1 the specified counters and returns the maximum.
Definition: HoughBaseAlg.h:386
houghCorner(double strengthTemp=0, double p0Temp=0, double p1Temp=0)
Definition: HoughBaseAlg.h:162
float fMissedHitsToLineSize
Ratio of missed hits to line size for a line to be considered a fake.
Definition: HoughBaseAlg.h:631
HoughTransformCounters< int, signed char, 64 > DistancesMap_t
Definition: HoughBaseAlg.h:520