5 //---------------------------------------------------------------------------
7 template < typename TImage, typename TNeighborhood, typename TExtrapolator >
8 int connectedComponents(TImage &im, const TNeighborhood &nh)
11 typedef typename TImage::value_type value_type;
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);
18 // Set first slice to background
20 Range range = getRange(im); range.setZMax(0);
21 typename Iterator<TImage>::Volumetric iIm(im, range);
22 for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
24 // Set top border to background
26 Range range = getRange(im); range.setYMax(0);
27 typename Iterator<TImage>::Volumetric iIm(im, range);
28 for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
30 // Set left border to background
32 Range range = getRange(im); range.setXMax(0);
33 typename Iterator<TImage>::Volumetric iIm(im, range);
34 for(; !iIm.isAtEnd(); ++iIm) { *iIm = 0; }
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;
43 // Allocate equivalence chain
44 EquivalenceChain lut(MAX_LABEL);
46 // Allocate variables used in the loop
55 typename Iterator<TImage>::Volumetric iIm(im);
56 for (; !iIm.isAtEnd(); ++iIm)
64 std::cout << "Completed " << (int)((100.0 * k) / (im.getZ()-1) + 0.5) << "% \r" << std::flush;
68 // If pixel is not background, it has to be labeled
71 // Get and count labels of neighbors already processed
72 // Process only backward neighbors (13 out of 26)
73 nLabeledNeighbors = 0;
75 SPAN_NEIGHBORS(-1,-1,-1)
76 SPAN_NEIGHBORS( 0,-1,-1)
77 SPAN_NEIGHBORS(+1,-1,-1)
79 SPAN_NEIGHBORS(-1, 0,-1)
80 SPAN_NEIGHBORS( 0, 0,-1)
81 SPAN_NEIGHBORS(+1, 0,-1)
83 SPAN_NEIGHBORS(-1,+1,-1)
84 SPAN_NEIGHBORS( 0,+1,-1)
85 SPAN_NEIGHBORS(+1,+1,-1)
87 SPAN_NEIGHBORS(-1,-1, 0)
88 SPAN_NEIGHBORS( 0,-1, 0)
89 SPAN_NEIGHBORS(+1,-1, 0)
91 SPAN_NEIGHBORS(-1, 0, 0)
94 // If no neighbor is labeled : create new label
95 if (nLabeledNeighbors == 0)
97 currentLabel = lut.getNewLabel();
99 // Is label table full?
100 if (currentLabel == 0)
102 //std::cout << "Labels compressed" << std::endl;
103 value_type numberOfLabels = lut.mergeLabels();
105 typename Iterator<TImage>::Linear iTmp(im);
106 iTmp.setEnd(iIm.getIndex()-1);
107 for (; !iTmp.isAtEnd(); ++iTmp)
115 lut.reset(numberOfLabels);
116 currentLabel = lut.getNewLabel();
118 // Table is still full after label merging: error
119 if (currentLabel == 0)
121 throw std::overflow_error("Too many regions");
129 // Take the lowest label
130 minLabel = std::numeric_limits<value_type>::max();
131 for (int n=0; n<13; ++n)
133 if (neighborLabels[n] > 0 && neighborLabels[n] < minLabel)
135 minLabel = neighborLabels[n];
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)
145 int lastLabelCurrent = lut.getLastLabel(*iIm);
147 for (int n=0; n<13; ++n)
149 if (neighborLabels[n] != 0)
151 lut.setEquivalence(neighborLabels[n], lastLabelCurrent);
160 // Merge all equivalent labels
163 // Update label image accordingly
164 for (typename Iterator<TImage>::Linear iTmp(im); !iTmp.isAtEnd(); ++iTmp)
166 if (*iTmp) *iTmp = lut[*iTmp];
169 return lut.getGreatestLabel();
172 //---------------------------------------------------------------------------
174 template < typename TImage, typename TNeighborhood >
175 int connectedComponents(TImage &im, const TNeighborhood &nh)
177 return connectedComponents<TImage, TNeighborhood, ZeroExtrapolator>(im,nh);
180 //---------------------------------------------------------------------------