You are on page 1of 4

1 template<typename LabelT, typename PixelT, typename StatsOp = NoOp >

2 struct LabelingImpl{
3 LabelT operator()(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp &sop){
4 CV_Assert(L.rows == I.rows);
5 CV_Assert(L.cols == I.cols);
6 CV_Assert(connectivity == 8 || connectivity == 4);
7 const int rows = L.rows;
8 const int cols = L.cols;
9 size_t Plength = (size_t(rows + 3 - 1)/3) * (size_t(cols + 3 - 1)/3);
10 if(connectivity == 4){
11 Plength = 4 * Plength;//a quick and dirty upper bound, an exact answer
exists if you want to find it
12 //the 4 comes from the fact that a 3x3 block can never have more than 4
unique labels
13 }
14 LabelT *P = (LabelT *) fastMalloc(sizeof(LabelT) * Plength);
15 P[0] = 0;
16 LabelT lunique = 1;
17 //scanning phase
18 for(int r_i = 0; r_i < rows; ++r_i){
19 LabelT *Lrow = (LabelT *)(L.data + L.step.p[0] * r_i);
20 LabelT *Lrow_prev = (LabelT *)(((char *)Lrow) - L.step.p[0]);
21 const PixelT *Irow = (PixelT *)(I.data + I.step.p[0] * r_i);
22 const PixelT *Irow_prev = (const PixelT *)(((char *)Irow) - I.step.p[0]);
23 LabelT *Lrows[2] = {
24 Lrow,
25 Lrow_prev
26 };
27 const PixelT *Irows[2] = {
28 Irow,
29 Irow_prev
30 };
31 if(connectivity == 8){
32 const int a = 0;
33 const int b = 1;
34 const int c = 2;
35 const int d = 3;
36 const bool T_a_r = (r_i - G8[a][0]) >= 0;
37 const bool T_b_r = (r_i - G8[b][0]) >= 0;
38 const bool T_c_r = (r_i - G8[c][0]) >= 0;
39 for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){
40 if(!*Irows[0]){
41 Lrow[c_i] = 0;
42 continue;
43 }
44 Irows[1] = Irow_prev + c_i;
45 Lrows[0] = Lrow + c_i;
46 Lrows[1] = Lrow_prev + c_i;
47 const bool T_a = T_a_r && (c_i + G8[a][1]) >= 0 &&
*(Irows[G8[a][0]] + G8[a][1]);
48 const bool T_b = T_b_r &&
*(Irows[G8[b][0]] + G8[b][1]);
49 const bool T_c = T_c_r && (c_i + G8[c][1]) < cols &&
*(Irows[G8[c][0]] + G8[c][1]);
50 const bool T_d = (c_i + G8[d][1]) >= 0 &&
*(Irows[G8[d][0]] + G8[d][1]);
51
52 //decision tree
53 if(T_b){
54 //copy(b)
55 *Lrows[0] = *(Lrows[G8[b][0]] + G8[b][1]);
56 }else{//not b
57 if(T_c){
58 if(T_a){
59 //copy(c, a)
60 *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] +
G8[c][1]), *(Lrows[G8[a][0]] + G8[a][1]));
61 }else{
62 if(T_d){
63 //copy(c, d)
64 *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] +
G8[c][1]), *(Lrows[G8[d][0]] + G8[d][1]));
65 }else{
66 //copy(c)
67 *Lrows[0] = *(Lrows[G8[c][0]] + G8[c][1]);
68 }
69 }
70 }else{//not c
71 if(T_a){
72 //copy(a)
73 *Lrows[0] = *(Lrows[G8[a][0]] + G8[a][1]);
74 }else{
75 if(T_d){
76 //copy(d)
77 *Lrows[0] = *(Lrows[G8[d][0]] + G8[d][1]);
78 }else{
79 //new label
80 *Lrows[0] = lunique;
81 P[lunique] = lunique;
82 lunique = lunique + 1;
83 }
84 }
85 }
86 }
87 }
88 }else{
89 //B & D only
90 const int b = 0;
91 const int d = 1;
92 const bool T_b_r = (r_i - G4[b][0]) >= 0;
93 for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){
94 if(!*Irows[0]){
95 Lrow[c_i] = 0;
96 continue;
97 }
98 Irows[1] = Irow_prev + c_i;
99 Lrows[0] = Lrow + c_i;
100 Lrows[1] = Lrow_prev + c_i;
101 const bool T_b = T_b_r &&
*(Irows[G4[b][0]] + G4[b][1]);
102 const bool T_d = (c_i + G4[d][1]) >= 0 &&
*(Irows[G4[d][0]] + G4[d][1]);
103 if(T_b){
104 if(T_d){
105 //copy(d, b)
106 *Lrows[0] = set_union(P, *(Lrows[G4[d][0]] + G4[d][1]),
*(Lrows[G4[b][0]] + G4[b][1]));
107 }else{
108 //copy(b)
109 *Lrows[0] = *(Lrows[G4[b][0]] + G4[b][1]);
110 }
111 }else{
112 if(T_d){
113 //copy(d)
114 *Lrows[0] = *(Lrows[G4[d][0]] + G4[d][1]);
115 }else{
116 //new label
117 *Lrows[0] = lunique;
118 P[lunique] = lunique;
119 lunique = lunique + 1;
120 }
121 }
122 }
123 }
124 }
125
126 //analysis
127 LabelT nLabels = flattenL(P, lunique);
128 sop.init(nLabels);
129
130 for(int r_i = 0; r_i < rows; ++r_i){
131 LabelT *Lrow_start = (LabelT *)(L.data + L.step.p[0] * r_i);
132 LabelT *Lrow_end = Lrow_start + cols;
133 LabelT *Lrow = Lrow_start;
134 for(int c_i = 0; Lrow != Lrow_end; ++Lrow, ++c_i){
135 const LabelT l = P[*Lrow];
136 *Lrow = l;
137 sop(r_i, c_i, l);
138 }
139 }
140
141 sop.finish();
142 fastFree(P);
143
144 return nLabels;
145 }//End function LabelingImpl operator()
146
147 };//End struct LabelingImpl
148 }//end namespace connectedcomponents
149
150 //L's type must have an appropriate depth for the number of pixels in I
151 template<typename StatsOp>
152 static
153 int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp
&sop){
154 CV_Assert(L.channels() == 1 && I.channels() == 1);
155 CV_Assert(connectivity == 8 || connectivity == 4);
156
157 int lDepth = L.depth();
158 int iDepth = I.depth();
159 using connectedcomponents::LabelingImpl;
160 //warn if L's depth is not sufficient?
161
162 CV_Assert(iDepth == CV_8U || iDepth == CV_8S);
163
164 if(lDepth == CV_8U){
165 return (int) LabelingImpl<uchar, uchar, StatsOp>()(I, L, connectivity, sop);
166 }else if(lDepth == CV_16U){
167 return (int) LabelingImpl<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
168 }else if(lDepth == CV_32S){
169 //note that signed types don't really make sense here and not being able to
use unsigned matters for scientific projects
170 //OpenCV: how should we proceed? .at<T> typechecks in debug mode
171 return (int) LabelingImpl<int, uchar, StatsOp>()(I, L, connectivity, sop);
172 }
173
174 CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");
175 return -1;
176 }
177
178 }
179
180 int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivity,
int ltype){
181 const cv::Mat img = _img.getMat();
182 _labels.create(img.size(), CV_MAT_DEPTH(ltype));
183 cv::Mat labels = _labels.getMat();
184 connectedcomponents::NoOp sop;
185 if(ltype == CV_16U){
186 return connectedComponents_sub1(img, labels, connectivity, sop);
187 }else if(ltype == CV_32S){
188 return connectedComponents_sub1(img, labels, connectivity, sop);
189 }else{
190 CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
191 return 0;
192 }
193 }
194
195 int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels,
OutputArray statsv,
196 OutputArray centroids, int connectivity, int
ltype)
197 {
198 const cv::Mat img = _img.getMat();
199 _labels.create(img.size(), CV_MAT_DEPTH(ltype));
200 cv::Mat labels = _labels.getMat();
201 connectedcomponents::CCStatsOp sop(statsv, centroids);
202 if(ltype == CV_16U){
203 return connectedComponents_sub1(img, labels, connectivity, sop);
204 }else if(ltype == CV_32S){
205 return connectedComponents_sub1(img, labels, connectivity, sop);
206 }else{
207 CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
208 return 0;
209 }
210 }

You might also like