aimstil  5.0.5
connected_components.tpp
Go to the documentation of this file.
1 
2 
3 namespace til
4 {
5  //---------------------------------------------------------------------------
6 
7  template < typename TImage, typename TNeighborhood, typename TExtrapolator >
8  int connectedComponents(TImage &im, const TNeighborhood &nh)
9  {
10  // typdefs
11  typedef typename TImage::value_type value_type;
12 
13  // the "-1" is to be able to write tests for loops like
14  // i<=maxLabel that can actually be false
15  const int MAX_LABEL = (int) min(100000.0, double(std::numeric_limits<value_type>::max()) - 1);
16 
17  /*
18  // Set first slice to background
19  {
20  Range range = getRange(im); range.setZMax(0);
21  typename Iterator<TImage>::Volumetric iIm(im, range);
22  for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
23  }
24  // Set top border to background
25  {
26  Range range = getRange(im); range.setYMax(0);
27  typename Iterator<TImage>::Volumetric iIm(im, range);
28  for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
29  }
30  // Set left border to background
31  {
32  Range range = getRange(im); range.setXMax(0);
33  typename Iterator<TImage>::Volumetric iIm(im, range);
34  for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
35  }
36  */
37 
38  value_type neighborLabels[3*3*3]; // contains the labels of neighbors
39  for (int n=0; n<3*3*3; ++n) neighborLabels[n] = value_type(0);
40  int nLabeledNeighbors; // counts the number of labelled neighbors
41  value_type currentLabel = 0;
42 
43  // Allocate equivalence chain
44  EquivalenceChain lut(MAX_LABEL);
45 
46  // Allocate variables used in the loop
47  value_type minLabel;
48  #ifdef VERBOSE
49  int k, oldk = -1;
50  #endif
51 
52 
53  // For all pixels
54 
55  typename Iterator<TImage>::Volumetric iIm(im);
56  for (; !iIm.isAtEnd(); ++iIm)
57  {
58 
59  #ifdef VERBOSE
60  k = iIm.getZ();
61  if (oldk != k)
62  {
63  oldk = k;
64  std::cout << "Completed " << (int)((100.0 * k) / (im.getZ()-1) + 0.5) << "% \r" << std::flush;
65  }
66  #endif
67 
68  // If pixel is not background, it has to be labeled
69  if (*iIm != 0)
70  {
71  // Get and count labels of neighbors already processed
72  // Process only backward neighbors (13 out of 26)
73  nLabeledNeighbors = 0;
74 
75  SPAN_NEIGHBORS(-1,-1,-1)
76  SPAN_NEIGHBORS( 0,-1,-1)
77  SPAN_NEIGHBORS(+1,-1,-1)
78 
79  SPAN_NEIGHBORS(-1, 0,-1)
80  SPAN_NEIGHBORS( 0, 0,-1)
81  SPAN_NEIGHBORS(+1, 0,-1)
82 
83  SPAN_NEIGHBORS(-1,+1,-1)
84  SPAN_NEIGHBORS( 0,+1,-1)
85  SPAN_NEIGHBORS(+1,+1,-1)
86 
87  SPAN_NEIGHBORS(-1,-1, 0)
88  SPAN_NEIGHBORS( 0,-1, 0)
89  SPAN_NEIGHBORS(+1,-1, 0)
90 
91  SPAN_NEIGHBORS(-1, 0, 0)
92 
93 
94  // If no neighbor is labeled : create new label
95  if (nLabeledNeighbors == 0)
96  {
97  currentLabel = lut.getNewLabel();
98 
99  // Is label table full?
100  if (currentLabel == 0)
101  {
102  //std::cout << "Labels compressed" << std::endl;
103  value_type numberOfLabels = lut.mergeLabels();
104 
105  typename Iterator<TImage>::Linear iTmp(im);
106  iTmp.setEnd(iIm.getIndex()-1);
107  for (; !iTmp.isAtEnd(); ++iTmp)
108  {
109  if (*iTmp)
110  {
111  *iTmp = lut[*iTmp];
112  }
113  }
114 
115  lut.reset(numberOfLabels);
116  currentLabel = lut.getNewLabel();
117 
118  // Table is still full after label merging: error
119  if (currentLabel == 0)
120  {
121  throw std::overflow_error("Too many regions");
122  }
123  }
124 
125  *iIm = currentLabel;
126  }
127  else
128  {
129  // Take the lowest label
130  minLabel = std::numeric_limits<value_type>::max();
131  for (int n=0; n<13; ++n)
132  {
133  if (neighborLabels[n] > 0 && neighborLabels[n] < minLabel)
134  {
135  minLabel = neighborLabels[n];
136  }
137  }
138 
139  *iIm = minLabel;
140 
141  // If there were more than one label, modify the look-up table
142  // to ensure that all labels correspond to the same region
143  if (nLabeledNeighbors >= 2)
144  {
145  int lastLabelCurrent = lut.getLastLabel(*iIm);
146 
147  for (int n=0; n<13; ++n)
148  {
149  if (neighborLabels[n] != 0)
150  {
151  lut.setEquivalence(neighborLabels[n], lastLabelCurrent);
152  }
153  }
154  }
155  }
156  }
157  }
158 
159 
160  // Merge all equivalent labels
161  lut.mergeLabels();
162 
163  // Update label image accordingly
164  for (typename Iterator<TImage>::Linear iTmp(im); !iTmp.isAtEnd(); ++iTmp)
165  {
166  if (*iTmp) *iTmp = lut[*iTmp];
167  }
168 
169  return lut.getGreatestLabel();
170  }
171 
172  //---------------------------------------------------------------------------
173 
174  template < typename TImage, typename TNeighborhood >
175  int connectedComponents(TImage &im, const TNeighborhood &nh)
176  {
177  return connectedComponents<TImage, TNeighborhood, ZeroExtrapolator>(im,nh);
178  }
179 
180  //---------------------------------------------------------------------------
181 
182 } // namespace til
183