Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgproc/src/connectedcomponents.cpp
16354 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// Intel License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Third party copyrights are property of their respective owners.
15
//
16
// Redistribution and use in source and binary forms, with or without modification,
17
// are permitted provided that the following conditions are met:
18
//
19
// * Redistribution's of source code must retain the above copyright notice,
20
// this list of conditions and the following disclaimer.
21
//
22
// * Redistribution's in binary form must reproduce the above copyright notice,
23
// this list of conditions and the following disclaimer in the documentation
24
// and/or other materials provided with the distribution.
25
//
26
// * The name of Intel Corporation may not be used to endorse or promote products
27
// derived from this software without specific prior written permission.
28
//
29
// This software is provided by the copyright holders and contributors "as is" and
30
// any express or implied warranties, including, but not limited to, the implied
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
33
// indirect, incidental, special, exemplary, or consequential damages
34
// (including, but not limited to, procurement of substitute goods or services;
35
// loss of use, data, or profits; or business interruption) however caused
36
// and on any theory of liability, whether in contract, strict liability,
37
// or tort (including negligence or otherwise) arising in any way out of
38
// the use of this software, even if advised of the possibility of such damage.
39
//
40
// 2011 Jason Newton <[email protected]>
41
// 2016 Costantino Grama <[email protected]>
42
// 2016 Federico Bolelli <[email protected]>
43
// 2016 Lorenzo Baraldi <[email protected]>
44
// 2016 Roberto Vezzani <[email protected]>
45
// 2016 Michele Cancilla <[email protected]>
46
//M*/
47
//
48
#include "precomp.hpp"
49
#include <vector>
50
51
namespace cv{
52
namespace connectedcomponents{
53
54
struct NoOp{
55
NoOp(){
56
}
57
58
inline
59
void init(int /*labels*/){
60
}
61
62
inline
63
void initElement(const int /*nlabels*/){
64
}
65
66
inline
67
void operator()(int r, int c, int l){
68
CV_UNUSED(r);
69
CV_UNUSED(c);
70
CV_UNUSED(l);
71
}
72
73
void finish(){
74
}
75
76
inline
77
void setNextLoc(const int /*nextLoc*/){
78
}
79
80
inline static
81
void mergeStats(const cv::Mat& /*imgLabels*/, NoOp * /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){
82
}
83
84
};
85
struct Point2ui64{
86
uint64 x, y;
87
Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){}
88
};
89
90
struct CCStatsOp{
91
const _OutputArray *_mstatsv;
92
cv::Mat statsv;
93
const _OutputArray *_mcentroidsv;
94
cv::Mat centroidsv;
95
std::vector<Point2ui64> integrals;
96
int _nextLoc;
97
98
CCStatsOp() : _mstatsv(0), _mcentroidsv(0), _nextLoc(0) {}
99
CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv), _nextLoc(0){}
100
101
inline
102
void init(int nlabels){
103
_mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType<int>::type);
104
statsv = _mstatsv->getMat();
105
_mcentroidsv->create(cv::Size(2, nlabels), cv::DataType<double>::type);
106
centroidsv = _mcentroidsv->getMat();
107
108
for (int l = 0; l < (int)nlabels; ++l){
109
int *row = (int *)&statsv.at<int>(l, 0);
110
row[CC_STAT_LEFT] = INT_MAX;
111
row[CC_STAT_TOP] = INT_MAX;
112
row[CC_STAT_WIDTH] = INT_MIN;
113
row[CC_STAT_HEIGHT] = INT_MIN;
114
row[CC_STAT_AREA] = 0;
115
}
116
integrals.resize(nlabels, Point2ui64(0, 0));
117
}
118
119
inline
120
void initElement(const int nlabels){
121
statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType<int>::type);
122
for (int l = 0; l < (int)nlabels; ++l){
123
int *row = (int *)statsv.ptr(l);
124
row[CC_STAT_LEFT] = INT_MAX;
125
row[CC_STAT_TOP] = INT_MAX;
126
row[CC_STAT_WIDTH] = INT_MIN;
127
row[CC_STAT_HEIGHT] = INT_MIN;
128
row[CC_STAT_AREA] = 0;
129
}
130
integrals.resize(nlabels, Point2ui64(0, 0));
131
}
132
133
void operator()(int r, int c, int l){
134
int *row =& statsv.at<int>(l, 0);
135
row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c);
136
row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c);
137
row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r);
138
row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r);
139
row[CC_STAT_AREA]++;
140
Point2ui64& integral = integrals[l];
141
integral.x += c;
142
integral.y += r;
143
}
144
145
void finish(){
146
for (int l = 0; l < statsv.rows; ++l){
147
int *row =& statsv.at<int>(l, 0);
148
row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1;
149
row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1;
150
151
Point2ui64& integral = integrals[l];
152
double *centroid = &centroidsv.at<double>(l, 0);
153
double area = ((unsigned*)row)[CC_STAT_AREA];
154
centroid[0] = double(integral.x) / area;
155
centroid[1] = double(integral.y) / area;
156
}
157
}
158
159
inline
160
void setNextLoc(const int nextLoc){
161
_nextLoc = nextLoc;
162
}
163
164
inline static
165
void mergeStats(const cv::Mat& imgLabels, CCStatsOp *sopArray, CCStatsOp& sop, const int& nLabels){
166
const int h = imgLabels.rows;
167
168
if (sop._nextLoc != h){
169
for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = sopArray[nextLoc]._nextLoc){
170
//merge between sopNext and sop
171
for (int l = 0; l < nLabels; ++l){
172
int *rowNext = (int*)sopArray[nextLoc].statsv.ptr(l);
173
if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats
174
int *rowMerged = (int*)sop.statsv.ptr(l);
175
rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]);
176
rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]);
177
rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]);
178
rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]);
179
rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA];
180
181
sop.integrals[l].x += sopArray[nextLoc].integrals[l].x;
182
sop.integrals[l].y += sopArray[nextLoc].integrals[l].y;
183
}
184
}
185
}
186
}
187
}
188
};
189
190
//Find the root of the tree of node i
191
template<typename LabelT>
192
inline static
193
LabelT findRoot(const LabelT *P, LabelT i){
194
LabelT root = i;
195
while (P[root] < root){
196
root = P[root];
197
}
198
return root;
199
}
200
201
//Make all nodes in the path of node i point to root
202
template<typename LabelT>
203
inline static
204
void setRoot(LabelT *P, LabelT i, LabelT root){
205
while (P[i] < i){
206
LabelT j = P[i];
207
P[i] = root;
208
i = j;
209
}
210
P[i] = root;
211
}
212
213
//Find the root of the tree of the node i and compress the path in the process
214
template<typename LabelT>
215
inline static
216
LabelT find(LabelT *P, LabelT i){
217
LabelT root = findRoot(P, i);
218
setRoot(P, i, root);
219
return root;
220
}
221
222
//unite the two trees containing nodes i and j and return the new root
223
template<typename LabelT>
224
inline static
225
LabelT set_union(LabelT *P, LabelT i, LabelT j){
226
LabelT root = findRoot(P, i);
227
if (i != j){
228
LabelT rootj = findRoot(P, j);
229
if (root > rootj){
230
root = rootj;
231
}
232
setRoot(P, j, root);
233
}
234
setRoot(P, i, root);
235
return root;
236
}
237
238
//Flatten the Union Find tree and relabel the components
239
template<typename LabelT>
240
inline static
241
LabelT flattenL(LabelT *P, LabelT length){
242
LabelT k = 1;
243
for (LabelT i = 1; i < length; ++i){
244
if (P[i] < i){
245
P[i] = P[P[i]];
246
}
247
else{
248
P[i] = k; k = k + 1;
249
}
250
}
251
return k;
252
}
253
254
template<typename LabelT>
255
inline static
256
void flattenL(LabelT *P, const int start, const int nElem, LabelT& k){
257
for (int i = start; i < start + nElem; ++i){
258
if (P[i] < i){//node that point to root
259
P[i] = P[P[i]];
260
}
261
else{ //for root node
262
P[i] = k;
263
k = k + 1;
264
}
265
}
266
}
267
268
//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
269
//using decision trees
270
//Kesheng Wu, et al
271
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
272
struct LabelingWuParallel{
273
274
class FirstScan8Connectivity : public cv::ParallelLoopBody{
275
const cv::Mat& img_;
276
cv::Mat& imgLabels_;
277
LabelT *P_;
278
int *chunksSizeAndLabels_;
279
280
public:
281
FirstScan8Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)
282
: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}
283
284
FirstScan8Connectivity& operator=(const FirstScan8Connectivity& ) { return *this; }
285
286
void operator()(const cv::Range& range) const CV_OVERRIDE
287
{
288
int r = range.start;
289
chunksSizeAndLabels_[r] = range.end;
290
291
LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1;
292
293
const LabelT firstLabel = label;
294
const int w = img_.cols;
295
const int limitLine = r, startR = r;
296
297
// Rosenfeld Mask
298
// +-+-+-+
299
// |p|q|r|
300
// +-+-+-+
301
// |s|x|
302
// +-+-+
303
for (; r != range.end; ++r)
304
{
305
PixelT const * const img_row = img_.ptr<PixelT>(r);
306
PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);
307
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
308
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);
309
for (int c = 0; c < w; ++c) {
310
311
#define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0
312
#define condition_q r > limitLine && img_row_prev[c] > 0
313
#define condition_r c < w - 1 && r > limitLine && img_row_prev[c + 1] > 0
314
#define condition_s c > 0 && img_row[c - 1] > 0
315
#define condition_x img_row[c] > 0
316
317
if (condition_x){
318
if (condition_q){
319
//copy q
320
imgLabels_row[c] = imgLabels_row_prev[c];
321
}
322
else{
323
//not q
324
if (condition_r){
325
if (condition_p){
326
//concavity p->x->r. Merge
327
imgLabels_row[c] = set_union(P_, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]);
328
}
329
else{ //not p and q
330
if (condition_s){
331
//step s->x->r. Merge
332
imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]);
333
}
334
else{ //not p, q and s
335
//copy r
336
imgLabels_row[c] = imgLabels_row_prev[c + 1];
337
}
338
}
339
}
340
else{
341
//not r and q
342
if (condition_p){
343
//copy p
344
imgLabels_row[c] = imgLabels_row_prev[c - 1];
345
}
346
else{//not r,q and p
347
if (condition_s){
348
imgLabels_row[c] = imgLabels_row[c - 1];
349
}
350
else{
351
//new label
352
imgLabels_row[c] = label;
353
P_[label] = label;
354
label = label + 1;
355
}
356
}
357
}
358
}
359
}
360
else{
361
//x is a background pixel
362
imgLabels_row[c] = 0;
363
}
364
}
365
}
366
//write in the follower memory location
367
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
368
}
369
#undef condition_p
370
#undef condition_q
371
#undef condition_r
372
#undef condition_s
373
#undef condition_x
374
};
375
376
class FirstScan4Connectivity : public cv::ParallelLoopBody{
377
const cv::Mat& img_;
378
cv::Mat& imgLabels_;
379
LabelT *P_;
380
int *chunksSizeAndLabels_;
381
382
public:
383
FirstScan4Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)
384
: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}
385
386
FirstScan4Connectivity& operator=(const FirstScan4Connectivity& ) { return *this; }
387
388
void operator()(const cv::Range& range) const CV_OVERRIDE
389
{
390
int r = range.start;
391
chunksSizeAndLabels_[r] = range.end;
392
393
LabelT label = LabelT((r * imgLabels_.cols + 1) / 2 + 1);
394
395
const LabelT firstLabel = label;
396
const int w = img_.cols;
397
const int limitLine = r, startR = r;
398
399
// Rosenfeld Mask
400
// +-+-+-+
401
// |-|q|-|
402
// +-+-+-+
403
// |s|x|
404
// +-+-+
405
for (; r != range.end; ++r){
406
PixelT const * const img_row = img_.ptr<PixelT>(r);
407
PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);
408
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
409
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);
410
for (int c = 0; c < w; ++c) {
411
412
#define condition_q r > limitLine && img_row_prev[c] > 0
413
#define condition_s c > 0 && img_row[c - 1] > 0
414
#define condition_x img_row[c] > 0
415
416
if (condition_x){
417
if (condition_q){
418
if (condition_s){
419
//step s->x->q. Merge
420
imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c]);
421
}
422
else{
423
//copy q
424
imgLabels_row[c] = imgLabels_row_prev[c];
425
}
426
}
427
else{
428
if (condition_s){ // copy s
429
imgLabels_row[c] = imgLabels_row[c - 1];
430
}
431
else{
432
//new label
433
imgLabels_row[c] = label;
434
P_[label] = label;
435
label = label + 1;
436
}
437
}
438
}
439
else{
440
//x is a background pixel
441
imgLabels_row[c] = 0;
442
}
443
}
444
}
445
//write in the following memory location
446
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
447
}
448
#undef condition_q
449
#undef condition_s
450
#undef condition_x
451
};
452
453
class SecondScan : public cv::ParallelLoopBody{
454
cv::Mat& imgLabels_;
455
const LabelT *P_;
456
StatsOp& sop_;
457
StatsOp *sopArray_;
458
LabelT& nLabels_;
459
public:
460
SecondScan(cv::Mat& imgLabels, const LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels)
461
: imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){}
462
463
SecondScan& operator=(const SecondScan& ) { return *this; }
464
465
void operator()(const cv::Range& range) const CV_OVERRIDE
466
{
467
int r = range.start;
468
const int rowBegin = r;
469
const int rowEnd = range.end;
470
471
if (rowBegin > 0){
472
sopArray_[rowBegin].initElement(nLabels_);
473
sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd;
474
475
for (; r < rowEnd; ++r) {
476
LabelT * img_row_start = imgLabels_.ptr<LabelT>(r);
477
LabelT * const img_row_end = img_row_start + imgLabels_.cols;
478
for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){
479
*img_row_start = P_[*img_row_start];
480
sopArray_[rowBegin](r, c, *img_row_start);
481
}
482
}
483
}
484
else{
485
//the first thread uses sop in order to make less merges
486
sop_.setNextLoc(rowEnd);
487
for (; r < rowEnd; ++r) {
488
LabelT * img_row_start = imgLabels_.ptr<LabelT>(r);
489
LabelT * const img_row_end = img_row_start + imgLabels_.cols;
490
for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){
491
*img_row_start = P_[*img_row_start];
492
sop_(r, c, *img_row_start);
493
}
494
}
495
}
496
}
497
};
498
499
inline static
500
void mergeLabels8Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){
501
502
// Merge Mask
503
// +-+-+-+
504
// |p|q|r|
505
// +-+-+-+
506
// |x|
507
// +-+
508
const int w = imgLabels.cols, h = imgLabels.rows;
509
510
for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){
511
512
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
513
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
514
515
for (int c = 0; c < w; ++c){
516
517
#define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0
518
#define condition_q imgLabels_row_prev[c] > 0
519
#define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0
520
#define condition_x imgLabels_row[c] > 0
521
522
if (condition_x){
523
if (condition_p){
524
//merge of two label
525
imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row[c]);
526
}
527
if (condition_r){
528
//merge of two label
529
imgLabels_row[c] = set_union(P, imgLabels_row_prev[c + 1], imgLabels_row[c]);
530
}
531
if (condition_q){
532
//merge of two label
533
imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]);
534
}
535
}
536
}
537
}
538
#undef condition_p
539
#undef condition_q
540
#undef condition_r
541
#undef condition_x
542
}
543
544
inline static
545
void mergeLabels4Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){
546
547
// Merge Mask
548
// +-+-+-+
549
// |-|q|-|
550
// +-+-+-+
551
// |x|
552
// +-+
553
const int w = imgLabels.cols, h = imgLabels.rows;
554
555
for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){
556
557
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
558
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
559
560
for (int c = 0; c < w; ++c){
561
562
#define condition_q imgLabels_row_prev[c] > 0
563
#define condition_x imgLabels_row[c] > 0
564
565
if (condition_x){
566
if (condition_q){
567
//merge of two label
568
imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]);
569
}
570
}
571
}
572
}
573
#undef condition_q
574
#undef condition_x
575
}
576
577
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
578
CV_Assert(img.rows == imgLabels.rows);
579
CV_Assert(img.cols == imgLabels.cols);
580
CV_Assert(connectivity == 8 || connectivity == 4);
581
582
const int h = img.rows;
583
const int w = img.cols;
584
585
//A quick and dirty upper bound for the maximum number of labels.
586
//Following formula comes from the fact that a 2x2 block in 4-way connectivity
587
//labeling can never have more than 2 new labels and 1 label for background.
588
//Worst case image example pattern:
589
//1 0 1 0 1...
590
//0 1 0 1 0...
591
//1 0 1 0 1...
592
//............
593
//Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling
594
const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;
595
596
//Array used to store info and labeled pixel by each thread.
597
//Different threads affect different memory location of chunksSizeAndLabels
598
int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));
599
600
//Tree of labels
601
LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));
602
//First label is for background
603
P[0] = 0;
604
605
cv::Range range(0, h);
606
const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4));
607
608
LabelT nLabels = 1;
609
610
if (connectivity == 8){
611
//First scan
612
cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);
613
614
//merge labels of different chunks
615
mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels);
616
617
for (int i = 0; i < h; i = chunksSizeAndLabels[i]){
618
flattenL(P, int((i + 1) / 2) * int((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels);
619
}
620
}
621
else{
622
//First scan
623
cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);
624
625
//merge labels of different chunks
626
mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels);
627
628
for (int i = 0; i < h; i = chunksSizeAndLabels[i]){
629
flattenL(P, int(i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels);
630
}
631
}
632
633
//Array for statistics dataof threads
634
StatsOp *sopArray = new StatsOp[h];
635
636
sop.init(nLabels);
637
//Second scan
638
cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nParallelStripes);
639
StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);
640
sop.finish();
641
642
delete[] sopArray;
643
cv::fastFree(chunksSizeAndLabels);
644
cv::fastFree(P);
645
return nLabels;
646
}
647
};//End struct LabelingWuParallel
648
649
650
//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
651
//using decision trees
652
//Kesheng Wu, et al
653
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
654
struct LabelingWu{
655
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
656
CV_Assert(imgLabels.rows == img.rows);
657
CV_Assert(imgLabels.cols == img.cols);
658
CV_Assert(connectivity == 8 || connectivity == 4);
659
660
const int h = img.rows;
661
const int w = img.cols;
662
663
//A quick and dirty upper bound for the maximum number of labels.
664
//Following formula comes from the fact that a 2x2 block in 4-way connectivity
665
//labeling can never have more than 2 new labels and 1 label for background.
666
//Worst case image example pattern:
667
//1 0 1 0 1...
668
//0 1 0 1 0...
669
//1 0 1 0 1...
670
//............
671
//Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling
672
const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;
673
//array P for equivalences resolution
674
LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);
675
//first label is for background pixels
676
P[0] = 0;
677
LabelT lunique = 1;
678
679
if (connectivity == 8){
680
for (int r = 0; r < h; ++r){
681
// Get row pointers
682
PixelT const * const img_row = img.ptr<PixelT>(r);
683
PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
684
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
685
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
686
687
for (int c = 0; c < w; ++c){
688
689
#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0
690
#define condition_q r>0 && img_row_prev[c]>0
691
#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0
692
#define condition_s c > 0 && img_row[c - 1] > 0
693
#define condition_x img_row[c] > 0
694
695
if (condition_x){
696
if (condition_q){
697
//x <- q
698
imgLabels_row[c] = imgLabels_row_prev[c];
699
}
700
else{
701
// q = 0
702
if (condition_r){
703
if (condition_p){
704
// x <- merge(p,r)
705
imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]);
706
}
707
else{
708
// p = q = 0
709
if (condition_s){
710
// x <- merge(s,r)
711
imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]);
712
}
713
else{
714
// p = q = s = 0
715
// x <- r
716
imgLabels_row[c] = imgLabels_row_prev[c + 1];
717
}
718
}
719
}
720
else{
721
// r = q = 0
722
if (condition_p){
723
// x <- p
724
imgLabels_row[c] = imgLabels_row_prev[c - 1];
725
}
726
else{
727
// r = q = p = 0
728
if (condition_s){
729
imgLabels_row[c] = imgLabels_row[c - 1];
730
}
731
else{
732
//new label
733
imgLabels_row[c] = lunique;
734
P[lunique] = lunique;
735
lunique = lunique + 1;
736
}
737
}
738
}
739
}
740
}
741
else{
742
//x is a background pixel
743
imgLabels_row[c] = 0;
744
}
745
}
746
}
747
#undef condition_p
748
#undef condition_q
749
#undef condition_r
750
#undef condition_s
751
#undef condition_x
752
}
753
else{
754
for (int r = 0; r < h; ++r){
755
PixelT const * const img_row = img.ptr<PixelT>(r);
756
PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
757
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
758
LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
759
for (int c = 0; c < w; ++c) {
760
761
#define condition_q r > 0 && img_row_prev[c] > 0
762
#define condition_s c > 0 && img_row[c - 1] > 0
763
#define condition_x img_row[c] > 0
764
765
if (condition_x){
766
if (condition_q){
767
if (condition_s){
768
//Merge s->x->q
769
imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]);
770
}
771
else{
772
//copy q
773
imgLabels_row[c] = imgLabels_row_prev[c];
774
}
775
}
776
else{
777
if (condition_s){
778
// copy s
779
imgLabels_row[c] = imgLabels_row[c - 1];
780
}
781
else{
782
//new label
783
imgLabels_row[c] = lunique;
784
P[lunique] = lunique;
785
lunique = lunique + 1;
786
}
787
}
788
}
789
else{
790
//x is a background pixel
791
imgLabels_row[c] = 0;
792
}
793
}
794
}
795
#undef condition_q
796
#undef condition_s
797
#undef condition_x
798
}
799
800
//analysis
801
LabelT nLabels = flattenL(P, lunique);
802
sop.init(nLabels);
803
804
for (int r = 0; r < h; ++r) {
805
LabelT * img_row_start = imgLabels.ptr<LabelT>(r);
806
LabelT * const img_row_end = img_row_start + w;
807
for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){
808
*img_row_start = P[*img_row_start];
809
sop(r, c, *img_row_start);
810
}
811
}
812
813
sop.finish();
814
fastFree(P);
815
816
return nLabels;
817
}//End function LabelingWu operator()
818
};//End struct LabelingWu
819
820
821
// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
822
// Only for 8-connectivity
823
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
824
struct LabelingGranaParallel{
825
826
class FirstScan : public cv::ParallelLoopBody{
827
private:
828
const cv::Mat& img_;
829
cv::Mat& imgLabels_;
830
LabelT *P_;
831
int *chunksSizeAndLabels_;
832
833
public:
834
FirstScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)
835
: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}
836
837
FirstScan& operator=(const FirstScan&) { return *this; }
838
839
void operator()(const cv::Range& range) const CV_OVERRIDE
840
{
841
int r = range.start;
842
r += (r % 2);
843
844
chunksSizeAndLabels_[r] = range.end + (range.end % 2);
845
846
LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1;
847
848
const LabelT firstLabel = label;
849
const int h = img_.rows, w = img_.cols;
850
const int limitLine = r + 1, startR = r;
851
852
for (; r < range.end; r += 2){
853
// Get rows pointer
854
const PixelT * const img_row = img_.ptr<uchar>(r);
855
const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);
856
const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img_.step.p[0]);
857
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
858
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
859
LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0] - imgLabels_.step.p[0]);
860
for (int c = 0; c < w; c += 2) {
861
862
// We work with 2x2 blocks
863
// +-+-+-+
864
// |P|Q|R|
865
// +-+-+-+
866
// |S|X|
867
// +-+-+
868
869
// The pixels are named as follows
870
// +---+---+---+
871
// |a b|c d|e f|
872
// |g h|i j|k l|
873
// +---+---+---+
874
// |m n|o p|
875
// |q r|s t|
876
// +---+---+
877
878
// Pixels a, f, l, q are not needed, since we need to understand the
879
// the connectivity between these blocks and those pixels only metter
880
// when considering the outer connectivities
881
882
// A bunch of defines used to check if the pixels are foreground,
883
// without going outside the image limits.
884
885
#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0
886
#define condition_c r > limitLine && img_row_prev_prev[c]>0
887
#define condition_d c+1<w && r > limitLine && img_row_prev_prev[c+1]>0
888
#define condition_e c+2<w && r > limitLine && img_row_prev_prev[c+2]>0
889
890
#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0
891
#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0
892
#define condition_i r > limitLine - 1 && img_row_prev[c]>0
893
#define condition_j c+1<w && r > limitLine - 1 && img_row_prev[c+1]>0
894
#define condition_k c+2<w && r > limitLine - 1 && img_row_prev[c+2]>0
895
896
#define condition_m c-2>=0 && img_row[c-2]>0
897
#define condition_n c-1>=0 && img_row[c-1]>0
898
#define condition_o img_row[c]>0
899
#define condition_p c+1<w && img_row[c+1]>0
900
901
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
902
#define condition_s r+1<h && img_row_fol[c]>0
903
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
904
905
// This is a decision tree which allows to choose which action to
906
// perform, checking as few conditions as possible.
907
// Actions are available after the tree.
908
909
if (condition_o) {
910
if (condition_n) {
911
if (condition_j) {
912
if (condition_i) {
913
//Action_6: Assign label of block S
914
imgLabels_row[c] = imgLabels_row[c - 2];
915
continue;
916
}
917
else {
918
if (condition_c) {
919
if (condition_h) {
920
//Action_6: Assign label of block S
921
imgLabels_row[c] = imgLabels_row[c - 2];
922
continue;
923
}
924
else {
925
if (condition_g) {
926
if (condition_b) {
927
//Action_6: Assign label of block S
928
imgLabels_row[c] = imgLabels_row[c - 2];
929
continue;
930
}
931
else {
932
//Action_11: Merge labels of block Q and S
933
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
934
continue;
935
}
936
}
937
else {
938
//Action_11: Merge labels of block Q and S
939
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
940
continue;
941
}
942
}
943
}
944
else {
945
//Action_11: Merge labels of block Q and S
946
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
947
continue;
948
}
949
}
950
}
951
else {
952
if (condition_p) {
953
if (condition_k) {
954
if (condition_d) {
955
if (condition_i) {
956
//Action_6: Assign label of block S
957
imgLabels_row[c] = imgLabels_row[c - 2];
958
continue;
959
}
960
else {
961
if (condition_c) {
962
if (condition_h) {
963
//Action_6: Assign label of block S
964
imgLabels_row[c] = imgLabels_row[c - 2];
965
continue;
966
}
967
else {
968
if (condition_g) {
969
if (condition_b) {
970
//Action_6: Assign label of block S
971
imgLabels_row[c] = imgLabels_row[c - 2];
972
continue;
973
}
974
else {
975
//Action_12: Merge labels of block R and S
976
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
977
continue;
978
}
979
}
980
else {
981
//Action_12: Merge labels of block R and S
982
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
983
continue;
984
}
985
}
986
}
987
else {
988
//Action_12: Merge labels of block R and S
989
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
990
continue;
991
}
992
}
993
}
994
else {
995
//Action_12: Merge labels of block R and S
996
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
997
continue;
998
}
999
}
1000
else {
1001
//Action_6: Assign label of block S
1002
imgLabels_row[c] = imgLabels_row[c - 2];
1003
continue;
1004
}
1005
}
1006
else {
1007
//Action_6: Assign label of block S
1008
imgLabels_row[c] = imgLabels_row[c - 2];
1009
continue;
1010
}
1011
}
1012
}
1013
else {
1014
if (condition_r) {
1015
if (condition_j) {
1016
if (condition_m) {
1017
if (condition_h) {
1018
if (condition_i) {
1019
//Action_6: Assign label of block S
1020
imgLabels_row[c] = imgLabels_row[c - 2];
1021
continue;
1022
}
1023
else {
1024
if (condition_c) {
1025
//Action_6: Assign label of block S
1026
imgLabels_row[c] = imgLabels_row[c - 2];
1027
continue;
1028
}
1029
else {
1030
//Action_11: Merge labels of block Q and S
1031
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1032
continue;
1033
}
1034
}
1035
}
1036
else {
1037
if (condition_g) {
1038
if (condition_b) {
1039
if (condition_i) {
1040
//Action_6: Assign label of block S
1041
imgLabels_row[c] = imgLabels_row[c - 2];
1042
continue;
1043
}
1044
else {
1045
if (condition_c) {
1046
//Action_6: Assign label of block S
1047
imgLabels_row[c] = imgLabels_row[c - 2];
1048
continue;
1049
}
1050
else {
1051
//Action_11: Merge labels of block Q and S
1052
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1053
continue;
1054
}
1055
}
1056
}
1057
else {
1058
//Action_11: Merge labels of block Q and S
1059
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1060
continue;
1061
}
1062
}
1063
else {
1064
//Action_11: Merge labels of block Q and S
1065
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1066
continue;
1067
}
1068
}
1069
}
1070
else {
1071
if (condition_i) {
1072
//Action_11: Merge labels of block Q and S
1073
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1074
continue;
1075
}
1076
else {
1077
if (condition_h) {
1078
if (condition_c) {
1079
//Action_11: Merge labels of block Q and S
1080
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1081
continue;
1082
}
1083
else {
1084
//Action_14: Merge labels of block P_, Q and S
1085
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);
1086
continue;
1087
}
1088
}
1089
else {
1090
//Action_11: Merge labels of block Q and S
1091
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1092
continue;
1093
}
1094
}
1095
}
1096
}
1097
else {
1098
if (condition_p) {
1099
if (condition_k) {
1100
if (condition_m) {
1101
if (condition_h) {
1102
if (condition_d) {
1103
if (condition_i) {
1104
//Action_6: Assign label of block S
1105
imgLabels_row[c] = imgLabels_row[c - 2];
1106
continue;
1107
}
1108
else {
1109
if (condition_c) {
1110
//Action_6: Assign label of block S
1111
imgLabels_row[c] = imgLabels_row[c - 2];
1112
continue;
1113
}
1114
else {
1115
//Action_12: Merge labels of block R and S
1116
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1117
continue;
1118
}
1119
}
1120
}
1121
else {
1122
//Action_12: Merge labels of block R and S
1123
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1124
continue;
1125
}
1126
}
1127
else {
1128
if (condition_d) {
1129
if (condition_g) {
1130
if (condition_b) {
1131
if (condition_i) {
1132
//Action_6: Assign label of block S
1133
imgLabels_row[c] = imgLabels_row[c - 2];
1134
continue;
1135
}
1136
else {
1137
if (condition_c) {
1138
//Action_6: Assign label of block S
1139
imgLabels_row[c] = imgLabels_row[c - 2];
1140
continue;
1141
}
1142
else {
1143
//Action_12: Merge labels of block R and S
1144
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1145
continue;
1146
}
1147
}
1148
}
1149
else {
1150
//Action_12: Merge labels of block R and S
1151
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1152
continue;
1153
}
1154
}
1155
else {
1156
//Action_12: Merge labels of block R and S
1157
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1158
continue;
1159
}
1160
}
1161
else {
1162
if (condition_i) {
1163
if (condition_g) {
1164
if (condition_b) {
1165
//Action_12: Merge labels of block R and S
1166
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1167
continue;
1168
}
1169
else {
1170
//Action_16: labels of block Q, R and S
1171
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1172
continue;
1173
}
1174
}
1175
else {
1176
//Action_16: labels of block Q, R and S
1177
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1178
continue;
1179
}
1180
}
1181
else {
1182
//Action_12: Merge labels of block R and S
1183
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1184
continue;
1185
}
1186
}
1187
}
1188
}
1189
else {
1190
if (condition_i) {
1191
if (condition_d) {
1192
//Action_12: Merge labels of block R and S
1193
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1194
continue;
1195
}
1196
else {
1197
//Action_16: labels of block Q, R and S
1198
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1199
continue;
1200
}
1201
}
1202
else {
1203
if (condition_h) {
1204
if (condition_d) {
1205
if (condition_c) {
1206
//Action_12: Merge labels of block R and S
1207
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1208
continue;
1209
}
1210
else {
1211
//Action_15: Merge labels of block P_, R and S
1212
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1213
continue;
1214
}
1215
}
1216
else {
1217
//Action_15: Merge labels of block P_, R and S
1218
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1219
continue;
1220
}
1221
}
1222
else {
1223
//Action_12: Merge labels of block R and S
1224
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1225
continue;
1226
}
1227
}
1228
}
1229
}
1230
else {
1231
if (condition_h) {
1232
if (condition_m) {
1233
//Action_6: Assign label of block S
1234
imgLabels_row[c] = imgLabels_row[c - 2];
1235
continue;
1236
}
1237
else {
1238
// ACTION_9 Merge labels of block P_ and S
1239
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
1240
continue;
1241
}
1242
}
1243
else {
1244
if (condition_i) {
1245
if (condition_m) {
1246
if (condition_g) {
1247
if (condition_b) {
1248
//Action_6: Assign label of block S
1249
imgLabels_row[c] = imgLabels_row[c - 2];
1250
continue;
1251
}
1252
else {
1253
//Action_11: Merge labels of block Q and S
1254
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1255
continue;
1256
}
1257
}
1258
else {
1259
//Action_11: Merge labels of block Q and S
1260
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1261
continue;
1262
}
1263
}
1264
else {
1265
//Action_11: Merge labels of block Q and S
1266
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1267
continue;
1268
}
1269
}
1270
else {
1271
//Action_6: Assign label of block S
1272
imgLabels_row[c] = imgLabels_row[c - 2];
1273
continue;
1274
}
1275
}
1276
}
1277
}
1278
else {
1279
if (condition_h) {
1280
if (condition_m) {
1281
//Action_6: Assign label of block S
1282
imgLabels_row[c] = imgLabels_row[c - 2];
1283
continue;
1284
}
1285
else {
1286
// ACTION_9 Merge labels of block P_ and S
1287
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
1288
continue;
1289
}
1290
}
1291
else {
1292
if (condition_i) {
1293
if (condition_m) {
1294
if (condition_g) {
1295
if (condition_b) {
1296
//Action_6: Assign label of block S
1297
imgLabels_row[c] = imgLabels_row[c - 2];
1298
continue;
1299
}
1300
else {
1301
//Action_11: Merge labels of block Q and S
1302
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1303
continue;
1304
}
1305
}
1306
else {
1307
//Action_11: Merge labels of block Q and S
1308
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1309
continue;
1310
}
1311
}
1312
else {
1313
//Action_11: Merge labels of block Q and S
1314
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1315
continue;
1316
}
1317
}
1318
else {
1319
//Action_6: Assign label of block S
1320
imgLabels_row[c] = imgLabels_row[c - 2];
1321
continue;
1322
}
1323
}
1324
}
1325
}
1326
}
1327
else {
1328
if (condition_j) {
1329
if (condition_i) {
1330
//Action_4: Assign label of block Q
1331
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1332
continue;
1333
}
1334
else {
1335
if (condition_h) {
1336
if (condition_c) {
1337
//Action_4: Assign label of block Q
1338
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1339
continue;
1340
}
1341
else {
1342
//Action_7: Merge labels of block P_ and Q
1343
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);
1344
continue;
1345
}
1346
}
1347
else {
1348
//Action_4: Assign label of block Q
1349
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1350
continue;
1351
}
1352
}
1353
}
1354
else {
1355
if (condition_p) {
1356
if (condition_k) {
1357
if (condition_i) {
1358
if (condition_d) {
1359
//Action_5: Assign label of block R
1360
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1361
continue;
1362
}
1363
else {
1364
// ACTION_10 Merge labels of block Q and R
1365
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
1366
continue;
1367
}
1368
}
1369
else {
1370
if (condition_h) {
1371
if (condition_d) {
1372
if (condition_c) {
1373
//Action_5: Assign label of block R
1374
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1375
continue;
1376
}
1377
else {
1378
//Action_8: Merge labels of block P_ and R
1379
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
1380
continue;
1381
}
1382
}
1383
else {
1384
//Action_8: Merge labels of block P_ and R
1385
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
1386
continue;
1387
}
1388
}
1389
else {
1390
//Action_5: Assign label of block R
1391
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1392
continue;
1393
}
1394
}
1395
}
1396
else {
1397
if (condition_i) {
1398
//Action_4: Assign label of block Q
1399
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1400
continue;
1401
}
1402
else {
1403
if (condition_h) {
1404
//Action_3: Assign label of block P_
1405
imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
1406
continue;
1407
}
1408
else {
1409
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1410
imgLabels_row[c] = label;
1411
P_[label] = label;
1412
label = label + 1;
1413
continue;
1414
}
1415
}
1416
}
1417
}
1418
else {
1419
if (condition_i) {
1420
//Action_4: Assign label of block Q
1421
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1422
continue;
1423
}
1424
else {
1425
if (condition_h) {
1426
//Action_3: Assign label of block P_
1427
imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
1428
continue;
1429
}
1430
else {
1431
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1432
imgLabels_row[c] = label;
1433
P_[label] = label;
1434
label = label + 1;
1435
continue;
1436
}
1437
}
1438
}
1439
}
1440
}
1441
}
1442
}
1443
else {
1444
if (condition_s) {
1445
if (condition_p) {
1446
if (condition_n) {
1447
if (condition_j) {
1448
if (condition_i) {
1449
//Action_6: Assign label of block S
1450
imgLabels_row[c] = imgLabels_row[c - 2];
1451
continue;
1452
}
1453
else {
1454
if (condition_c) {
1455
if (condition_h) {
1456
//Action_6: Assign label of block S
1457
imgLabels_row[c] = imgLabels_row[c - 2];
1458
continue;
1459
}
1460
else {
1461
if (condition_g) {
1462
if (condition_b) {
1463
//Action_6: Assign label of block S
1464
imgLabels_row[c] = imgLabels_row[c - 2];
1465
continue;
1466
}
1467
else {
1468
//Action_11: Merge labels of block Q and S
1469
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1470
continue;
1471
}
1472
}
1473
else {
1474
//Action_11: Merge labels of block Q and S
1475
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1476
continue;
1477
}
1478
}
1479
}
1480
else {
1481
//Action_11: Merge labels of block Q and S
1482
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1483
continue;
1484
}
1485
}
1486
}
1487
else {
1488
if (condition_k) {
1489
if (condition_d) {
1490
if (condition_i) {
1491
//Action_6: Assign label of block S
1492
imgLabels_row[c] = imgLabels_row[c - 2];
1493
continue;
1494
}
1495
else {
1496
if (condition_c) {
1497
if (condition_h) {
1498
//Action_6: Assign label of block S
1499
imgLabels_row[c] = imgLabels_row[c - 2];
1500
continue;
1501
}
1502
else {
1503
if (condition_g) {
1504
if (condition_b) {
1505
//Action_6: Assign label of block S
1506
imgLabels_row[c] = imgLabels_row[c - 2];
1507
continue;
1508
}
1509
else {
1510
//Action_12: Merge labels of block R and S
1511
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1512
continue;
1513
}
1514
}
1515
else {
1516
//Action_12: Merge labels of block R and S
1517
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1518
continue;
1519
}
1520
}
1521
}
1522
else {
1523
//Action_12: Merge labels of block R and S
1524
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1525
continue;
1526
}
1527
}
1528
}
1529
else {
1530
//Action_12: Merge labels of block R and S
1531
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1532
continue;
1533
}
1534
}
1535
else {
1536
//Action_6: Assign label of block S
1537
imgLabels_row[c] = imgLabels_row[c - 2];
1538
continue;
1539
}
1540
}
1541
}
1542
else {
1543
if (condition_r) {
1544
if (condition_j) {
1545
if (condition_m) {
1546
if (condition_h) {
1547
if (condition_i) {
1548
//Action_6: Assign label of block S
1549
imgLabels_row[c] = imgLabels_row[c - 2];
1550
continue;
1551
}
1552
else {
1553
if (condition_c) {
1554
//Action_6: Assign label of block S
1555
imgLabels_row[c] = imgLabels_row[c - 2];
1556
continue;
1557
}
1558
else {
1559
//Action_11: Merge labels of block Q and S
1560
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1561
continue;
1562
}
1563
}
1564
}
1565
else {
1566
if (condition_g) {
1567
if (condition_b) {
1568
if (condition_i) {
1569
//Action_6: Assign label of block S
1570
imgLabels_row[c] = imgLabels_row[c - 2];
1571
continue;
1572
}
1573
else {
1574
if (condition_c) {
1575
//Action_6: Assign label of block S
1576
imgLabels_row[c] = imgLabels_row[c - 2];
1577
continue;
1578
}
1579
else {
1580
//Action_11: Merge labels of block Q and S
1581
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1582
continue;
1583
}
1584
}
1585
}
1586
else {
1587
//Action_11: Merge labels of block Q and S
1588
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1589
continue;
1590
}
1591
}
1592
else {
1593
//Action_11: Merge labels of block Q and S
1594
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1595
continue;
1596
}
1597
}
1598
}
1599
else {
1600
//Action_11: Merge labels of block Q and S
1601
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1602
continue;
1603
}
1604
}
1605
else {
1606
if (condition_k) {
1607
if (condition_d) {
1608
if (condition_m) {
1609
if (condition_h) {
1610
if (condition_i) {
1611
//Action_6: Assign label of block S
1612
imgLabels_row[c] = imgLabels_row[c - 2];
1613
continue;
1614
}
1615
else {
1616
if (condition_c) {
1617
//Action_6: Assign label of block S
1618
imgLabels_row[c] = imgLabels_row[c - 2];
1619
continue;
1620
}
1621
else {
1622
//Action_12: Merge labels of block R and S
1623
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1624
continue;
1625
}
1626
}
1627
}
1628
else {
1629
if (condition_g) {
1630
if (condition_b) {
1631
if (condition_i) {
1632
//Action_6: Assign label of block S
1633
imgLabels_row[c] = imgLabels_row[c - 2];
1634
continue;
1635
}
1636
else {
1637
if (condition_c) {
1638
//Action_6: Assign label of block S
1639
imgLabels_row[c] = imgLabels_row[c - 2];
1640
continue;
1641
}
1642
else {
1643
//Action_12: Merge labels of block R and S
1644
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1645
continue;
1646
}
1647
}
1648
}
1649
else {
1650
//Action_12: Merge labels of block R and S
1651
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1652
continue;
1653
}
1654
}
1655
else {
1656
//Action_12: Merge labels of block R and S
1657
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1658
continue;
1659
}
1660
}
1661
}
1662
else {
1663
//Action_12: Merge labels of block R and S
1664
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1665
continue;
1666
}
1667
}
1668
else {
1669
if (condition_i) {
1670
if (condition_m) {
1671
if (condition_h) {
1672
//Action_12: Merge labels of block R and S
1673
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1674
continue;
1675
}
1676
else {
1677
if (condition_g) {
1678
if (condition_b) {
1679
//Action_12: Merge labels of block R and S
1680
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1681
continue;
1682
}
1683
else {
1684
//Action_16: labels of block Q, R and S
1685
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1686
continue;
1687
}
1688
}
1689
else {
1690
//Action_16: labels of block Q, R and S
1691
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1692
continue;
1693
}
1694
}
1695
}
1696
else {
1697
//Action_16: labels of block Q, R and S
1698
imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
1699
continue;
1700
}
1701
}
1702
else {
1703
//Action_12: Merge labels of block R and S
1704
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
1705
continue;
1706
}
1707
}
1708
}
1709
else {
1710
if (condition_i) {
1711
if (condition_m) {
1712
if (condition_h) {
1713
//Action_6: Assign label of block S
1714
imgLabels_row[c] = imgLabels_row[c - 2];
1715
continue;
1716
}
1717
else {
1718
if (condition_g) {
1719
if (condition_b) {
1720
//Action_6: Assign label of block S
1721
imgLabels_row[c] = imgLabels_row[c - 2];
1722
continue;
1723
}
1724
else {
1725
//Action_11: Merge labels of block Q and S
1726
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1727
continue;
1728
}
1729
}
1730
else {
1731
//Action_11: Merge labels of block Q and S
1732
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1733
continue;
1734
}
1735
}
1736
}
1737
else {
1738
//Action_11: Merge labels of block Q and S
1739
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
1740
continue;
1741
}
1742
}
1743
else {
1744
//Action_6: Assign label of block S
1745
imgLabels_row[c] = imgLabels_row[c - 2];
1746
continue;
1747
}
1748
}
1749
}
1750
}
1751
else {
1752
if (condition_j) {
1753
//Action_4: Assign label of block Q
1754
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1755
continue;
1756
}
1757
else {
1758
if (condition_k) {
1759
if (condition_i) {
1760
if (condition_d) {
1761
//Action_5: Assign label of block R
1762
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1763
continue;
1764
}
1765
else {
1766
// ACTION_10 Merge labels of block Q and R
1767
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
1768
continue;
1769
}
1770
}
1771
else {
1772
//Action_5: Assign label of block R
1773
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1774
continue;
1775
}
1776
}
1777
else {
1778
if (condition_i) {
1779
//Action_4: Assign label of block Q
1780
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1781
continue;
1782
}
1783
else {
1784
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1785
imgLabels_row[c] = label;
1786
P_[label] = label;
1787
label = label + 1;
1788
continue;
1789
}
1790
}
1791
}
1792
}
1793
}
1794
}
1795
else {
1796
if (condition_r) {
1797
//Action_6: Assign label of block S
1798
imgLabels_row[c] = imgLabels_row[c - 2];
1799
continue;
1800
}
1801
else {
1802
if (condition_n) {
1803
//Action_6: Assign label of block S
1804
imgLabels_row[c] = imgLabels_row[c - 2];
1805
continue;
1806
}
1807
else {
1808
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1809
imgLabels_row[c] = label;
1810
P_[label] = label;
1811
label = label + 1;
1812
continue;
1813
}
1814
}
1815
}
1816
}
1817
else {
1818
if (condition_p) {
1819
if (condition_j) {
1820
//Action_4: Assign label of block Q
1821
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1822
continue;
1823
}
1824
else {
1825
if (condition_k) {
1826
if (condition_i) {
1827
if (condition_d) {
1828
//Action_5: Assign label of block R
1829
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1830
continue;
1831
}
1832
else {
1833
// ACTION_10 Merge labels of block Q and R
1834
imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
1835
continue;
1836
}
1837
}
1838
else {
1839
//Action_5: Assign label of block R
1840
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
1841
continue;
1842
}
1843
}
1844
else {
1845
if (condition_i) {
1846
//Action_4: Assign label of block Q
1847
imgLabels_row[c] = imgLabels_row_prev_prev[c];
1848
continue;
1849
}
1850
else {
1851
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1852
imgLabels_row[c] = label;
1853
P_[label] = label;
1854
label = label + 1;
1855
continue;
1856
}
1857
}
1858
}
1859
}
1860
else {
1861
if (condition_t) {
1862
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
1863
imgLabels_row[c] = label;
1864
P_[label] = label;
1865
label = label + 1;
1866
continue;
1867
}
1868
else {
1869
// Action_1: No action (the block has no foreground pixels)
1870
imgLabels_row[c] = 0;
1871
continue;
1872
}
1873
}
1874
}
1875
}
1876
}
1877
}
1878
//write in the follower memory location
1879
chunksSizeAndLabels_[startR + 1] = label - firstLabel;
1880
}
1881
#undef condition_k
1882
#undef condition_j
1883
#undef condition_i
1884
#undef condition_h
1885
#undef condition_g
1886
#undef condition_e
1887
#undef condition_d
1888
#undef condition_c
1889
#undef condition_b
1890
};
1891
1892
class SecondScan : public cv::ParallelLoopBody{
1893
private:
1894
const cv::Mat& img_;
1895
cv::Mat& imgLabels_;
1896
LabelT *P_;
1897
StatsOp& sop_;
1898
StatsOp *sopArray_;
1899
LabelT& nLabels_;
1900
1901
public:
1902
SecondScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels)
1903
: img_(img), imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){}
1904
1905
SecondScan& operator=(const SecondScan& ) { return *this; }
1906
1907
void operator()(const cv::Range& range) const CV_OVERRIDE
1908
{
1909
int r = range.start;
1910
r += (r % 2);
1911
const int rowBegin = r;
1912
const int rowEnd = range.end + range.end % 2;
1913
1914
if (rowBegin > 0){
1915
sopArray_[rowBegin].initElement(nLabels_);
1916
sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd;
1917
1918
if (imgLabels_.rows& 1){
1919
if (imgLabels_.cols& 1){
1920
//Case 1: both rows and cols odd
1921
for (; r < rowEnd; r += 2){
1922
// Get rows pointer
1923
const PixelT * const img_row = img_.ptr<PixelT>(r);
1924
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
1925
1926
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
1927
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
1928
// Get rows pointer
1929
for (int c = 0; c < imgLabels_.cols; c += 2) {
1930
LabelT iLabel = imgLabels_row[c];
1931
if (iLabel > 0) {
1932
iLabel = P_[iLabel];
1933
if (img_row[c] > 0){
1934
imgLabels_row[c] = iLabel;
1935
sopArray_[rowBegin](r, c, iLabel);
1936
}
1937
else{
1938
imgLabels_row[c] = 0;
1939
sopArray_[rowBegin](r, c, 0);
1940
}
1941
if (c + 1 < imgLabels_.cols) {
1942
if (img_row[c + 1] > 0){
1943
imgLabels_row[c + 1] = iLabel;
1944
sopArray_[rowBegin](r, c + 1, iLabel);
1945
}
1946
else{
1947
imgLabels_row[c + 1] = 0;
1948
sopArray_[rowBegin](r, c + 1, 0);
1949
}
1950
if (r + 1 < imgLabels_.rows) {
1951
if (img_row_fol[c] > 0){
1952
imgLabels_row_fol[c] = iLabel;
1953
sopArray_[rowBegin](r + 1, c, iLabel);
1954
}
1955
else{
1956
imgLabels_row_fol[c] = 0;
1957
sopArray_[rowBegin](r + 1, c, 0);
1958
}
1959
if (img_row_fol[c + 1] > 0){
1960
imgLabels_row_fol[c + 1] = iLabel;
1961
sopArray_[rowBegin](r + 1, c + 1, iLabel);
1962
}
1963
else{
1964
imgLabels_row_fol[c + 1] = 0;
1965
sopArray_[rowBegin](r + 1, c + 1, 0);
1966
}
1967
}
1968
}
1969
else if (r + 1 < imgLabels_.rows) {
1970
if (img_row_fol[c] > 0){
1971
imgLabels_row_fol[c] = iLabel;
1972
sopArray_[rowBegin](r + 1, c, iLabel);
1973
}
1974
else{
1975
imgLabels_row_fol[c] = 0;
1976
sopArray_[rowBegin](r + 1, c, 0);
1977
}
1978
}
1979
}
1980
else {
1981
imgLabels_row[c] = 0;
1982
sopArray_[rowBegin](r, c, 0);
1983
if (c + 1 < imgLabels_.cols) {
1984
imgLabels_row[c + 1] = 0;
1985
sopArray_[rowBegin](r, c + 1, 0);
1986
if (r + 1 < imgLabels_.rows) {
1987
imgLabels_row_fol[c] = 0;
1988
imgLabels_row_fol[c + 1] = 0;
1989
sopArray_[rowBegin](r + 1, c, 0);
1990
sopArray_[rowBegin](r + 1, c + 1, 0);
1991
}
1992
}
1993
else if (r + 1 < imgLabels_.rows) {
1994
imgLabels_row_fol[c] = 0;
1995
sopArray_[rowBegin](r + 1, c, 0);
1996
}
1997
}
1998
}
1999
}
2000
}//END Case 1
2001
else{
2002
//Case 2: only rows odd
2003
for (; r < rowEnd; r += 2){
2004
// Get rows pointer
2005
const PixelT * const img_row = img_.ptr<PixelT>(r);
2006
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2007
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2008
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2009
// Get rows pointer
2010
for (int c = 0; c < imgLabels_.cols; c += 2) {
2011
LabelT iLabel = imgLabels_row[c];
2012
if (iLabel > 0) {
2013
iLabel = P_[iLabel];
2014
if (img_row[c] > 0){
2015
imgLabels_row[c] = iLabel;
2016
sopArray_[rowBegin](r, c, iLabel);
2017
}
2018
else{
2019
imgLabels_row[c] = 0;
2020
sopArray_[rowBegin](r, c, 0);
2021
}
2022
if (img_row[c + 1] > 0){
2023
imgLabels_row[c + 1] = iLabel;
2024
sopArray_[rowBegin](r, c + 1, iLabel);
2025
}
2026
else{
2027
imgLabels_row[c + 1] = 0;
2028
sopArray_[rowBegin](r, c + 1, 0);
2029
}
2030
if (r + 1 < imgLabels_.rows) {
2031
if (img_row_fol[c] > 0){
2032
imgLabels_row_fol[c] = iLabel;
2033
sopArray_[rowBegin](r + 1, c, iLabel);
2034
}
2035
else{
2036
imgLabels_row_fol[c] = 0;
2037
sopArray_[rowBegin](r + 1, c, 0);
2038
}
2039
if (img_row_fol[c + 1] > 0){
2040
imgLabels_row_fol[c + 1] = iLabel;
2041
sopArray_[rowBegin](r + 1, c + 1, iLabel);
2042
}
2043
else{
2044
imgLabels_row_fol[c + 1] = 0;
2045
sopArray_[rowBegin](r + 1, c + 1, 0);
2046
}
2047
}
2048
}
2049
else {
2050
imgLabels_row[c] = 0;
2051
imgLabels_row[c + 1] = 0;
2052
sopArray_[rowBegin](r, c, 0);
2053
sopArray_[rowBegin](r, c + 1, 0);
2054
if (r + 1 < imgLabels_.rows) {
2055
imgLabels_row_fol[c] = 0;
2056
imgLabels_row_fol[c + 1] = 0;
2057
sopArray_[rowBegin](r + 1, c, 0);
2058
sopArray_[rowBegin](r + 1, c + 1, 0);
2059
}
2060
}
2061
}
2062
}
2063
}// END Case 2
2064
}
2065
else{
2066
if (imgLabels_.cols& 1){
2067
//Case 3: only cols odd
2068
for (; r < rowEnd; r += 2){
2069
// Get rows pointer
2070
const PixelT * const img_row = img_.ptr<PixelT>(r);
2071
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2072
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2073
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2074
// Get rows pointer
2075
for (int c = 0; c < imgLabels_.cols; c += 2) {
2076
LabelT iLabel = imgLabels_row[c];
2077
if (iLabel > 0) {
2078
iLabel = P_[iLabel];
2079
if (img_row[c] > 0){
2080
imgLabels_row[c] = iLabel;
2081
sopArray_[rowBegin](r, c, iLabel);
2082
}
2083
else{
2084
imgLabels_row[c] = 0;
2085
sopArray_[rowBegin](r, c, 0);
2086
}
2087
if (img_row_fol[c] > 0){
2088
imgLabels_row_fol[c] = iLabel;
2089
sopArray_[rowBegin](r + 1, c, iLabel);
2090
}
2091
else{
2092
imgLabels_row_fol[c] = 0;
2093
sopArray_[rowBegin](r + 1, c, 0);
2094
}
2095
if (c + 1 < imgLabels_.cols) {
2096
if (img_row[c + 1] > 0){
2097
imgLabels_row[c + 1] = iLabel;
2098
sopArray_[rowBegin](r, c + 1, iLabel);
2099
}
2100
else{
2101
imgLabels_row[c + 1] = 0;
2102
sopArray_[rowBegin](r, c + 1, 0);
2103
}
2104
if (img_row_fol[c + 1] > 0){
2105
imgLabels_row_fol[c + 1] = iLabel;
2106
sopArray_[rowBegin](r + 1, c + 1, iLabel);
2107
}
2108
else{
2109
imgLabels_row_fol[c + 1] = 0;
2110
sopArray_[rowBegin](r + 1, c + 1, 0);
2111
}
2112
}
2113
}
2114
else{
2115
imgLabels_row[c] = 0;
2116
imgLabels_row_fol[c] = 0;
2117
sopArray_[rowBegin](r, c, 0);
2118
sopArray_[rowBegin](r + 1, c, 0);
2119
if (c + 1 < imgLabels_.cols) {
2120
imgLabels_row[c + 1] = 0;
2121
imgLabels_row_fol[c + 1] = 0;
2122
sopArray_[rowBegin](r, c + 1, 0);
2123
sopArray_[rowBegin](r + 1, c + 1, 0);
2124
}
2125
}
2126
}
2127
}
2128
}// END case 3
2129
else{
2130
//Case 4: nothing odd
2131
for (; r < rowEnd; r += 2){
2132
// Get rows pointer
2133
const PixelT * const img_row = img_.ptr<PixelT>(r);
2134
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2135
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2136
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2137
// Get rows pointer
2138
for (int c = 0; c < imgLabels_.cols; c += 2) {
2139
LabelT iLabel = imgLabels_row[c];
2140
if (iLabel > 0) {
2141
iLabel = P_[iLabel];
2142
if (img_row[c] > 0){
2143
imgLabels_row[c] = iLabel;
2144
sopArray_[rowBegin](r, c, iLabel);
2145
}
2146
else{
2147
imgLabels_row[c] = 0;
2148
sopArray_[rowBegin](r, c, 0);
2149
}
2150
if (img_row[c + 1] > 0){
2151
imgLabels_row[c + 1] = iLabel;
2152
sopArray_[rowBegin](r, c + 1, iLabel);
2153
}
2154
else{
2155
imgLabels_row[c + 1] = 0;
2156
sopArray_[rowBegin](r, c + 1, 0);
2157
}
2158
if (img_row_fol[c] > 0){
2159
imgLabels_row_fol[c] = iLabel;
2160
sopArray_[rowBegin](r + 1, c, iLabel);
2161
}
2162
else{
2163
imgLabels_row_fol[c] = 0;
2164
sopArray_[rowBegin](r + 1, c, 0);
2165
}
2166
if (img_row_fol[c + 1] > 0){
2167
imgLabels_row_fol[c + 1] = iLabel;
2168
sopArray_[rowBegin](r + 1, c + 1, iLabel);
2169
}
2170
else{
2171
imgLabels_row_fol[c + 1] = 0;
2172
sopArray_[rowBegin](r + 1, c + 1, 0);
2173
}
2174
}
2175
else {
2176
imgLabels_row[c] = 0;
2177
imgLabels_row[c + 1] = 0;
2178
imgLabels_row_fol[c] = 0;
2179
imgLabels_row_fol[c + 1] = 0;
2180
sopArray_[rowBegin](r, c, 0);
2181
sopArray_[rowBegin](r, c + 1, 0);
2182
sopArray_[rowBegin](r + 1, c, 0);
2183
sopArray_[rowBegin](r + 1, c + 1, 0);
2184
}
2185
}
2186
}//END case 4
2187
}
2188
}
2189
}
2190
else{
2191
//the first thread uses sop in order to make less merges
2192
sop_.setNextLoc(rowEnd);
2193
if (imgLabels_.rows& 1){
2194
if (imgLabels_.cols& 1){
2195
//Case 1: both rows and cols odd
2196
for (; r < rowEnd; r += 2){
2197
// Get rows pointer
2198
const PixelT * const img_row = img_.ptr<PixelT>(r);
2199
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2200
2201
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2202
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2203
// Get rows pointer
2204
for (int c = 0; c < imgLabels_.cols; c += 2) {
2205
LabelT iLabel = imgLabels_row[c];
2206
if (iLabel > 0) {
2207
iLabel = P_[iLabel];
2208
if (img_row[c] > 0){
2209
imgLabels_row[c] = iLabel;
2210
sop_(r, c, iLabel);
2211
}
2212
else{
2213
imgLabels_row[c] = 0;
2214
sop_(r, c, 0);
2215
}
2216
if (c + 1 < imgLabels_.cols) {
2217
if (img_row[c + 1] > 0){
2218
imgLabels_row[c + 1] = iLabel;
2219
sop_(r, c + 1, iLabel);
2220
}
2221
else{
2222
imgLabels_row[c + 1] = 0;
2223
sop_(r, c + 1, 0);
2224
}
2225
if (r + 1 < imgLabels_.rows) {
2226
if (img_row_fol[c] > 0){
2227
imgLabels_row_fol[c] = iLabel;
2228
sop_(r + 1, c, iLabel);
2229
}
2230
else{
2231
imgLabels_row_fol[c] = 0;
2232
sop_(r + 1, c, 0);
2233
}
2234
if (img_row_fol[c + 1] > 0){
2235
imgLabels_row_fol[c + 1] = iLabel;
2236
sop_(r + 1, c + 1, iLabel);
2237
}
2238
else{
2239
imgLabels_row_fol[c + 1] = 0;
2240
sop_(r + 1, c + 1, 0);
2241
}
2242
}
2243
}
2244
else if (r + 1 < imgLabels_.rows) {
2245
if (img_row_fol[c] > 0){
2246
imgLabels_row_fol[c] = iLabel;
2247
sop_(r + 1, c, iLabel);
2248
}
2249
else{
2250
imgLabels_row_fol[c] = 0;
2251
sop_(r + 1, c, 0);
2252
}
2253
}
2254
}
2255
else {
2256
imgLabels_row[c] = 0;
2257
sop_(r, c, 0);
2258
if (c + 1 < imgLabels_.cols) {
2259
imgLabels_row[c + 1] = 0;
2260
sop_(r, c + 1, 0);
2261
if (r + 1 < imgLabels_.rows) {
2262
imgLabels_row_fol[c] = 0;
2263
imgLabels_row_fol[c + 1] = 0;
2264
sop_(r + 1, c, 0);
2265
sop_(r + 1, c + 1, 0);
2266
}
2267
}
2268
else if (r + 1 < imgLabels_.rows) {
2269
imgLabels_row_fol[c] = 0;
2270
sop_(r + 1, c, 0);
2271
}
2272
}
2273
}
2274
}
2275
}//END Case 1
2276
else{
2277
//Case 2: only rows odd
2278
for (; r < rowEnd; r += 2){
2279
// Get rows pointer
2280
const PixelT * const img_row = img_.ptr<PixelT>(r);
2281
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2282
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2283
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2284
// Get rows pointer
2285
for (int c = 0; c < imgLabels_.cols; c += 2) {
2286
LabelT iLabel = imgLabels_row[c];
2287
if (iLabel > 0) {
2288
iLabel = P_[iLabel];
2289
if (img_row[c] > 0){
2290
imgLabels_row[c] = iLabel;
2291
sop_(r, c, iLabel);
2292
}
2293
else{
2294
imgLabels_row[c] = 0;
2295
sop_(r, c, 0);
2296
}
2297
if (img_row[c + 1] > 0){
2298
imgLabels_row[c + 1] = iLabel;
2299
sop_(r, c + 1, iLabel);
2300
}
2301
else{
2302
imgLabels_row[c + 1] = 0;
2303
sop_(r, c + 1, 0);
2304
}
2305
if (r + 1 < imgLabels_.rows) {
2306
if (img_row_fol[c] > 0){
2307
imgLabels_row_fol[c] = iLabel;
2308
sop_(r + 1, c, iLabel);
2309
}
2310
else{
2311
imgLabels_row_fol[c] = 0;
2312
sop_(r + 1, c, 0);
2313
}
2314
if (img_row_fol[c + 1] > 0){
2315
imgLabels_row_fol[c + 1] = iLabel;
2316
sop_(r + 1, c + 1, iLabel);
2317
}
2318
else{
2319
imgLabels_row_fol[c + 1] = 0;
2320
sop_(r + 1, c + 1, 0);
2321
}
2322
}
2323
}
2324
else {
2325
imgLabels_row[c] = 0;
2326
imgLabels_row[c + 1] = 0;
2327
sop_(r, c, 0);
2328
sop_(r, c + 1, 0);
2329
if (r + 1 < imgLabels_.rows) {
2330
imgLabels_row_fol[c] = 0;
2331
imgLabels_row_fol[c + 1] = 0;
2332
sop_(r + 1, c, 0);
2333
sop_(r + 1, c + 1, 0);
2334
}
2335
}
2336
}
2337
}
2338
}// END Case 2
2339
}
2340
else{
2341
if (imgLabels_.cols& 1){
2342
//Case 3: only cols odd
2343
for (; r < rowEnd; r += 2){
2344
// Get rows pointer
2345
const PixelT * const img_row = img_.ptr<PixelT>(r);
2346
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2347
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2348
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2349
// Get rows pointer
2350
for (int c = 0; c < imgLabels_.cols; c += 2) {
2351
LabelT iLabel = imgLabels_row[c];
2352
if (iLabel > 0) {
2353
iLabel = P_[iLabel];
2354
if (img_row[c] > 0){
2355
imgLabels_row[c] = iLabel;
2356
sop_(r, c, iLabel);
2357
}
2358
else{
2359
imgLabels_row[c] = 0;
2360
sop_(r, c, 0);
2361
}
2362
if (img_row_fol[c] > 0){
2363
imgLabels_row_fol[c] = iLabel;
2364
sop_(r + 1, c, iLabel);
2365
}
2366
else{
2367
imgLabels_row_fol[c] = 0;
2368
sop_(r + 1, c, 0);
2369
}
2370
if (c + 1 < imgLabels_.cols) {
2371
if (img_row[c + 1] > 0){
2372
imgLabels_row[c + 1] = iLabel;
2373
sop_(r, c + 1, iLabel);
2374
}
2375
else{
2376
imgLabels_row[c + 1] = 0;
2377
sop_(r, c + 1, 0);
2378
}
2379
if (img_row_fol[c + 1] > 0){
2380
imgLabels_row_fol[c + 1] = iLabel;
2381
sop_(r + 1, c + 1, iLabel);
2382
}
2383
else{
2384
imgLabels_row_fol[c + 1] = 0;
2385
sop_(r + 1, c + 1, 0);
2386
}
2387
}
2388
}
2389
else{
2390
imgLabels_row[c] = 0;
2391
imgLabels_row_fol[c] = 0;
2392
sop_(r, c, 0);
2393
sop_(r + 1, c, 0);
2394
if (c + 1 < imgLabels_.cols) {
2395
imgLabels_row[c + 1] = 0;
2396
imgLabels_row_fol[c + 1] = 0;
2397
sop_(r, c + 1, 0);
2398
sop_(r + 1, c + 1, 0);
2399
}
2400
}
2401
}
2402
}
2403
}// END case 3
2404
else{
2405
//Case 4: nothing odd
2406
for (; r < rowEnd; r += 2){
2407
// Get rows pointer
2408
const PixelT * const img_row = img_.ptr<PixelT>(r);
2409
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
2410
LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
2411
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
2412
// Get rows pointer
2413
for (int c = 0; c < imgLabels_.cols; c += 2) {
2414
LabelT iLabel = imgLabels_row[c];
2415
if (iLabel > 0) {
2416
iLabel = P_[iLabel];
2417
if (img_row[c] > 0){
2418
imgLabels_row[c] = iLabel;
2419
sop_(r, c, iLabel);
2420
}
2421
else{
2422
imgLabels_row[c] = 0;
2423
sop_(r, c, 0);
2424
}
2425
if (img_row[c + 1] > 0){
2426
imgLabels_row[c + 1] = iLabel;
2427
sop_(r, c + 1, iLabel);
2428
}
2429
else{
2430
imgLabels_row[c + 1] = 0;
2431
sop_(r, c + 1, 0);
2432
}
2433
if (img_row_fol[c] > 0){
2434
imgLabels_row_fol[c] = iLabel;
2435
sop_(r + 1, c, iLabel);
2436
}
2437
else{
2438
imgLabels_row_fol[c] = 0;
2439
sop_(r + 1, c, 0);
2440
}
2441
if (img_row_fol[c + 1] > 0){
2442
imgLabels_row_fol[c + 1] = iLabel;
2443
sop_(r + 1, c + 1, iLabel);
2444
}
2445
else{
2446
imgLabels_row_fol[c + 1] = 0;
2447
sop_(r + 1, c + 1, 0);
2448
}
2449
}
2450
else {
2451
imgLabels_row[c] = 0;
2452
imgLabels_row[c + 1] = 0;
2453
imgLabels_row_fol[c] = 0;
2454
imgLabels_row_fol[c + 1] = 0;
2455
sop_(r, c, 0);
2456
sop_(r, c + 1, 0);
2457
sop_(r + 1, c, 0);
2458
sop_(r + 1, c + 1, 0);
2459
}
2460
}
2461
}//END case 4
2462
}
2463
}
2464
}
2465
}
2466
};
2467
2468
inline static
2469
void mergeLabels(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels){
2470
2471
// Merge Mask
2472
// +---+---+---+
2473
// |P -|Q -|R -|
2474
// |- -|- -|- -|
2475
// +---+---+---+
2476
// |X -|
2477
// |- -|
2478
// +---+
2479
const int w = imgLabels.cols, h = imgLabels.rows;
2480
2481
for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){
2482
2483
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
2484
LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
2485
const PixelT * const img_row = img.ptr<PixelT>(r);
2486
const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
2487
2488
for (int c = 0; c < w; c += 2){
2489
2490
#define condition_x imgLabels_row[c] > 0
2491
#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0
2492
#define condition_qppr imgLabels_row_prev_prev[c] > 0
2493
#define condition_qppr1 c < w - 1
2494
#define condition_qppr2 c < w
2495
#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0
2496
2497
if (condition_x){
2498
if (condition_pppr){
2499
//check in img
2500
if (img_row[c] > 0 && img_row_prev[c - 1] > 0)
2501
//assign the same label
2502
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]);
2503
}
2504
if (condition_qppr){
2505
if (condition_qppr1){
2506
if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) ||
2507
(img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){
2508
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);
2509
}
2510
}
2511
else /*if (condition_qppr2)*/{
2512
if (img_row[c] > 0 && img_row_prev[c] > 0)
2513
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);
2514
}
2515
}
2516
if (condition_rppr){
2517
if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0)
2518
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]);
2519
}
2520
}
2521
}
2522
}
2523
}
2524
2525
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
2526
CV_Assert(img.rows == imgLabels.rows);
2527
CV_Assert(img.cols == imgLabels.cols);
2528
CV_Assert(connectivity == 8);
2529
2530
const int h = img.rows;
2531
const int w = img.cols;
2532
2533
//A quick and dirty upper bound for the maximum number of labels.
2534
//Following formula comes from the fact that a 2x2 block in 8-connectivity case
2535
//can never have more than 1 new label and 1 label for background.
2536
//Worst case image example pattern:
2537
//1 0 1 0 1...
2538
//0 0 0 0 0...
2539
//1 0 1 0 1...
2540
//............
2541
const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;
2542
2543
//Array used to store info and labeled pixel by each thread.
2544
//Different threads affect different memory location of chunksSizeAndLabels
2545
int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));
2546
2547
//Tree of labels
2548
LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));
2549
//First label is for background
2550
P[0] = 0;
2551
2552
cv::Range range(0, h);
2553
const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4));
2554
2555
//First scan, each thread works with chunk of img.rows/nThreads rows
2556
//e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows
2557
cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);
2558
2559
//merge labels of different chunks
2560
mergeLabels(img, imgLabels, P, chunksSizeAndLabels);
2561
2562
LabelT nLabels = 1;
2563
for (int i = 0; i < h; i = chunksSizeAndLabels[i]){
2564
flattenL(P, LabelT((i + 1) / 2) * LabelT((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels);
2565
}
2566
2567
//Array for statistics data
2568
StatsOp *sopArray = new StatsOp[h];
2569
sop.init(nLabels);
2570
2571
//Second scan
2572
cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nParallelStripes);
2573
2574
StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);
2575
sop.finish();
2576
2577
delete[] sopArray;
2578
cv::fastFree(chunksSizeAndLabels);
2579
cv::fastFree(P);
2580
return nLabels;
2581
}
2582
};//End struct LabelingGranaParallel
2583
2584
// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
2585
// Only for 8-connectivity
2586
template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
2587
struct LabelingGrana{
2588
LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
2589
CV_Assert(img.rows == imgLabels.rows);
2590
CV_Assert(img.cols == imgLabels.cols);
2591
CV_Assert(connectivity == 8);
2592
2593
const int h = img.rows;
2594
const int w = img.cols;
2595
2596
//A quick and dirty upper bound for the maximum number of labels.
2597
//Following formula comes from the fact that a 2x2 block in 8-connectivity case
2598
//can never have more than 1 new label and 1 label for background.
2599
//Worst case image example pattern:
2600
//1 0 1 0 1...
2601
//0 0 0 0 0...
2602
//1 0 1 0 1...
2603
//............
2604
const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;
2605
2606
LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);
2607
P[0] = 0;
2608
LabelT lunique = 1;
2609
2610
// First scan
2611
for (int r = 0; r < h; r += 2) {
2612
// Get rows pointer
2613
const PixelT * const img_row = img.ptr<PixelT>(r);
2614
const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
2615
const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]);
2616
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
2617
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
2618
LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
2619
for (int c = 0; c < w; c += 2) {
2620
2621
// We work with 2x2 blocks
2622
// +-+-+-+
2623
// |P|Q|R|
2624
// +-+-+-+
2625
// |S|X|
2626
// +-+-+
2627
2628
// The pixels are named as follows
2629
// +---+---+---+
2630
// |a b|c d|e f|
2631
// |g h|i j|k l|
2632
// +---+---+---+
2633
// |m n|o p|
2634
// |q r|s t|
2635
// +---+---+
2636
2637
// Pixels a, f, l, q are not needed, since we need to understand the
2638
// the connectivity between these blocks and those pixels only metter
2639
// when considering the outer connectivities
2640
2641
// A bunch of defines used to check if the pixels are foreground,
2642
// without going outside the image limits.
2643
#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
2644
#define condition_c r-2>=0 && img_row_prev_prev[c]>0
2645
#define condition_d c+1<w&& r-2>=0 && img_row_prev_prev[c+1]>0
2646
#define condition_e c+2<w && r-1>=0 && img_row_prev[c-1]>0
2647
2648
#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
2649
#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
2650
#define condition_i r-1>=0 && img_row_prev[c]>0
2651
#define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
2652
#define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
2653
2654
#define condition_m c-2>=0 && img_row[c-2]>0
2655
#define condition_n c-1>=0 && img_row[c-1]>0
2656
#define condition_o img_row[c]>0
2657
#define condition_p c+1<w && img_row[c+1]>0
2658
2659
#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
2660
#define condition_s r+1<h && img_row_fol[c]>0
2661
#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
2662
2663
// This is a decision tree which allows to choose which action to
2664
// perform, checking as few conditions as possible.
2665
// Actions: the blocks label are provisionally stored in the top left
2666
// pixel of the block in the labels image
2667
2668
if (condition_o) {
2669
if (condition_n) {
2670
if (condition_j) {
2671
if (condition_i) {
2672
//Action_6: Assign label of block S
2673
imgLabels_row[c] = imgLabels_row[c - 2];
2674
continue;
2675
}
2676
else {
2677
if (condition_c) {
2678
if (condition_h) {
2679
//Action_6: Assign label of block S
2680
imgLabels_row[c] = imgLabels_row[c - 2];
2681
continue;
2682
}
2683
else {
2684
if (condition_g) {
2685
if (condition_b) {
2686
//Action_6: Assign label of block S
2687
imgLabels_row[c] = imgLabels_row[c - 2];
2688
continue;
2689
}
2690
else {
2691
//Action_11: Merge labels of block Q and S
2692
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2693
continue;
2694
}
2695
}
2696
else {
2697
//Action_11: Merge labels of block Q and S
2698
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2699
continue;
2700
}
2701
}
2702
}
2703
else {
2704
//Action_11: Merge labels of block Q and S
2705
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2706
continue;
2707
}
2708
}
2709
}
2710
else {
2711
if (condition_p) {
2712
if (condition_k) {
2713
if (condition_d) {
2714
if (condition_i) {
2715
//Action_6: Assign label of block S
2716
imgLabels_row[c] = imgLabels_row[c - 2];
2717
continue;
2718
}
2719
else {
2720
if (condition_c) {
2721
if (condition_h) {
2722
//Action_6: Assign label of block S
2723
imgLabels_row[c] = imgLabels_row[c - 2];
2724
continue;
2725
}
2726
else {
2727
if (condition_g) {
2728
if (condition_b) {
2729
//Action_6: Assign label of block S
2730
imgLabels_row[c] = imgLabels_row[c - 2];
2731
continue;
2732
}
2733
else {
2734
//Action_12: Merge labels of block R and S
2735
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2736
continue;
2737
}
2738
}
2739
else {
2740
//Action_12: Merge labels of block R and S
2741
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2742
continue;
2743
}
2744
}
2745
}
2746
else {
2747
//Action_12: Merge labels of block R and S
2748
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2749
continue;
2750
}
2751
}
2752
}
2753
else {
2754
//Action_12: Merge labels of block R and S
2755
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2756
continue;
2757
}
2758
}
2759
else {
2760
//Action_6: Assign label of block S
2761
imgLabels_row[c] = imgLabels_row[c - 2];
2762
continue;
2763
}
2764
}
2765
else {
2766
//Action_6: Assign label of block S
2767
imgLabels_row[c] = imgLabels_row[c - 2];
2768
continue;
2769
}
2770
}
2771
}
2772
else {
2773
if (condition_r) {
2774
if (condition_j) {
2775
if (condition_m) {
2776
if (condition_h) {
2777
if (condition_i) {
2778
//Action_6: Assign label of block S
2779
imgLabels_row[c] = imgLabels_row[c - 2];
2780
continue;
2781
}
2782
else {
2783
if (condition_c) {
2784
//Action_6: Assign label of block S
2785
imgLabels_row[c] = imgLabels_row[c - 2];
2786
continue;
2787
}
2788
else {
2789
//Action_11: Merge labels of block Q and S
2790
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2791
continue;
2792
}
2793
}
2794
}
2795
else {
2796
if (condition_g) {
2797
if (condition_b) {
2798
if (condition_i) {
2799
//Action_6: Assign label of block S
2800
imgLabels_row[c] = imgLabels_row[c - 2];
2801
continue;
2802
}
2803
else {
2804
if (condition_c) {
2805
//Action_6: Assign label of block S
2806
imgLabels_row[c] = imgLabels_row[c - 2];
2807
continue;
2808
}
2809
else {
2810
//Action_11: Merge labels of block Q and S
2811
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2812
continue;
2813
}
2814
}
2815
}
2816
else {
2817
//Action_11: Merge labels of block Q and S
2818
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2819
continue;
2820
}
2821
}
2822
else {
2823
//Action_11: Merge labels of block Q and S
2824
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2825
continue;
2826
}
2827
}
2828
}
2829
else {
2830
if (condition_i) {
2831
//Action_11: Merge labels of block Q and S
2832
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2833
continue;
2834
}
2835
else {
2836
if (condition_h) {
2837
if (condition_c) {
2838
//Action_11: Merge labels of block Q and S
2839
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2840
continue;
2841
}
2842
else {
2843
//Action_14: Merge labels of block P, Q and S
2844
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);
2845
continue;
2846
}
2847
}
2848
else {
2849
//Action_11: Merge labels of block Q and S
2850
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
2851
continue;
2852
}
2853
}
2854
}
2855
}
2856
else {
2857
if (condition_p) {
2858
if (condition_k) {
2859
if (condition_m) {
2860
if (condition_h) {
2861
if (condition_d) {
2862
if (condition_i) {
2863
//Action_6: Assign label of block S
2864
imgLabels_row[c] = imgLabels_row[c - 2];
2865
continue;
2866
}
2867
else {
2868
if (condition_c) {
2869
//Action_6: Assign label of block S
2870
imgLabels_row[c] = imgLabels_row[c - 2];
2871
continue;
2872
}
2873
else {
2874
//Action_12: Merge labels of block R and S
2875
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2876
continue;
2877
}
2878
}
2879
}
2880
else {
2881
//Action_12: Merge labels of block R and S
2882
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2883
continue;
2884
}
2885
}
2886
else {
2887
if (condition_d) {
2888
if (condition_g) {
2889
if (condition_b) {
2890
if (condition_i) {
2891
//Action_6: Assign label of block S
2892
imgLabels_row[c] = imgLabels_row[c - 2];
2893
continue;
2894
}
2895
else {
2896
if (condition_c) {
2897
//Action_6: Assign label of block S
2898
imgLabels_row[c] = imgLabels_row[c - 2];
2899
continue;
2900
}
2901
else {
2902
//Action_12: Merge labels of block R and S
2903
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2904
continue;
2905
}
2906
}
2907
}
2908
else {
2909
//Action_12: Merge labels of block R and S
2910
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2911
continue;
2912
}
2913
}
2914
else {
2915
//Action_12: Merge labels of block R and S
2916
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2917
continue;
2918
}
2919
}
2920
else {
2921
if (condition_i) {
2922
if (condition_g) {
2923
if (condition_b) {
2924
//Action_12: Merge labels of block R and S
2925
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2926
continue;
2927
}
2928
else {
2929
//Action_16: labels of block Q, R and S
2930
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
2931
continue;
2932
}
2933
}
2934
else {
2935
//Action_16: labels of block Q, R and S
2936
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
2937
continue;
2938
}
2939
}
2940
else {
2941
//Action_12: Merge labels of block R and S
2942
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2943
continue;
2944
}
2945
}
2946
}
2947
}
2948
else {
2949
if (condition_i) {
2950
if (condition_d) {
2951
//Action_12: Merge labels of block R and S
2952
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2953
continue;
2954
}
2955
else {
2956
//Action_16: labels of block Q, R and S
2957
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
2958
continue;
2959
}
2960
}
2961
else {
2962
if (condition_h) {
2963
if (condition_d) {
2964
if (condition_c) {
2965
//Action_12: Merge labels of block R and S
2966
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2967
continue;
2968
}
2969
else {
2970
//Action_15: Merge labels of block P, R and S
2971
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
2972
continue;
2973
}
2974
}
2975
else {
2976
//Action_15: Merge labels of block P, R and S
2977
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
2978
continue;
2979
}
2980
}
2981
else {
2982
//Action_12: Merge labels of block R and S
2983
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
2984
continue;
2985
}
2986
}
2987
}
2988
}
2989
else {
2990
if (condition_h) {
2991
if (condition_m) {
2992
//Action_6: Assign label of block S
2993
imgLabels_row[c] = imgLabels_row[c - 2];
2994
continue;
2995
}
2996
else {
2997
// ACTION_9 Merge labels of block P and S
2998
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
2999
continue;
3000
}
3001
}
3002
else {
3003
if (condition_i) {
3004
if (condition_m) {
3005
if (condition_g) {
3006
if (condition_b) {
3007
//Action_6: Assign label of block S
3008
imgLabels_row[c] = imgLabels_row[c - 2];
3009
continue;
3010
}
3011
else {
3012
//Action_11: Merge labels of block Q and S
3013
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3014
continue;
3015
}
3016
}
3017
else {
3018
//Action_11: Merge labels of block Q and S
3019
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3020
continue;
3021
}
3022
}
3023
else {
3024
//Action_11: Merge labels of block Q and S
3025
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3026
continue;
3027
}
3028
}
3029
else {
3030
//Action_6: Assign label of block S
3031
imgLabels_row[c] = imgLabels_row[c - 2];
3032
continue;
3033
}
3034
}
3035
}
3036
}
3037
else {
3038
if (condition_h) {
3039
if (condition_m) {
3040
//Action_6: Assign label of block S
3041
imgLabels_row[c] = imgLabels_row[c - 2];
3042
continue;
3043
}
3044
else {
3045
// ACTION_9 Merge labels of block P and S
3046
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
3047
continue;
3048
}
3049
}
3050
else {
3051
if (condition_i) {
3052
if (condition_m) {
3053
if (condition_g) {
3054
if (condition_b) {
3055
//Action_6: Assign label of block S
3056
imgLabels_row[c] = imgLabels_row[c - 2];
3057
continue;
3058
}
3059
else {
3060
//Action_11: Merge labels of block Q and S
3061
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3062
continue;
3063
}
3064
}
3065
else {
3066
//Action_11: Merge labels of block Q and S
3067
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3068
continue;
3069
}
3070
}
3071
else {
3072
//Action_11: Merge labels of block Q and S
3073
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3074
continue;
3075
}
3076
}
3077
else {
3078
//Action_6: Assign label of block S
3079
imgLabels_row[c] = imgLabels_row[c - 2];
3080
continue;
3081
}
3082
}
3083
}
3084
}
3085
}
3086
else {
3087
if (condition_j) {
3088
if (condition_i) {
3089
//Action_4: Assign label of block Q
3090
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3091
continue;
3092
}
3093
else {
3094
if (condition_h) {
3095
if (condition_c) {
3096
//Action_4: Assign label of block Q
3097
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3098
continue;
3099
}
3100
else {
3101
//Action_7: Merge labels of block P and Q
3102
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);
3103
continue;
3104
}
3105
}
3106
else {
3107
//Action_4: Assign label of block Q
3108
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3109
continue;
3110
}
3111
}
3112
}
3113
else {
3114
if (condition_p) {
3115
if (condition_k) {
3116
if (condition_i) {
3117
if (condition_d) {
3118
//Action_5: Assign label of block R
3119
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3120
continue;
3121
}
3122
else {
3123
// ACTION_10 Merge labels of block Q and R
3124
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
3125
continue;
3126
}
3127
}
3128
else {
3129
if (condition_h) {
3130
if (condition_d) {
3131
if (condition_c) {
3132
//Action_5: Assign label of block R
3133
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3134
continue;
3135
}
3136
else {
3137
//Action_8: Merge labels of block P and R
3138
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
3139
continue;
3140
}
3141
}
3142
else {
3143
//Action_8: Merge labels of block P and R
3144
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
3145
continue;
3146
}
3147
}
3148
else {
3149
//Action_5: Assign label of block R
3150
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3151
continue;
3152
}
3153
}
3154
}
3155
else {
3156
if (condition_i) {
3157
//Action_4: Assign label of block Q
3158
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3159
continue;
3160
}
3161
else {
3162
if (condition_h) {
3163
//Action_3: Assign label of block P
3164
imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
3165
continue;
3166
}
3167
else {
3168
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3169
imgLabels_row[c] = lunique;
3170
P[lunique] = lunique;
3171
lunique = lunique + 1;
3172
continue;
3173
}
3174
}
3175
}
3176
}
3177
else {
3178
if (condition_i) {
3179
//Action_4: Assign label of block Q
3180
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3181
continue;
3182
}
3183
else {
3184
if (condition_h) {
3185
//Action_3: Assign label of block P
3186
imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
3187
continue;
3188
}
3189
else {
3190
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3191
imgLabels_row[c] = lunique;
3192
P[lunique] = lunique;
3193
lunique = lunique + 1;
3194
continue;
3195
}
3196
}
3197
}
3198
}
3199
}
3200
}
3201
}
3202
else {
3203
if (condition_s) {
3204
if (condition_p) {
3205
if (condition_n) {
3206
if (condition_j) {
3207
if (condition_i) {
3208
//Action_6: Assign label of block S
3209
imgLabels_row[c] = imgLabels_row[c - 2];
3210
continue;
3211
}
3212
else {
3213
if (condition_c) {
3214
if (condition_h) {
3215
//Action_6: Assign label of block S
3216
imgLabels_row[c] = imgLabels_row[c - 2];
3217
continue;
3218
}
3219
else {
3220
if (condition_g) {
3221
if (condition_b) {
3222
//Action_6: Assign label of block S
3223
imgLabels_row[c] = imgLabels_row[c - 2];
3224
continue;
3225
}
3226
else {
3227
//Action_11: Merge labels of block Q and S
3228
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3229
continue;
3230
}
3231
}
3232
else {
3233
//Action_11: Merge labels of block Q and S
3234
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3235
continue;
3236
}
3237
}
3238
}
3239
else {
3240
//Action_11: Merge labels of block Q and S
3241
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3242
continue;
3243
}
3244
}
3245
}
3246
else {
3247
if (condition_k) {
3248
if (condition_d) {
3249
if (condition_i) {
3250
//Action_6: Assign label of block S
3251
imgLabels_row[c] = imgLabels_row[c - 2];
3252
continue;
3253
}
3254
else {
3255
if (condition_c) {
3256
if (condition_h) {
3257
//Action_6: Assign label of block S
3258
imgLabels_row[c] = imgLabels_row[c - 2];
3259
continue;
3260
}
3261
else {
3262
if (condition_g) {
3263
if (condition_b) {
3264
//Action_6: Assign label of block S
3265
imgLabels_row[c] = imgLabels_row[c - 2];
3266
continue;
3267
}
3268
else {
3269
//Action_12: Merge labels of block R and S
3270
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3271
continue;
3272
}
3273
}
3274
else {
3275
//Action_12: Merge labels of block R and S
3276
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3277
continue;
3278
}
3279
}
3280
}
3281
else {
3282
//Action_12: Merge labels of block R and S
3283
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3284
continue;
3285
}
3286
}
3287
}
3288
else {
3289
//Action_12: Merge labels of block R and S
3290
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3291
continue;
3292
}
3293
}
3294
else {
3295
//Action_6: Assign label of block S
3296
imgLabels_row[c] = imgLabels_row[c - 2];
3297
continue;
3298
}
3299
}
3300
}
3301
else {
3302
if (condition_r) {
3303
if (condition_j) {
3304
if (condition_m) {
3305
if (condition_h) {
3306
if (condition_i) {
3307
//Action_6: Assign label of block S
3308
imgLabels_row[c] = imgLabels_row[c - 2];
3309
continue;
3310
}
3311
else {
3312
if (condition_c) {
3313
//Action_6: Assign label of block S
3314
imgLabels_row[c] = imgLabels_row[c - 2];
3315
continue;
3316
}
3317
else {
3318
//Action_11: Merge labels of block Q and S
3319
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3320
continue;
3321
}
3322
}
3323
}
3324
else {
3325
if (condition_g) {
3326
if (condition_b) {
3327
if (condition_i) {
3328
//Action_6: Assign label of block S
3329
imgLabels_row[c] = imgLabels_row[c - 2];
3330
continue;
3331
}
3332
else {
3333
if (condition_c) {
3334
//Action_6: Assign label of block S
3335
imgLabels_row[c] = imgLabels_row[c - 2];
3336
continue;
3337
}
3338
else {
3339
//Action_11: Merge labels of block Q and S
3340
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3341
continue;
3342
}
3343
}
3344
}
3345
else {
3346
//Action_11: Merge labels of block Q and S
3347
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3348
continue;
3349
}
3350
}
3351
else {
3352
//Action_11: Merge labels of block Q and S
3353
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3354
continue;
3355
}
3356
}
3357
}
3358
else {
3359
//Action_11: Merge labels of block Q and S
3360
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3361
continue;
3362
}
3363
}
3364
else {
3365
if (condition_k) {
3366
if (condition_d) {
3367
if (condition_m) {
3368
if (condition_h) {
3369
if (condition_i) {
3370
//Action_6: Assign label of block S
3371
imgLabels_row[c] = imgLabels_row[c - 2];
3372
continue;
3373
}
3374
else {
3375
if (condition_c) {
3376
//Action_6: Assign label of block S
3377
imgLabels_row[c] = imgLabels_row[c - 2];
3378
continue;
3379
}
3380
else {
3381
//Action_12: Merge labels of block R and S
3382
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3383
continue;
3384
}
3385
}
3386
}
3387
else {
3388
if (condition_g) {
3389
if (condition_b) {
3390
if (condition_i) {
3391
//Action_6: Assign label of block S
3392
imgLabels_row[c] = imgLabels_row[c - 2];
3393
continue;
3394
}
3395
else {
3396
if (condition_c) {
3397
//Action_6: Assign label of block S
3398
imgLabels_row[c] = imgLabels_row[c - 2];
3399
continue;
3400
}
3401
else {
3402
//Action_12: Merge labels of block R and S
3403
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3404
continue;
3405
}
3406
}
3407
}
3408
else {
3409
//Action_12: Merge labels of block R and S
3410
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3411
continue;
3412
}
3413
}
3414
else {
3415
//Action_12: Merge labels of block R and S
3416
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3417
continue;
3418
}
3419
}
3420
}
3421
else {
3422
//Action_12: Merge labels of block R and S
3423
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3424
continue;
3425
}
3426
}
3427
else {
3428
if (condition_i) {
3429
if (condition_m) {
3430
if (condition_h) {
3431
//Action_12: Merge labels of block R and S
3432
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3433
continue;
3434
}
3435
else {
3436
if (condition_g) {
3437
if (condition_b) {
3438
//Action_12: Merge labels of block R and S
3439
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3440
continue;
3441
}
3442
else {
3443
//Action_16: labels of block Q, R and S
3444
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
3445
continue;
3446
}
3447
}
3448
else {
3449
//Action_16: labels of block Q, R and S
3450
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
3451
continue;
3452
}
3453
}
3454
}
3455
else {
3456
//Action_16: labels of block Q, R and S
3457
imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
3458
continue;
3459
}
3460
}
3461
else {
3462
//Action_12: Merge labels of block R and S
3463
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
3464
continue;
3465
}
3466
}
3467
}
3468
else {
3469
if (condition_i) {
3470
if (condition_m) {
3471
if (condition_h) {
3472
//Action_6: Assign label of block S
3473
imgLabels_row[c] = imgLabels_row[c - 2];
3474
continue;
3475
}
3476
else {
3477
if (condition_g) {
3478
if (condition_b) {
3479
//Action_6: Assign label of block S
3480
imgLabels_row[c] = imgLabels_row[c - 2];
3481
continue;
3482
}
3483
else {
3484
//Action_11: Merge labels of block Q and S
3485
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3486
continue;
3487
}
3488
}
3489
else {
3490
//Action_11: Merge labels of block Q and S
3491
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3492
continue;
3493
}
3494
}
3495
}
3496
else {
3497
//Action_11: Merge labels of block Q and S
3498
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
3499
continue;
3500
}
3501
}
3502
else {
3503
//Action_6: Assign label of block S
3504
imgLabels_row[c] = imgLabels_row[c - 2];
3505
continue;
3506
}
3507
}
3508
}
3509
}
3510
else {
3511
if (condition_j) {
3512
//Action_4: Assign label of block Q
3513
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3514
continue;
3515
}
3516
else {
3517
if (condition_k) {
3518
if (condition_i) {
3519
if (condition_d) {
3520
//Action_5: Assign label of block R
3521
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3522
continue;
3523
}
3524
else {
3525
// ACTION_10 Merge labels of block Q and R
3526
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
3527
continue;
3528
}
3529
}
3530
else {
3531
//Action_5: Assign label of block R
3532
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3533
continue;
3534
}
3535
}
3536
else {
3537
if (condition_i) {
3538
//Action_4: Assign label of block Q
3539
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3540
continue;
3541
}
3542
else {
3543
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3544
imgLabels_row[c] = lunique;
3545
P[lunique] = lunique;
3546
lunique = lunique + 1;
3547
continue;
3548
}
3549
}
3550
}
3551
}
3552
}
3553
}
3554
else {
3555
if (condition_r) {
3556
//Action_6: Assign label of block S
3557
imgLabels_row[c] = imgLabels_row[c - 2];
3558
continue;
3559
}
3560
else {
3561
if (condition_n) {
3562
//Action_6: Assign label of block S
3563
imgLabels_row[c] = imgLabels_row[c - 2];
3564
continue;
3565
}
3566
else {
3567
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3568
imgLabels_row[c] = lunique;
3569
P[lunique] = lunique;
3570
lunique = lunique + 1;
3571
continue;
3572
}
3573
}
3574
}
3575
}
3576
else {
3577
if (condition_p) {
3578
if (condition_j) {
3579
//Action_4: Assign label of block Q
3580
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3581
continue;
3582
}
3583
else {
3584
if (condition_k) {
3585
if (condition_i) {
3586
if (condition_d) {
3587
//Action_5: Assign label of block R
3588
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3589
continue;
3590
}
3591
else {
3592
// ACTION_10 Merge labels of block Q and R
3593
imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
3594
continue;
3595
}
3596
}
3597
else {
3598
//Action_5: Assign label of block R
3599
imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
3600
continue;
3601
}
3602
}
3603
else {
3604
if (condition_i) {
3605
//Action_4: Assign label of block Q
3606
imgLabels_row[c] = imgLabels_row_prev_prev[c];
3607
continue;
3608
}
3609
else {
3610
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3611
imgLabels_row[c] = lunique;
3612
P[lunique] = lunique;
3613
lunique = lunique + 1;
3614
continue;
3615
}
3616
}
3617
}
3618
}
3619
else {
3620
if (condition_t) {
3621
//Action_2: New label (the block has foreground pixels and is not connected to anything else)
3622
imgLabels_row[c] = lunique;
3623
P[lunique] = lunique;
3624
lunique = lunique + 1;
3625
continue;
3626
}
3627
else {
3628
// Action_1: No action (the block has no foreground pixels)
3629
imgLabels_row[c] = 0;
3630
continue;
3631
}
3632
}
3633
}
3634
}
3635
}
3636
3637
}
3638
3639
// Second scan + analysis
3640
LabelT nLabels = flattenL(P, lunique);
3641
sop.init(nLabels);
3642
3643
if (imgLabels.rows & 1){
3644
if (imgLabels.cols & 1){
3645
//Case 1: both rows and cols odd
3646
for (int r = 0; r < imgLabels.rows; r += 2) {
3647
// Get rows pointer
3648
const PixelT * const img_row = img.ptr<PixelT>(r);
3649
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
3650
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
3651
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
3652
3653
for (int c = 0; c < imgLabels.cols; c += 2) {
3654
LabelT iLabel = imgLabels_row[c];
3655
if (iLabel > 0) {
3656
iLabel = P[iLabel];
3657
if (img_row[c] > 0){
3658
imgLabels_row[c] = iLabel;
3659
sop(r, c, iLabel);
3660
}
3661
else{
3662
imgLabels_row[c] = 0;
3663
sop(r, c, 0);
3664
}
3665
if (c + 1 < imgLabels.cols) {
3666
if (img_row[c + 1] > 0){
3667
imgLabels_row[c + 1] = iLabel;
3668
sop(r, c + 1, iLabel);
3669
}
3670
else{
3671
imgLabels_row[c + 1] = 0;
3672
sop(r, c + 1, 0);
3673
}
3674
if (r + 1 < imgLabels.rows) {
3675
if (img_row_fol[c] > 0){
3676
imgLabels_row_fol[c] = iLabel;
3677
sop(r + 1, c, iLabel);
3678
}
3679
else{
3680
imgLabels_row_fol[c] = 0;
3681
sop(r + 1, c, 0);
3682
}
3683
if (img_row_fol[c + 1] > 0){
3684
imgLabels_row_fol[c + 1] = iLabel;
3685
sop(r + 1, c + 1, iLabel);
3686
}
3687
else{
3688
imgLabels_row_fol[c + 1] = 0;
3689
sop(r + 1, c + 1, 0);
3690
}
3691
}
3692
}
3693
else if (r + 1 < imgLabels.rows) {
3694
if (img_row_fol[c] > 0){
3695
imgLabels_row_fol[c] = iLabel;
3696
sop(r + 1, c, iLabel);
3697
}
3698
else{
3699
imgLabels_row_fol[c] = 0;
3700
sop(r + 1, c, 0);
3701
}
3702
}
3703
}
3704
else {
3705
imgLabels_row[c] = 0;
3706
sop(r, c, 0);
3707
if (c + 1 < imgLabels.cols) {
3708
imgLabels_row[c + 1] = 0;
3709
sop(r, c + 1, 0);
3710
if (r + 1 < imgLabels.rows) {
3711
imgLabels_row_fol[c] = 0;
3712
imgLabels_row_fol[c + 1] = 0;
3713
sop(r + 1, c, 0);
3714
sop(r + 1, c + 1, 0);
3715
}
3716
}
3717
else if (r + 1 < imgLabels.rows) {
3718
imgLabels_row_fol[c] = 0;
3719
sop(r + 1, c, 0);
3720
}
3721
}
3722
}
3723
}
3724
}//END Case 1
3725
else{
3726
//Case 2: only rows odd
3727
for (int r = 0; r < imgLabels.rows; r += 2) {
3728
// Get rows pointer
3729
const PixelT * const img_row = img.ptr<PixelT>(r);
3730
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
3731
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
3732
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
3733
3734
for (int c = 0; c < imgLabels.cols; c += 2) {
3735
LabelT iLabel = imgLabels_row[c];
3736
if (iLabel > 0) {
3737
iLabel = P[iLabel];
3738
if (img_row[c] > 0){
3739
imgLabels_row[c] = iLabel;
3740
sop(r, c, iLabel);
3741
}
3742
else{
3743
imgLabels_row[c] = 0;
3744
sop(r, c, 0);
3745
}
3746
if (img_row[c + 1] > 0){
3747
imgLabels_row[c + 1] = iLabel;
3748
sop(r, c + 1, iLabel);
3749
}
3750
else{
3751
imgLabels_row[c + 1] = 0;
3752
sop(r, c + 1, 0);
3753
}
3754
if (r + 1 < imgLabels.rows) {
3755
if (img_row_fol[c] > 0){
3756
imgLabels_row_fol[c] = iLabel;
3757
sop(r + 1, c, iLabel);
3758
}
3759
else{
3760
imgLabels_row_fol[c] = 0;
3761
sop(r + 1, c, 0);
3762
}
3763
if (img_row_fol[c + 1] > 0){
3764
imgLabels_row_fol[c + 1] = iLabel;
3765
sop(r + 1, c + 1, iLabel);
3766
}
3767
else{
3768
imgLabels_row_fol[c + 1] = 0;
3769
sop(r + 1, c + 1, 0);
3770
}
3771
}
3772
}
3773
else {
3774
imgLabels_row[c] = 0;
3775
imgLabels_row[c + 1] = 0;
3776
sop(r, c, 0);
3777
sop(r, c + 1, 0);
3778
if (r + 1 < imgLabels.rows) {
3779
imgLabels_row_fol[c] = 0;
3780
imgLabels_row_fol[c + 1] = 0;
3781
sop(r + 1, c, 0);
3782
sop(r + 1, c + 1, 0);
3783
}
3784
}
3785
}
3786
}
3787
}// END Case 2
3788
}
3789
else{
3790
if (imgLabels.cols & 1){
3791
//Case 3: only cols odd
3792
for (int r = 0; r < imgLabels.rows; r += 2) {
3793
// Get rows pointer
3794
const PixelT * const img_row = img.ptr<PixelT>(r);
3795
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
3796
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
3797
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
3798
3799
for (int c = 0; c < imgLabels.cols; c += 2) {
3800
LabelT iLabel = imgLabels_row[c];
3801
if (iLabel > 0) {
3802
iLabel = P[iLabel];
3803
if (img_row[c] > 0){
3804
imgLabels_row[c] = iLabel;
3805
sop(r, c, iLabel);
3806
}
3807
else{
3808
imgLabels_row[c] = 0;
3809
sop(r, c, 0);
3810
}
3811
if (img_row_fol[c] > 0){
3812
imgLabels_row_fol[c] = iLabel;
3813
sop(r + 1, c, iLabel);
3814
}
3815
else{
3816
imgLabels_row_fol[c] = 0;
3817
sop(r + 1, c, 0);
3818
}
3819
if (c + 1 < imgLabels.cols) {
3820
if (img_row[c + 1] > 0){
3821
imgLabels_row[c + 1] = iLabel;
3822
sop(r, c + 1, iLabel);
3823
}
3824
else{
3825
imgLabels_row[c + 1] = 0;
3826
sop(r, c + 1, 0);
3827
}
3828
if (img_row_fol[c + 1] > 0){
3829
imgLabels_row_fol[c + 1] = iLabel;
3830
sop(r + 1, c + 1, iLabel);
3831
}
3832
else{
3833
imgLabels_row_fol[c + 1] = 0;
3834
sop(r + 1, c + 1, 0);
3835
}
3836
}
3837
}
3838
else{
3839
imgLabels_row[c] = 0;
3840
imgLabels_row_fol[c] = 0;
3841
sop(r, c, 0);
3842
sop(r + 1, c, 0);
3843
if (c + 1 < imgLabels.cols) {
3844
imgLabels_row[c + 1] = 0;
3845
imgLabels_row_fol[c + 1] = 0;
3846
sop(r, c + 1, 0);
3847
sop(r + 1, c + 1, 0);
3848
}
3849
}
3850
}
3851
}
3852
}// END case 3
3853
else{
3854
//Case 4: nothing odd
3855
for (int r = 0; r < imgLabels.rows; r += 2) {
3856
// Get rows pointer
3857
const PixelT * const img_row = img.ptr<PixelT>(r);
3858
const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
3859
LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
3860
LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
3861
3862
for (int c = 0; c < imgLabels.cols; c += 2) {
3863
LabelT iLabel = imgLabels_row[c];
3864
if (iLabel > 0) {
3865
iLabel = P[iLabel];
3866
if (img_row[c] > 0){
3867
imgLabels_row[c] = iLabel;
3868
sop(r, c, iLabel);
3869
}
3870
else{
3871
imgLabels_row[c] = 0;
3872
sop(r, c, 0);
3873
}
3874
if (img_row[c + 1] > 0){
3875
imgLabels_row[c + 1] = iLabel;
3876
sop(r, c + 1, iLabel);
3877
}
3878
else{
3879
imgLabels_row[c + 1] = 0;
3880
sop(r, c + 1, 0);
3881
}
3882
if (img_row_fol[c] > 0){
3883
imgLabels_row_fol[c] = iLabel;
3884
sop(r + 1, c, iLabel);
3885
}
3886
else{
3887
imgLabels_row_fol[c] = 0;
3888
sop(r + 1, c, 0);
3889
}
3890
if (img_row_fol[c + 1] > 0){
3891
imgLabels_row_fol[c + 1] = iLabel;
3892
sop(r + 1, c + 1, iLabel);
3893
}
3894
else{
3895
imgLabels_row_fol[c + 1] = 0;
3896
sop(r + 1, c + 1, 0);
3897
}
3898
}
3899
else {
3900
imgLabels_row[c] = 0;
3901
imgLabels_row[c + 1] = 0;
3902
imgLabels_row_fol[c] = 0;
3903
imgLabels_row_fol[c + 1] = 0;
3904
sop(r, c, 0);
3905
sop(r, c + 1, 0);
3906
sop(r + 1, c, 0);
3907
sop(r + 1, c + 1, 0);
3908
}
3909
}
3910
}
3911
}//END case 4
3912
}
3913
3914
sop.finish();
3915
fastFree(P);
3916
3917
return nLabels;
3918
3919
} //End function LabelingGrana operator()
3920
};//End struct LabelingGrana
3921
}//end namespace connectedcomponents
3922
3923
//L's type must have an appropriate depth for the number of pixels in I
3924
template<typename StatsOp>
3925
static
3926
int connectedComponents_sub1(const cv::Mat& I, cv::Mat& L, int connectivity, int ccltype, StatsOp& sop){
3927
CV_Assert(L.channels() == 1 && I.channels() == 1);
3928
CV_Assert(connectivity == 8 || connectivity == 4);
3929
CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT);
3930
3931
int lDepth = L.depth();
3932
int iDepth = I.depth();
3933
const char *currentParallelFramework = cv::currentParallelFramework();
3934
const int nThreads = cv::getNumThreads();
3935
3936
CV_Assert(iDepth == CV_8U || iDepth == CV_8S);
3937
3938
//Run parallel labeling only if the rows of the image are at least twice the number of available threads
3939
const bool is_parallel = currentParallelFramework != NULL && nThreads > 1 && L.rows / nThreads >= 2;
3940
3941
if (ccltype == CCL_WU || connectivity == 4){
3942
// Wu algorithm is used
3943
using connectedcomponents::LabelingWu;
3944
using connectedcomponents::LabelingWuParallel;
3945
//warn if L's depth is not sufficient?
3946
if (lDepth == CV_8U){
3947
//Not supported yet
3948
}
3949
else if (lDepth == CV_16U){
3950
return (int)LabelingWu<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
3951
}
3952
else if (lDepth == CV_32S){
3953
//note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
3954
//OpenCV: how should we proceed? .at<T> typechecks in debug mode
3955
if (!is_parallel)
3956
return (int)LabelingWu<int, uchar, StatsOp>()(I, L, connectivity, sop);
3957
else
3958
return (int)LabelingWuParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);
3959
}
3960
}
3961
else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){
3962
// Grana algorithm is used
3963
using connectedcomponents::LabelingGrana;
3964
using connectedcomponents::LabelingGranaParallel;
3965
//warn if L's depth is not sufficient?
3966
if (lDepth == CV_8U){
3967
//Not supported yet
3968
}
3969
else if (lDepth == CV_16U){
3970
return (int)LabelingGrana<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
3971
}
3972
else if (lDepth == CV_32S){
3973
//note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
3974
//OpenCV: how should we proceed? .at<T> typechecks in debug mode
3975
if (!is_parallel)
3976
return (int)LabelingGrana<int, uchar, StatsOp>()(I, L, connectivity, sop);
3977
else
3978
return (int)LabelingGranaParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);
3979
}
3980
}
3981
3982
CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");
3983
}
3984
3985
}
3986
3987
// Simple wrapper to ensure binary and source compatibility (ABI)
3988
int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype){
3989
return cv::connectedComponents(img_, _labels, connectivity, ltype, CCL_DEFAULT);
3990
}
3991
3992
int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype, int ccltype){
3993
const cv::Mat img = img_.getMat();
3994
_labels.create(img.size(), CV_MAT_DEPTH(ltype));
3995
cv::Mat labels = _labels.getMat();
3996
connectedcomponents::NoOp sop;
3997
if (ltype == CV_16U){
3998
return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
3999
}
4000
else if (ltype == CV_32S){
4001
return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
4002
}
4003
else{
4004
CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
4005
}
4006
}
4007
4008
// Simple wrapper to ensure binary and source compatibility (ABI)
4009
int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv,
4010
OutputArray centroids, int connectivity, int ltype)
4011
{
4012
return cv::connectedComponentsWithStats(img_, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT);
4013
}
4014
4015
int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv,
4016
OutputArray centroids, int connectivity, int ltype, int ccltype)
4017
{
4018
const cv::Mat img = img_.getMat();
4019
_labels.create(img.size(), CV_MAT_DEPTH(ltype));
4020
cv::Mat labels = _labels.getMat();
4021
connectedcomponents::CCStatsOp sop(statsv, centroids);
4022
if (ltype == CV_16U){
4023
return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
4024
}
4025
else if (ltype == CV_32S){
4026
return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
4027
}
4028
else{
4029
CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
4030
return 0;
4031
}
4032
}
4033
4034