From 0bc9a0db18e750f3c66f72948cb714a0c9d540be Mon Sep 17 00:00:00 2001 From: Michele Cancilla Date: Tue, 22 Nov 2016 11:42:13 +0100 Subject: [PATCH 1/6] Improvement of sequential connected components Wu's algorithm and provide parallel version of both Wu's and Grana's algorithms (using TBB library) --- modules/imgproc/src/connectedcomponents.cpp | 4549 ++++++++++++++----- 1 file changed, 3403 insertions(+), 1146 deletions(-) diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index bf53704144..00fa8d0eb4 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -42,6 +42,7 @@ // 2016 Federico Bolelli // 2016 Lorenzo Baraldi // 2016 Roberto Vezzani +// 2016 Michele Cancilla //M*/ // #include "precomp.hpp" @@ -50,414 +51,860 @@ namespace cv{ namespace connectedcomponents{ - struct NoOp{ - NoOp(){ - } - void init(int /*labels*/){ - } - inline - void operator()(int r, int c, int l){ - (void) r; - (void) c; - (void) l; - } - void finish(){} - }; - struct Point2ui64{ - uint64 x, y; - Point2ui64(uint64 _x, uint64 _y):x(_x), y(_y){} - }; - - struct CCStatsOp{ - const _OutputArray* _mstatsv; - cv::Mat statsv; - const _OutputArray* _mcentroidsv; - cv::Mat centroidsv; - std::vector integrals; - - CCStatsOp(OutputArray _statsv, OutputArray _centroidsv): _mstatsv(&_statsv), _mcentroidsv(&_centroidsv){ - } - inline - void init(int nlabels){ - _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); - statsv = _mstatsv->getMat(); - _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); - centroidsv = _mcentroidsv->getMat(); - - for(int l = 0; l < (int) nlabels; ++l){ - int *row = (int *) &statsv.at(l, 0); - row[CC_STAT_LEFT] = INT_MAX; - row[CC_STAT_TOP] = INT_MAX; - row[CC_STAT_WIDTH] = INT_MIN; - row[CC_STAT_HEIGHT] = INT_MIN; - row[CC_STAT_AREA] = 0; + struct NoOp{ + NoOp(){ } - integrals.resize(nlabels, Point2ui64(0, 0)); - } - void operator()(int r, int c, int l){ - int *row = &statsv.at(l, 0); - row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c); - row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c); - row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r); - row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r); - row[CC_STAT_AREA]++; - Point2ui64 &integral = integrals[l]; - integral.x += c; - integral.y += r; - } - void finish(){ - for(int l = 0; l < statsv.rows; ++l){ + inline + void init(int /*labels*/){ + } + + inline + void initElement(const int /*nlabels*/){ + } + + inline + void operator()(int r, int c, int l){ + (void)r; + (void)c; + (void)l; + } + + void finish(){} + + inline + void setNextLoc(const int /*nextLoc*/){ + } + + inline static + void mergeStats(const cv::Mat& /*imgLabels*/, NoOp* /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){ + } + + }; + struct Point2ui64{ + uint64 x, y; + Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){} + }; + + struct CCStatsOp{ + const _OutputArray* _mstatsv; + cv::Mat statsv; + const _OutputArray* _mcentroidsv; + cv::Mat centroidsv; + std::vector integrals; + int _nextLoc; + + CCStatsOp(){} + CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv){} + + inline + void init(int nlabels){ + _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); + statsv = _mstatsv->getMat(); + _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); + centroidsv = _mcentroidsv->getMat(); + + for (int l = 0; l < (int)nlabels; ++l){ + int *row = (int *)&statsv.at(l, 0); + row[CC_STAT_LEFT] = INT_MAX; + row[CC_STAT_TOP] = INT_MAX; + row[CC_STAT_WIDTH] = INT_MIN; + row[CC_STAT_HEIGHT] = INT_MIN; + row[CC_STAT_AREA] = 0; + } + integrals.resize(nlabels, Point2ui64(0, 0)); + } + + inline + void initElement(const int nlabels){ + statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); + for (int l = 0; l < (int)nlabels; ++l){ + int *row = (int *)statsv.ptr(l); + row[CC_STAT_LEFT] = INT_MAX; + row[CC_STAT_TOP] = INT_MAX; + row[CC_STAT_WIDTH] = INT_MIN; + row[CC_STAT_HEIGHT] = INT_MIN; + row[CC_STAT_AREA] = 0; + } + integrals.resize(nlabels, Point2ui64(0, 0)); + } + + void operator()(int r, int c, int l){ int *row = &statsv.at(l, 0); - row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1; - row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; - + row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c); + row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c); + row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r); + row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r); + row[CC_STAT_AREA]++; Point2ui64 &integral = integrals[l]; - double *centroid = ¢roidsv.at(l, 0); - double area = ((unsigned*)row)[CC_STAT_AREA]; - centroid[0] = double(integral.x) / area; - centroid[1] = double(integral.y) / area; + integral.x += c; + integral.y += r; } - } - }; - //Find the root of the tree of node i - template - inline static - LabelT findRoot(const LabelT *P, LabelT i){ - LabelT root = i; - while(P[root] < root){ - root = P[root]; - } - return root; - } + void finish(){ + for (int l = 0; l < statsv.rows; ++l){ + int *row = &statsv.at(l, 0); + row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1; + row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; - //Make all nodes in the path of node i point to root - template - inline static - void setRoot(LabelT *P, LabelT i, LabelT root){ - while(P[i] < i){ - LabelT j = P[i]; - P[i] = root; - i = j; - } - P[i] = root; - } - - //Find the root of the tree of the node i and compress the path in the process - template - inline static - LabelT find(LabelT *P, LabelT i){ - LabelT root = findRoot(P, i); - setRoot(P, i, root); - return root; - } - - //unite the two trees containing nodes i and j and return the new root - template - inline static - LabelT set_union(LabelT *P, LabelT i, LabelT j){ - LabelT root = findRoot(P, i); - if(i != j){ - LabelT rootj = findRoot(P, j); - if(root > rootj){ - root = rootj; + Point2ui64 &integral = integrals[l]; + double *centroid = ¢roidsv.at(l, 0); + double area = ((unsigned*)row)[CC_STAT_AREA]; + centroid[0] = double(integral.x) / area; + centroid[1] = double(integral.y) / area; + } } - setRoot(P, j, root); - } - setRoot(P, i, root); - return root; - } - //Flatten the Union Find tree and relabel the components - template - inline static - LabelT flattenL(LabelT *P, LabelT length){ - LabelT k = 1; - for(LabelT i = 1; i < length; ++i){ - if(P[i] < i){ - P[i] = P[P[i]]; - }else{ - P[i] = k; k = k + 1; - } - } - return k; - } + inline + void setNextLoc(const int nextLoc){ + _nextLoc = nextLoc; + } - //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant - //using decision trees - //Kesheng Wu, et al - //Note: rows are encoded as position in the "rows" array to save lookup times - //reference for 4-way: {{-1, 0}, {0, -1}};//b, d neighborhoods - const int G4[2][2] = {{1, 0}, {0, -1}};//b, d neighborhoods - //reference for 8-way: {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}};//a, b, c, d neighborhoods - const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods - template - struct LabelingWu{ - LabelT operator()(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp &sop){ - CV_Assert(L.rows == I.rows); - CV_Assert(L.cols == I.cols); - CV_Assert(connectivity == 8 || connectivity == 4); - const int rows = L.rows; - const int cols = L.cols; - //A quick and dirty upper bound for the maximimum number of labels. The 4 comes from - //the fact that a 3x3 block can never have more than 4 unique labels for both 4 & 8-way - const size_t Plength = 4 * (size_t(rows + 3 - 1)/3) * (size_t(cols + 3 - 1)/3); - LabelT *P = (LabelT *) fastMalloc(sizeof(LabelT) * Plength); - P[0] = 0; - LabelT lunique = 1; - //scanning phase - for(int r_i = 0; r_i < rows; ++r_i){ - LabelT * const Lrow = L.ptr(r_i); - LabelT * const Lrow_prev = (LabelT *)(((char *)Lrow) - L.step.p[0]); - const PixelT * const Irow = I.ptr(r_i); - const PixelT * const Irow_prev = (const PixelT *)(((char *)Irow) - I.step.p[0]); - LabelT *Lrows[2] = { - Lrow, - Lrow_prev - }; - const PixelT *Irows[2] = { - Irow, - Irow_prev - }; - if(connectivity == 8){ - const int a = 0; - const int b = 1; - const int c = 2; - const int d = 3; - const bool T_a_r = (r_i - G8[a][0]) >= 0; - const bool T_b_r = (r_i - G8[b][0]) >= 0; - const bool T_c_r = (r_i - G8[c][0]) >= 0; - for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){ - if(!*Irows[0]){ - Lrow[c_i] = 0; - continue; - } - Irows[1] = Irow_prev + c_i; - Lrows[0] = Lrow + c_i; - Lrows[1] = Lrow_prev + c_i; - const bool T_a = T_a_r && (c_i + G8[a][1]) >= 0 && *(Irows[G8[a][0]] + G8[a][1]); - const bool T_b = T_b_r && *(Irows[G8[b][0]] + G8[b][1]); - const bool T_c = T_c_r && (c_i + G8[c][1]) < cols && *(Irows[G8[c][0]] + G8[c][1]); - const bool T_d = (c_i + G8[d][1]) >= 0 && *(Irows[G8[d][0]] + G8[d][1]); + inline static + void mergeStats(const cv::Mat &imgLabels, CCStatsOp *SopArray, CCStatsOp &sop, const int &nLabels){ + const int h = imgLabels.rows; - //decision tree - if(T_b){ - //copy(b) - *Lrows[0] = *(Lrows[G8[b][0]] + G8[b][1]); - }else{//not b - if(T_c){ - if(T_a){ - //copy(c, a) - *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] + G8[c][1]), *(Lrows[G8[a][0]] + G8[a][1])); - }else{ - if(T_d){ - //copy(c, d) - *Lrows[0] = set_union(P, *(Lrows[G8[c][0]] + G8[c][1]), *(Lrows[G8[d][0]] + G8[d][1])); - }else{ - //copy(c) - *Lrows[0] = *(Lrows[G8[c][0]] + G8[c][1]); - } - } - }else{//not c - if(T_a){ - //copy(a) - *Lrows[0] = *(Lrows[G8[a][0]] + G8[a][1]); - }else{ - if(T_d){ - //copy(d) - *Lrows[0] = *(Lrows[G8[d][0]] + G8[d][1]); - }else{ - //new label - *Lrows[0] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; + if (sop._nextLoc != h){ + for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = SopArray[nextLoc]._nextLoc){ + //merge between sopNext and sop + for (int l = 0; l < nLabels; ++l){ + int *rowNext = (int*)SopArray[nextLoc].statsv.ptr(l); + if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats + int *rowMerged = (int*)sop.statsv.ptr(l); + rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]); + rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]); + rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]); + rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]); + rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA]; + + sop.integrals[l].x += SopArray[nextLoc].integrals[l].x; + sop.integrals[l].y += SopArray[nextLoc].integrals[l].y; } } } } } - }else{ - //B & D only - const int b = 0; - const int d = 1; - const bool T_b_r = (r_i - G4[b][0]) >= 0; - for(int c_i = 0; Irows[0] != Irow + cols; ++Irows[0], c_i++){ - if(!*Irows[0]){ - Lrow[c_i] = 0; - continue; + + }; + + //Find the root of the tree of node i + template + inline static + LabelT findRoot(const LabelT *P, LabelT i){ + LabelT root = i; + while (P[root] < root){ + root = P[root]; + } + return root; + } + + //Make all nodes in the path of node i point to root + template + inline static + void setRoot(LabelT *P, LabelT i, LabelT root){ + while (P[i] < i){ + LabelT j = P[i]; + P[i] = root; + i = j; + } + P[i] = root; + } + + //Find the root of the tree of the node i and compress the path in the process + template + inline static + LabelT find(LabelT *P, LabelT i){ + LabelT root = findRoot(P, i); + setRoot(P, i, root); + return root; + } + + //unite the two trees containing nodes i and j and return the new root + template + inline static + LabelT set_union(LabelT *P, LabelT i, LabelT j){ + LabelT root = findRoot(P, i); + if (i != j){ + LabelT rootj = findRoot(P, j); + if (root > rootj){ + root = rootj; } - Irows[1] = Irow_prev + c_i; - Lrows[0] = Lrow + c_i; - Lrows[1] = Lrow_prev + c_i; - const bool T_b = T_b_r && *(Irows[G4[b][0]] + G4[b][1]); - const bool T_d = (c_i + G4[d][1]) >= 0 && *(Irows[G4[d][0]] + G4[d][1]); - if(T_b){ - if(T_d){ - //copy(d, b) - *Lrows[0] = set_union(P, *(Lrows[G4[d][0]] + G4[d][1]), *(Lrows[G4[b][0]] + G4[b][1])); - }else{ - //copy(b) - *Lrows[0] = *(Lrows[G4[b][0]] + G4[b][1]); - } - }else{ - if(T_d){ - //copy(d) - *Lrows[0] = *(Lrows[G4[d][0]] + G4[d][1]); - }else{ - //new label - *Lrows[0] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - } + setRoot(P, j, root); + } + setRoot(P, i, root); + return root; + } + + //Flatten the Union Find tree and relabel the components + template + inline static + LabelT flattenL(LabelT *P, LabelT length){ + LabelT k = 1; + for (LabelT i = 1; i < length; ++i){ + if (P[i] < i){ + P[i] = P[P[i]]; + } + else{ + P[i] = k; k = k + 1; + } + } + return k; + } + + template + inline static + void flattenL(LabelT *P, const int start, const int nElem, LabelT &k){ + for (int i = start; i < start + nElem; ++i){ + if (P[i] < i){//node that point to root + P[i] = P[P[i]]; + } + else{ //for root node + P[i] = k; + k = k + 1; } } } - } - //analysis - LabelT nLabels = flattenL(P, lunique); - sop.init(nLabels); + //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant + //using decision trees + //Kesheng Wu, et al + template + struct LabelingWu{ +#ifdef HAVE_TBB +# if TBB_VERSION_MAJOR + TBB_VERSION_MINOR >= 2017 - for(int r_i = 0; r_i < rows; ++r_i){ - LabelT *Lrow_start = L.ptr(r_i); - LabelT *Lrow_end = Lrow_start + cols; - LabelT *Lrow = Lrow_start; - for(int c_i = 0; Lrow != Lrow_end; ++Lrow, ++c_i){ - const LabelT l = P[*Lrow]; - *Lrow = l; - sop(r_i, c_i, l); - } - } + class FirstScan8Connectivity{ + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; - sop.finish(); - fastFree(P); + public: + FirstScan8Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} - return nLabels; - }//End function LabelingWu operator() - };//End struct LabelingWu + FirstScan8Connectivity & operator=(const FirstScan8Connectivity &) { return *this; } - // Based on “Optimized Block-based Connected Components Labeling with Decision Trees”, Costantino Grana et al - // Only for 8-connectivity - template - struct LabelingGrana{ - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ - CV_Assert(img.rows == imgLabels.rows); - CV_Assert(img.cols == imgLabels.cols); - CV_Assert(connectivity == 8 || connectivity == 4); + void operator()(const tbb::blocked_range &range) const{ - const int h = img.rows; - const int w = img.cols; + int r = range.begin(); + _chunksSizeAndLabels[r] = range.end(); - //A quick and dirty upper bound for the maximimum number of labels. - const size_t Plength = img.rows*img.cols / 4; - LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); - P[0] = 0; - LabelT lunique = 1; + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); - // First scan - for (int r = 0; r(r); - const PixelT* const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - const PixelT* const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]); - const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT* const imgLabels_row = imgLabels.ptr(r); - LabelT* const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); - for (int c = 0; c < w; c += 2) { + const LabelT firstLabel = label; + const int w = _img.cols; + const int limitLine = r, startR = r; - // We work with 2x2 blocks - // +-+-+-+ - // |P|Q|R| - // +-+-+-+ - // |S|X| - // +-+-+ + // Rosenfeld Mask + // +-+-+-+ + // |p|q|r| + // +-+-+-+ + // |s|x| + // +-+-+ + for (; r != range.end(); ++r) + { + PixelT const * const img_row = _img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { - // The pixels are named as follows - // +---+---+---+ - // |a b|c d|e f| - // |g h|i j|k l| - // +---+---+---+ - // |m n|o p| - // |q r|s t| - // +---+---+ +#define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0 +#define condition_q r > limitLine && img_row_prev[c] > 0 +#define condition_r c < w - 1 && r > limitLine && img_row_prev[c + 1] > 0 +#define condition_s c > 0 && img_row[c - 1] > 0 +#define condition_x img_row[c] > 0 - // Pixels a, f, l, q are not needed, since we need to understand the - // the connectivity between these blocks and those pixels only metter - // when considering the outer connectivities - - // A bunch of defines used to check if the pixels are foreground, - // without going outside the image limits. - #define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0 - #define condition_c r-2>=0 && img_row_prev_prev[c]>0 - #define condition_d c+1=0 && img_row_prev_prev[c+1]>0 - #define condition_e c+2=0 && img_row_prev_prev[c+2]>0 - - #define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0 - #define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0 - #define condition_i r-1>=0 && img_row_prev[c]>0 - #define condition_j c+1=0 && img_row_prev[c+1]>0 - #define condition_k c+2=0 && img_row_prev[c+2]>0 - - #define condition_m c-2>=0 && img_row[c-2]>0 - #define condition_n c-1>=0 && img_row[c-1]>0 - #define condition_o img_row[c]>0 - #define condition_p c+10 - - #define condition_r c-1>=0 && r+10 - #define condition_s r+10 - #define condition_t c+10 - - // This is a decision tree which allows to choose which action to - // perform, checking as few conditions as possible. - // Actions: the blocks label are provisionally stored in the top left - // pixel of the block in the labels image - - if (condition_o) { - if (condition_n) { - if (condition_j) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; + if (condition_x){ + if (condition_q){ + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; + } + else{ + //not q + if (condition_r){ + if (condition_p){ + //concavity p->x->r. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); + } + else{ //not p and q + if (condition_s){ + //step s->x->r. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + else{ //not p, q and s + //copy r + imgLabels_row[c] = imgLabels_row_prev[c + 1]; } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + } + else{ + //not r and q + if (condition_p){ + //copy p + imgLabels_row[c] = imgLabels_row_prev[c - 1]; + } + else{//not r,q and p + if (condition_s){ + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + } } } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } + } + } + //write in the follower memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; + } +#undef condition_p +#undef condition_q +#undef condition_r +#undef condition_s +#undef condition_x + }; + + class FirstScan4Connectivity{ + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; + + public: + FirstScan4Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + + FirstScan4Connectivity & operator=(const FirstScan4Connectivity &) { return *this; } + + void operator()(const tbb::blocked_range &range) const{ + + int r = range.begin(); + _chunksSizeAndLabels[r] = range.end(); + + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + + const LabelT firstLabel = label; + const int w = _img.cols; + const int limitLine = r, startR = r; + + // Rosenfeld Mask + // +-+-+-+ + // |-|q|-| + // +-+-+-+ + // |s|x| + // +-+-+ + for (; r != range.end(); ++r){ + PixelT const * const img_row = _img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { + +#define condition_q r > limitLine && img_row_prev[c] > 0 +#define condition_s c > 0 && img_row[c - 1] > 0 +#define condition_x img_row[c] > 0 + + if (condition_x){ + if (condition_q){ + if (condition_s){ + //step s->x->q. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c]); + } + else{ + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; + } + } + else{ + if (condition_s){ // copy s + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + } + } + } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } + } + } + //write in the following memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; + } +#undef condition_q +#undef condition_s +#undef condition_x + }; + + class SecondScan{ + cv::Mat &_imgLabels; + const LabelT *_P; + StatsOp &_sop; + StatsOp *_sopArray; + LabelT &_nLabels; + public: + SecondScan(cv::Mat &imgLabels, const LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) + : _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + + SecondScan & operator=(const SecondScan &) { return *this; } + + void operator()(const tbb::blocked_range &range) const{ + + int r = range.begin(); + const int rowBegin = r; + const int rowEnd = range.end(); + + if (rowBegin > 0){ + _sopArray[rowBegin].initElement(_nLabels); + _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = range.second; + + for (; r < range.end(); ++r) { + LabelT * img_row_start = _imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + _imgLabels.cols; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = _P[*img_row_start]; + _sopArray[rowBegin](r, c, *img_row_start); + } + } + } + else{ + //the first thread use sop in order to make less merges + _sop.setNextLoc(rowEnd); + for (; r < range.end(); ++r) { + LabelT * img_row_start = _imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + _imgLabels.cols; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = _P[*img_row_start]; + _sop(r, c, *img_row_start); + } + } + } + } + }; + + inline static + void mergeLabels8Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + + // Merge Mask + // +-+-+-+ + // |p|q|r| + // +-+-+-+ + // |x| + // +-+ + const int w = imgLabels.cols, h = imgLabels.rows; + + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + + for (int c = 0; c < w; ++c){ + +#define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0 +#define condition_q imgLabels_row_prev[c] > 0 +#define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0 +#define condition_x imgLabels_row[c] > 0 + + if (condition_x){ + if (condition_p){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row[c]); + } + if (condition_r){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c + 1], imgLabels_row[c]); + } + if (condition_q){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); } } } - else { - if (condition_p) { - if (condition_k) { - if (condition_d) { + } +#undef condition_p +#undef condition_q +#undef condition_r +#undef condition_x + } + + inline static + void mergeLabels4Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + + // Merge Mask + // +-+-+-+ + // |-|q|-| + // +-+-+-+ + // |x| + // +-+ + const int w = imgLabels.cols, h = imgLabels.rows; + + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + + for (int c = 0; c < w; ++c){ + +#define condition_q imgLabels_row_prev[c] > 0 +#define condition_x imgLabels_row[c] > 0 + + if (condition_x){ + if (condition_q){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); + } + } + } + } +#undef condition_q +#undef condition_x + } + + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8 || connectivity == 4); + + const int nThreads = tbb::task_scheduler_init::default_num_threads(); + tbb::task_scheduler_init init(nThreads); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 4-way connectivity + //labeling can never have more than 2 new labels and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 1 0 1 0... + //1 0 1 0 1... + //............ + //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + + //Array used to store info and labeled pixel by each thread. + //Different threads affect different memory location of chunksSizeAndLabels + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + + //Tree of labels + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + //First label is for background + P[0] = 0; + + tbb::blocked_range range(0, h, h / nThreads); + + if (connectivity == 8){ + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + tbb::parallel_for(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); + + //merge labels of different chunks + mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels); + } + else{ + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + tbb::parallel_for(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); + + //merge labels of different chunks + mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); + } + LabelT nLabels = 1; + + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + } + + //Array for statistics dataof threads + StatsOp *SopArray = new StatsOp[h]; + + sop.init(nLabels); + //Second scan + tbb::parallel_for(range, SecondScan(imgLabels, P, sop, SopArray, nLabels), tbb::static_partitioner()); + StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + sop.finish(); + + delete[] SopArray; + cv::fastFree(chunksSizeAndLabels); + cv::fastFree(P); + return nLabels; + } +#endif +#else + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(imgLabels.rows == img.rows); + CV_Assert(imgLabels.cols == img.cols); + CV_Assert(connectivity == 8 || connectivity == 4); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 4-way connectivity + //labeling can never have more than 2 new labels and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 1 0 1 0... + //1 0 1 0 1... + //............ + //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + //array P for equivalences resolution + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); + //first label is for background pixels + P[0] = 0; + LabelT lunique = 1; + + if (connectivity == 8){ + for (int r = 0; r < h; ++r){ + // Get row pointers + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + + for (int c = 0; c < w; ++c){ + +#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0 +#define condition_q r>0 && img_row_prev[c]>0 +#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0 +#define condition_s c > 0 && img_row[c - 1] > 0 +#define condition_x img_row[c] > 0 + + if (condition_x){ + if (condition_q){ + //x <- q + imgLabels_row[c] = imgLabels_row_prev[c]; + } + else{ + // q = 0 + if (condition_r){ + if (condition_p){ + // x <- merge(p,r) + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); + } + else{ + // p = q = 0 + if (condition_s){ + // x <- merge(s,r) + imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); + } + else{ + // p = q = s = 0 + // x <- r + imgLabels_row[c] = imgLabels_row_prev[c + 1]; + } + } + } + else{ + // r = q = 0 + if (condition_p){ + // x <- p + imgLabels_row[c] = imgLabels_row_prev[c - 1]; + } + else{ + // r = q = p = 0 + if (condition_s){ + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + } + } + } + } + } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } + } + } +#undef condition_p +#undef condition_q +#undef condition_r +#undef condition_s +#undef condition_x + } + else{ + for (int r = 0; r < h; ++r){ + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { + +#define condition_q r > 0 && img_row_prev[c] > 0 +#define condition_s c > 0 && img_row[c - 1] > 0 +#define condition_x img_row[c] > 0 + + if (condition_x){ + if (condition_q){ + if (condition_s){ + //Merge s->x->q + imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]); + } + else{ + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; + } + } + else{ + if (condition_s){ + // copy s + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + } + } + } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } + } + } +#undef condition_q +#undef condition_s +#undef condition_x + } + + //analysis + LabelT nLabels = flattenL(P, lunique); + sop.init(nLabels); + + for (int r = 0; r < h; ++r) { + LabelT * img_row_start = imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + w; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = P[*img_row_start]; + sop(r, c, *img_row_start); + } + } + + sop.finish(); + fastFree(P); + + return nLabels; + }//End function LabelingWu operator() +#endif + };//End struct LabelingWu + + // Based on “Optimized Block-based Connected Components Labeling with Decision Trees”, Costantino Grana et al + // Only for 8-connectivity + template + struct LabelingGrana{ +#ifdef HAVE_TBB +# if TBB_VERSION_MAJOR + TBB_VERSION_MINOR >= 2017 + + class FirstScan{ + private: + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; + + public: + FirstScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + + FirstScan & operator=(const FirstScan&) { return *this; } + + void operator()(const tbb::blocked_range &range) const{ + + int r = range.begin(); + r += (r % 2); + + _chunksSizeAndLabels[r] = range.end() + (range.end() % 2); + + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + + const LabelT firstLabel = label; + const int h = _img.rows, w = _img.cols; + const int limitLine = r + 1, startR = r; + + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - _img.step.p[0]); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0] - _imgLabels.step.p[0]); + for (int c = 0; c < w; c += 2) { + + // We work with 2x2 blocks + // +-+-+-+ + // |P|Q|R| + // +-+-+-+ + // |S|X| + // +-+-+ + + // The pixels are named as follows + // +---+---+---+ + // |a b|c d|e f| + // |g h|i j|k l| + // +---+---+---+ + // |m n|o p| + // |q r|s t| + // +---+---+ + + // Pixels a, f, l, q are not needed, since we need to understand the + // the connectivity between these blocks and those pixels only metter + // when considering the outer connectivities + + // A bunch of defines used to check if the pixels are foreground, + // without going outside the image limits. + +#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0 +#define condition_c r > limitLine && img_row_prev_prev[c]>0 +#define condition_d c+1 limitLine && img_row_prev_prev[c+1]>0 +#define condition_e c+2 limitLine && img_row_prev_prev[c+2]>0 + +#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0 +#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0 +#define condition_i r > limitLine - 1 && img_row_prev[c]>0 +#define condition_j c+1 limitLine - 1 && img_row_prev[c+1]>0 +#define condition_k c+2 limitLine - 1 && img_row_prev[c+2]>0 + +#define condition_m c-2>=0 && img_row[c-2]>0 +#define condition_n c-1>=0 && img_row[c-1]>0 +#define condition_o img_row[c]>0 +#define condition_p c+10 + +#define condition_r c-1>=0 && r+10 +#define condition_s r+10 +#define condition_t c+10 + + // This is a decision tree which allows to choose which action to + // perform, checking as few conditions as possible. + // Actions are available after the tree. + + if (condition_o) { + if (condition_n) { + if (condition_j) { if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -478,134 +925,92 @@ namespace cv{ continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - else { - if (condition_r) { - if (condition_j) { - if (condition_m) { - if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { + if (condition_p) { + if (condition_k) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } } } else { - if (condition_i) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_h) { - if (condition_c) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - //Action_14: Merge labels of block P, Q and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_p) { - if (condition_k) { - if (condition_m) { - if (condition_h) { - if (condition_d) { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -618,20 +1023,13 @@ namespace cv{ continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_d) { if (condition_g) { if (condition_b) { if (condition_i) { @@ -646,298 +1044,826 @@ namespace cv{ continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } + } + else { + if (condition_i) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } else { - if (condition_i) { - if (condition_g) { - if (condition_b) { + if (condition_h) { + if (condition_c) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + else { + //Action_14: Merge labels of block _P, Q and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_m) { + if (condition_h) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_d) { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + } + else { + if (condition_i) { + if (condition_d) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_15: Merge labels of block _P, R and S + 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]); + continue; + } + } + else { + //Action_15: Merge labels of block _P, R and S + 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]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_i) { - if (condition_d) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_h) { - if (condition_d) { - if (condition_c) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_15: Merge labels of block P, R and S - 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]); - continue; - } - } - else { - //Action_15: Merge labels of block P, R and S - 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]); - continue; - } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_h) { - if (condition_m) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - // ACTION_9 Merge labels of block P and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_g) { - if (condition_b) { + if (condition_h) { + if (condition_m) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + // ACTION_9 Merge labels of block _P and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); continue; } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - } - else { - if (condition_h) { - if (condition_m) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - // ACTION_9 Merge labels of block P and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_g) { - if (condition_b) { + if (condition_h) { + if (condition_m) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + // ACTION_9 Merge labels of block _P and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); continue; } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + } + else { + if (condition_j) { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + if (condition_c) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_7: Merge labels of block _P and Q + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + continue; + } + } + else { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; continue; } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; + if (condition_p) { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + //Action_8: Merge labels of block _P and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_8: Merge labels of block _P and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block _P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block _P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } } } } } - } - else { - if (condition_j) { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; + else { + if (condition_s) { + if (condition_p) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + else { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } + } + } + } + else { + if (condition_r) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_n) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } } else { - if (condition_h) { - if (condition_c) { + if (condition_p) { + if (condition_j) { //Action_4: Assign label of block Q imgLabels_row[c] = imgLabels_row_prev_prev[c]; continue; } else { - //Action_7: Merge labels of block P and Q - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); - continue; - } - } - else { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - } - } - else { - if (condition_p) { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } - } - else { - if (condition_h) { - if (condition_d) { - if (condition_c) { + if (condition_k) { + if (condition_i) { + if (condition_d) { //Action_5: Assign label of block R imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; continue; } else { - //Action_8: Merge labels of block P and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } else { - //Action_8: Merge labels of block P and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; continue; } } else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } } } } else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - if (condition_h) { - //Action_3: Assign label of block P - imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; - continue; - } - else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } - } - } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - if (condition_h) { - //Action_3: Assign label of block P - imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; - continue; - } - else { + if (condition_t) { //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + else { + // Action_1: No action (the block has no foreground pixels) + imgLabels_row[c] = 0; continue; } } @@ -945,10 +1871,786 @@ namespace cv{ } } } + //write in the follower memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; } - else { - if (condition_s) { - if (condition_p) { + }; + + class SecondScan{ + private: + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + StatsOp &_sop; + StatsOp *_sopArray; + LabelT &_nLabels; + + public: + SecondScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + + SecondScan & operator=(const SecondScan &) { return *this; } + + void operator()(const tbb::blocked_range &range) const{ + + int r = range.begin(); + r += (r % 2); + const int rowBegin = r; + const int rowEnd = range.end() + range.end() % 2; + + if (rowBegin > 0){ + _sopArray[rowBegin].initElement(_nLabels); + _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = range.second; + + if (_imgLabels.rows & 1){ + if (_imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + } + else if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + } + } + else { + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + else if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + } + } + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + } + } + }// END Case 2 + } + else{ + if (_imgLabels.cols & 1){ + //Case 3: only cols odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r + 1, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r, c + 1, 0); + _sopArray[rowBegin](r + 1, c, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + }//END case 4 + } + } + } + else{ + //the first thread use sop in order to make less merges + _sop.setNextLoc(rowEnd); + if (_imgLabels.rows & 1){ + if (_imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + } + else if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + } + } + else { + imgLabels_row[c] = 0; + _sop(r, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c, 0); + _sop(r + 1, c + 1, 0); + } + } + else if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + } + } + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + _sop(r, c, 0); + _sop(r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c, 0); + _sop(r + 1, c + 1, 0); + } + } + } + } + }// END Case 2 + } + else{ + if (_imgLabels.cols & 1){ + //Case 3: only cols odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + _sop(r, c, 0); + _sop(r + 1, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r, c + 1, 0); + _sop(r + 1, c + 1, 0); + } + } + } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (; r < range.end(); r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r, c, 0); + _sop(r, c + 1, 0); + _sop(r + 1, c, 0); + _sop(r + 1, c + 1, 0); + } + } + }//END case 4 + } + } + } + } + }; + + inline static + void mergeLabels(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels){ + + // Merge Mask + // +---+---+---+ + // |P -|Q -|R -| + // |- -|- -|- -| + // +---+---+---+ + // |X -| + // |- -| + // +---+ + const int w = imgLabels.cols, h = imgLabels.rows; + + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + + for (int c = 0; c < w; c += 2){ + +#define condition_x imgLabels_row[c] > 0 +#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0 +#define condition_qppr imgLabels_row_prev_prev[c] > 0 +#define condition_qppr1 c < w - 1 +#define condition_qppr2 c < w +#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0 + + if (condition_x){ + if (condition_pppr){ + //check in img + if (img_row[c] > 0 && img_row_prev[c - 1] > 0) + //assign the same label + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]); + } + if (condition_qppr){ + if (condition_qppr1){ + if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) || + (img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){ + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); + } + } + else /*if (condition_qppr2)*/{ + if (img_row[c] > 0 && img_row_prev[c] > 0) + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); + } + } + if (condition_rppr){ + if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0) + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]); + } + } + } + } + } + + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8); + + const int nThreads = tbb::task_scheduler_init::default_num_threads(); + tbb::task_scheduler_init init(nThreads); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 8-connectivity case + //can never have more than 1 new label and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 0 0 0 0... + //1 0 1 0 1... + //............ + const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + + //Array used to store info and labeled pixel by each thread. + //Different threads affect different memory location of chunksSizeAndLabels + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + + //Tree of labels + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + //First label is for background + P[0] = 0; + + tbb::blocked_range range(0, h, h / nThreads); + + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + tbb::parallel_for(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); + + //merge labels of different chunks + mergeLabels(img, imgLabels, P, chunksSizeAndLabels); + + LabelT nLabels = 1; + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + } + + //Array for statistics data + StatsOp *SopArray = new StatsOp[h]; + sop.init(nLabels); + + //Second scan + tbb::parallel_for(range, SecondScan(img, imgLabels, P, sop, SopArray, nLabels), tbb::static_partitioner()); + + StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + sop.finish(); + + delete[] SopArray; + cv::fastFree(chunksSizeAndLabels); + cv::fastFree(P); + return nLabels; + } +#endif +#else + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 8-connectivity case + //can never have more than 1 new label and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 0 0 0 0... + //1 0 1 0 1... + //............ + const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); + P[0] = 0; + LabelT lunique = 1; + + // First scan + for (int r = 0; r < h; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); + for (int c = 0; c < w; c += 2) { + + // We work with 2x2 blocks + // +-+-+-+ + // |P|Q|R| + // +-+-+-+ + // |S|X| + // +-+-+ + + // The pixels are named as follows + // +---+---+---+ + // |a b|c d|e f| + // |g h|i j|k l| + // +---+---+---+ + // |m n|o p| + // |q r|s t| + // +---+---+ + + // Pixels a, f, l, q are not needed, since we need to understand the + // the connectivity between these blocks and those pixels only metter + // when considering the outer connectivities + + // A bunch of defines used to check if the pixels are foreground, + // without going outside the image limits. +#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0 +#define condition_c r-2>=0 && img_row_prev_prev[c]>0 +#define condition_d c+1=0 && img_row_prev_prev[c+1]>0 +#define condition_e c+2=0 && img_row_prev_prev[c+2]>0 + +#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0 +#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0 +#define condition_i r-1>=0 && img_row_prev[c]>0 +#define condition_j c+1=0 && img_row_prev[c+1]>0 +#define condition_k c+2=0 && img_row_prev[c+2]>0 + +#define condition_m c-2>=0 && img_row[c-2]>0 +#define condition_n c-1>=0 && img_row[c-1]>0 +#define condition_o img_row[c]>0 +#define condition_p c+10 + +#define condition_r c-1>=0 && r+10 +#define condition_s r+10 +#define condition_t c+10 + + // This is a decision tree which allows to choose which action to + // perform, checking as few conditions as possible. + // Actions: the blocks label are provisionally stored in the top left + // pixel of the block in the labels image + + if (condition_o) { if (condition_n) { if (condition_j) { if (condition_i) { @@ -991,26 +2693,33 @@ namespace cv{ } } else { - if (condition_k) { - if (condition_d) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; + if (condition_p) { + if (condition_k) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } else { //Action_12: Merge labels of block R and S @@ -1018,23 +2727,23 @@ namespace cv{ continue; } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } } @@ -1103,54 +2812,89 @@ namespace cv{ } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + if (condition_i) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + else { + if (condition_h) { + if (condition_c) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + else { + //Action_14: Merge labels of block P, Q and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } } } else { - if (condition_k) { - if (condition_d) { + if (condition_p) { + if (condition_k) { if (condition_m) { if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { + if (condition_c) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_c) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_d) { + if (condition_g) { + if (condition_b) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } else { //Action_12: Merge labels of block R and S @@ -1159,32 +2903,18 @@ namespace cv{ } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_h) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; + if (condition_i) { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } } else { //Action_16: labels of block Q, R and S @@ -1193,28 +2923,279 @@ namespace cv{ } } else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } + } + else { + if (condition_i) { + if (condition_d) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_15: Merge labels of block P, R and S + 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]); + continue; + } + } + else { + //Action_15: Merge labels of block P, R and S + 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]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + } + else { + if (condition_h) { + if (condition_m) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + // ACTION_9 Merge labels of block P and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); continue; } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + else { + if (condition_h) { + if (condition_m) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } + else { + // ACTION_9 Merge labels of block P and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + } + else { + if (condition_j) { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + if (condition_c) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_7: Merge labels of block P and Q + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + continue; + } + } + else { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + //Action_8: Merge labels of block P and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_8: Merge labels of block P and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } } } else { if (condition_i) { - if (condition_m) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } + } + } + } + } + } + else { + if (condition_s) { + if (condition_p) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { if (condition_h) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -1246,6 +3227,55 @@ namespace cv{ continue; } } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } else { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -1253,8 +3283,283 @@ namespace cv{ } } } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + else { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } + } + } + } } else { + if (condition_r) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_n) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } + } + } + else { + if (condition_p) { if (condition_j) { //Action_4: Assign label of block Q imgLabels_row[c] = imgLabels_row_prev_prev[c]; @@ -1296,409 +3601,361 @@ namespace cv{ } } } - } - } - else { - if (condition_r) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_n) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } - } - } - } - else { - if (condition_p) { - if (condition_j) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } - } - else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { + if (condition_t) { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = lunique; P[lunique] = lunique; lunique = lunique + 1; continue; } + else { + // Action_1: No action (the block has no foreground pixels) + imgLabels_row[c] = 0; + continue; + } } } } - else { - if (condition_t) { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } - else { - // Action_1: No action (the block has no foreground pixels) - imgLabels_row[c] = 0; - continue; - } - } } + } - } - } - // Second scan + analysis - LabelT nLabels = flattenL(P, lunique); - sop.init(nLabels); + // Second scan + analysis + LabelT nLabels = flattenL(P, lunique); + sop.init(nLabels); - if (imgLabels.rows & 1){ - if (imgLabels.cols & 1){ - //Case 1: both rows and cols odd - for (int r = 0; r(r); - const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT* const imgLabels_row = imgLabels.ptr(r); - LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + if (imgLabels.rows & 1){ + if (imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - for (int c = 0; c0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (c + 1 0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (c + 1 < imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (r + 1 < imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c + 1, 0); + } + } + } + else if (r + 1 < imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + } } - else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (r + 1 0){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - } else{ + else { + imgLabels_row[c] = 0; + sop(r, c, 0); + if (c + 1 < imgLabels.cols) { + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + if (r + 1 < imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c, 0); + sop(r + 1, c + 1, 0); + } + } + else if (r + 1 < imgLabels.rows) { imgLabels_row_fol[c] = 0; sop(r + 1, c, 0); } - if (img_row_fol[c + 1]>0){ + } + } + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (r + 1 < imgLabels.rows) { + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c + 1, 0); + } + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + sop(r, c, 0); + sop(r, c + 1, 0); + if (r + 1 < imgLabels.rows) { + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c, 0); + sop(r + 1, c + 1, 0); + } + } + } + } + }// END Case 2 + } + else{ + if (imgLabels.cols & 1){ + //Case 3: only cols odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (c + 1 < imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c + 1, 0); + } + } + } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + sop(r, c, 0); + sop(r + 1, c, 0); + if (c + 1 < imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + sop(r, c + 1, 0); + sop(r + 1, c + 1, 0); + } + } + } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; sop(r + 1, c + 1, iLabel); - } else{ + } + else{ imgLabels_row_fol[c + 1] = 0; sop(r + 1, c + 1, 0); } - } - } - else if (r + 10){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - }else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); } - } - } - else { - imgLabels_row[c] = 0; - sop(r, c, 0); - if (c + 1(r); - const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT* const imgLabels_row = imgLabels.ptr(r); - LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - - for (int c = 0; c0) { - iLabel = P[iLabel]; - if (img_row[c]>0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (img_row[c + 1]>0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - }else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (r + 10){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - }else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } - if (img_row_fol[c + 1]>0){ - imgLabels_row_fol[c + 1] = iLabel; - sop(r + 1, c + 1, iLabel); - }else{ - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c + 1, 0); - } - } - } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; - sop(r, c, 0); - sop(r, c + 1, 0); - if (r + 1(r); - const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT* const imgLabels_row = imgLabels.ptr(r); - LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - - for (int c = 0; c0) { - iLabel = P[iLabel]; - if (img_row[c]>0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - }else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (img_row_fol[c]>0){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - }else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } - if (c + 10){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - }else{ + else { + imgLabels_row[c] = 0; imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (img_row_fol[c + 1]>0){ - imgLabels_row_fol[c + 1] = iLabel; - sop(r + 1, c + 1, iLabel); - }else{ + imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; + sop(r, c, 0); + sop(r, c + 1, 0); + sop(r + 1, c, 0); sop(r + 1, c + 1, 0); } } } - else{ - imgLabels_row[c] = 0; - imgLabels_row_fol[c] = 0; - sop(r, c, 0); - sop(r + 1, c, 0); - if (c + 1(r); - const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT* const imgLabels_row = imgLabels.ptr(r); - LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - for (int c = 0; c0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - }else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - }else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - }else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - sop(r + 1, c + 1, iLabel); - }else{ - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c + 1, 0); - } - } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - sop(r, c, 0); - sop(r, c + 1, 0); - sop(r + 1, c, 0); - sop(r + 1, c + 1, 0); - } - } + sop.finish(); + fastFree(P); + + return nLabels; + + } //End function LabelingGrana operator() +#endif + }; //End struct LabelingGrana + }//end namespace connectedcomponents + + //L's type must have an appropriate depth for the number of pixels in I + template + static + int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){ + CV_Assert(L.channels() == 1 && I.channels() == 1); + CV_Assert(connectivity == 8 || connectivity == 4); + CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT); + + int lDepth = L.depth(); + int iDepth = I.depth(); + + CV_Assert(iDepth == CV_8U || iDepth == CV_8S); + + if (ccltype == CCL_WU || connectivity == 4){ + // Wu algorithm is used + using connectedcomponents::LabelingWu; + //warn if L's depth is not sufficient? + if (lDepth == CV_8U){ + return (int)LabelingWu()(I, L, connectivity, sop); } - }//END case 4 + else if (lDepth == CV_16U){ + return (int)LabelingWu()(I, L, connectivity, sop); + } + else if (lDepth == CV_32S){ + //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects + //OpenCV: how should we proceed? .at typechecks in debug mode + return (int)LabelingWu()(I, L, connectivity, sop); + } + } + else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){ + // Grana algorithm is used + using connectedcomponents::LabelingGrana; + //warn if L's depth is not sufficient? + if (lDepth == CV_8U){ + return (int)LabelingGrana()(I, L, connectivity, sop); + } + else if (lDepth == CV_16U){ + return (int)LabelingGrana()(I, L, connectivity, sop); + } + else if (lDepth == CV_32S){ + //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects + //OpenCV: how should we proceed? .at typechecks in debug mode + return (int)LabelingGrana()(I, L, connectivity, sop); + } + } + + CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type"); + return -1; } - sop.finish(); - fastFree(P); - - return nLabels; - - } //End function LabelingGrana operator() - }; //End struct LabelingGrana -}//end namespace connectedcomponents - -//L's type must have an appropriate depth for the number of pixels in I -template -static -int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){ - CV_Assert(L.channels() == 1 && I.channels() == 1); - CV_Assert(connectivity == 8 || connectivity == 4); - CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT); - - int lDepth = L.depth(); - int iDepth = I.depth(); - - CV_Assert(iDepth == CV_8U || iDepth == CV_8S); - - if (ccltype == CCL_WU || connectivity == 4){ - // Wu algorithm is used - using connectedcomponents::LabelingWu; - //warn if L's depth is not sufficient? - if (lDepth == CV_8U){ - return (int)LabelingWu()(I, L, connectivity, sop); - } - else if (lDepth == CV_16U){ - return (int)LabelingWu()(I, L, connectivity, sop); - } - else if (lDepth == CV_32S){ - //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects - //OpenCV: how should we proceed? .at typechecks in debug mode - return (int)LabelingWu()(I, L, connectivity, sop); - } - }else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){ - // Grana algorithm is used - using connectedcomponents::LabelingGrana; - //warn if L's depth is not sufficient? - if (lDepth == CV_8U){ - return (int)LabelingGrana()(I, L, connectivity, sop); - } - else if (lDepth == CV_16U){ - return (int)LabelingGrana()(I, L, connectivity, sop); - } - else if (lDepth == CV_32S){ - //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects - //OpenCV: how should we proceed? .at typechecks in debug mode - return (int)LabelingGrana()(I, L, connectivity, sop); - } - } - - CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type"); - return -1; -} - } // Simple wrapper to ensure binary and source compatibility (ABI) @@ -1725,13 +3982,13 @@ int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivi // Simple wrapper to ensure binary and source compatibility (ABI) int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv, - OutputArray centroids, int connectivity, int ltype) + OutputArray centroids, int connectivity, int ltype) { return cv::connectedComponentsWithStats(_img, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT); } int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv, - OutputArray centroids, int connectivity, int ltype, int ccltype) + OutputArray centroids, int connectivity, int ltype, int ccltype) { const cv::Mat img = _img.getMat(); _labels.create(img.size(), CV_MAT_DEPTH(ltype)); From 5b23c0b176206d4ee7efc43f454fcd7f4f0419f1 Mon Sep 17 00:00:00 2001 From: Michele Cancilla Date: Thu, 24 Nov 2016 15:03:36 +0100 Subject: [PATCH 2/6] Fixed unnecessary black spaces; Extended parallel version to all frameworks supported by OpenCV; Added some documentation notes in modules/imgproc/include/opencv2/imgproc.hpp; --- modules/imgproc/include/opencv2/imgproc.hpp | 7 +- modules/imgproc/src/connectedcomponents.cpp | 3437 ++++++++++--------- 2 files changed, 1741 insertions(+), 1703 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 2a3173c8df..1f5c76c7f4 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3674,8 +3674,10 @@ image with 4 or 8 way connectivity - returns N, the total number of labels [0, N represents the background label. ltype specifies the output label image type, an important consideration based on the total number of labels or alternatively the total number of pixels in the source image. ccltype specifies the connected components labeling algorithm to use, currently -Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes +Grana (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. +This function uses parallel version of both Grana and Wu's algorithms if at least one allowed +parallel framework is enabled. @param image the 8-bit single-channel image to be labeled @param labels destination labeled image @@ -3706,7 +3708,8 @@ consideration based on the total number of labels or alternatively the total num the source image. ccltype specifies the connected components labeling algorithm to use, currently Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. - +This function uses parallel version of both Grana and Wu's algorithms (statistics included) if at least one allowed +parallel framework is enabled. @param image the 8-bit single-channel image to be labeled @param labels destination labeled image diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index 00fa8d0eb4..1e2956fee2 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -51,19 +51,19 @@ namespace cv{ namespace connectedcomponents{ - struct NoOp{ + struct NoOp{ NoOp(){ } inline - void init(int /*labels*/){ + void init(int /*labels*/){ } inline - void initElement(const int /*nlabels*/){ + void initElement(const int /*nlabels*/){ } inline - void operator()(int r, int c, int l){ + void operator()(int r, int c, int l){ (void)r; (void)c; (void)l; @@ -72,20 +72,20 @@ namespace cv{ void finish(){} inline - void setNextLoc(const int /*nextLoc*/){ + void setNextLoc(const int /*nextLoc*/){ } inline static - void mergeStats(const cv::Mat& /*imgLabels*/, NoOp* /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){ + void mergeStats(const cv::Mat& /*imgLabels*/, NoOp* /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){ } }; - struct Point2ui64{ + struct Point2ui64{ uint64 x, y; Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){} }; - struct CCStatsOp{ + struct CCStatsOp{ const _OutputArray* _mstatsv; cv::Mat statsv; const _OutputArray* _mcentroidsv; @@ -97,7 +97,7 @@ namespace cv{ CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv){} inline - void init(int nlabels){ + void init(int nlabels){ _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); statsv = _mstatsv->getMat(); _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); @@ -115,18 +115,18 @@ namespace cv{ } inline - void initElement(const int nlabels){ - statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); - for (int l = 0; l < (int)nlabels; ++l){ - int *row = (int *)statsv.ptr(l); - row[CC_STAT_LEFT] = INT_MAX; - row[CC_STAT_TOP] = INT_MAX; - row[CC_STAT_WIDTH] = INT_MIN; - row[CC_STAT_HEIGHT] = INT_MIN; - row[CC_STAT_AREA] = 0; - } - integrals.resize(nlabels, Point2ui64(0, 0)); + void initElement(const int nlabels){ + statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); + for (int l = 0; l < (int)nlabels; ++l){ + int *row = (int *)statsv.ptr(l); + row[CC_STAT_LEFT] = INT_MAX; + row[CC_STAT_TOP] = INT_MAX; + row[CC_STAT_WIDTH] = INT_MIN; + row[CC_STAT_HEIGHT] = INT_MIN; + row[CC_STAT_AREA] = 0; } + integrals.resize(nlabels, Point2ui64(0, 0)); + } void operator()(int r, int c, int l){ int *row = &statsv.at(l, 0); @@ -155,41 +155,41 @@ namespace cv{ } inline - void setNextLoc(const int nextLoc){ - _nextLoc = nextLoc; - } + void setNextLoc(const int nextLoc){ + _nextLoc = nextLoc; + } inline static - void mergeStats(const cv::Mat &imgLabels, CCStatsOp *SopArray, CCStatsOp &sop, const int &nLabels){ - const int h = imgLabels.rows; + void mergeStats(const cv::Mat &imgLabels, CCStatsOp *SopArray, CCStatsOp &sop, const int &nLabels){ + const int h = imgLabels.rows; - if (sop._nextLoc != h){ - for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = SopArray[nextLoc]._nextLoc){ - //merge between sopNext and sop - for (int l = 0; l < nLabels; ++l){ - int *rowNext = (int*)SopArray[nextLoc].statsv.ptr(l); - if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats - int *rowMerged = (int*)sop.statsv.ptr(l); - rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]); - rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]); - rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]); - rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]); - rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA]; + if (sop._nextLoc != h){ + for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = SopArray[nextLoc]._nextLoc){ + //merge between sopNext and sop + for (int l = 0; l < nLabels; ++l){ + int *rowNext = (int*)SopArray[nextLoc].statsv.ptr(l); + if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats + int *rowMerged = (int*)sop.statsv.ptr(l); + rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]); + rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]); + rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]); + rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]); + rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA]; - sop.integrals[l].x += SopArray[nextLoc].integrals[l].x; - sop.integrals[l].y += SopArray[nextLoc].integrals[l].y; - } + sop.integrals[l].x += SopArray[nextLoc].integrals[l].x; + sop.integrals[l].y += SopArray[nextLoc].integrals[l].y; } } } } + } }; - //Find the root of the tree of node i - template - inline static - LabelT findRoot(const LabelT *P, LabelT i){ + //Find the root of the tree of node i + template + inline static + LabelT findRoot(const LabelT *P, LabelT i){ LabelT root = i; while (P[root] < root){ root = P[root]; @@ -197,10 +197,10 @@ namespace cv{ return root; } - //Make all nodes in the path of node i point to root - template - inline static - void setRoot(LabelT *P, LabelT i, LabelT root){ + //Make all nodes in the path of node i point to root + template + inline static + void setRoot(LabelT *P, LabelT i, LabelT root){ while (P[i] < i){ LabelT j = P[i]; P[i] = root; @@ -209,19 +209,19 @@ namespace cv{ P[i] = root; } - //Find the root of the tree of the node i and compress the path in the process - template - inline static - LabelT find(LabelT *P, LabelT i){ + //Find the root of the tree of the node i and compress the path in the process + template + inline static + LabelT find(LabelT *P, LabelT i){ LabelT root = findRoot(P, i); setRoot(P, i, root); return root; } - //unite the two trees containing nodes i and j and return the new root - template - inline static - LabelT set_union(LabelT *P, LabelT i, LabelT j){ + //unite the two trees containing nodes i and j and return the new root + template + inline static + LabelT set_union(LabelT *P, LabelT i, LabelT j){ LabelT root = findRoot(P, i); if (i != j){ LabelT rootj = findRoot(P, j); @@ -234,10 +234,10 @@ namespace cv{ return root; } - //Flatten the Union Find tree and relabel the components - template - inline static - LabelT flattenL(LabelT *P, LabelT length){ + //Flatten the Union Find tree and relabel the components + template + inline static + LabelT flattenL(LabelT *P, LabelT length){ LabelT k = 1; for (LabelT i = 1; i < length; ++i){ if (P[i] < i){ @@ -250,9 +250,9 @@ namespace cv{ return k; } - template - inline static - void flattenL(LabelT *P, const int start, const int nElem, LabelT &k){ + template + inline static + void flattenL(LabelT *P, const int start, const int nElem, LabelT &k){ for (int i = start; i < start + nElem; ++i){ if (P[i] < i){//node that point to root P[i] = P[P[i]]; @@ -264,50 +264,48 @@ namespace cv{ } } - //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant + //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant //using decision trees //Kesheng Wu, et al - template - struct LabelingWu{ -#ifdef HAVE_TBB -# if TBB_VERSION_MAJOR + TBB_VERSION_MINOR >= 2017 + template + struct LabelingWuParallel{ - class FirstScan8Connectivity{ - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + class FirstScan8Connectivity : public cv::ParallelLoopBody{ + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; - public: - FirstScan8Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + public: + FirstScan8Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} - FirstScan8Connectivity & operator=(const FirstScan8Connectivity &) { return *this; } + FirstScan8Connectivity & operator=(const FirstScan8Connectivity &) { return *this; } - void operator()(const tbb::blocked_range &range) const{ + void operator()(const cv::Range &range) const{ - int r = range.begin(); - _chunksSizeAndLabels[r] = range.end(); + int r = range.start; + _chunksSizeAndLabels[r] = range.end; - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); - const LabelT firstLabel = label; - const int w = _img.cols; - const int limitLine = r, startR = r; + const LabelT firstLabel = label; + const int w = _img.cols; + const int limitLine = r, startR = r; - // Rosenfeld Mask - // +-+-+-+ - // |p|q|r| - // +-+-+-+ - // |s|x| - // +-+-+ - for (; r != range.end(); ++r) - { - PixelT const * const img_row = _img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); - for (int c = 0; c < w; ++c) { + // Rosenfeld Mask + // +-+-+-+ + // |p|q|r| + // +-+-+-+ + // |s|x| + // +-+-+ + for (; r != range.end; ++r) + { + PixelT const * const img_row = _img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { #define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0 #define condition_q r > limitLine && img_row_prev[c] > 0 @@ -315,370 +313,376 @@ namespace cv{ #define condition_s c > 0 && img_row[c - 1] > 0 #define condition_x img_row[c] > 0 - if (condition_x){ - if (condition_q){ - //copy q - imgLabels_row[c] = imgLabels_row_prev[c]; - } - else{ - //not q - if (condition_r){ - if (condition_p){ - //concavity p->x->r. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); - } - else{ //not p and q - if (condition_s){ - //step s->x->r. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); - } - else{ //not p, q and s - //copy r - imgLabels_row[c] = imgLabels_row_prev[c + 1]; - } - } - } - else{ - //not r and q - if (condition_p){ - //copy p - imgLabels_row[c] = imgLabels_row_prev[c - 1]; - } - else{//not r,q and p - if (condition_s){ - imgLabels_row[c] = imgLabels_row[c - 1]; - } - else{ - //new label - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; - } - } - } - } + if (condition_x){ + if (condition_q){ + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; } else{ - //x is a background pixel - imgLabels_row[c] = 0; + //not q + if (condition_r){ + if (condition_p){ + //concavity p->x->r. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); + } + else{ //not p and q + if (condition_s){ + //step s->x->r. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); + } + else{ //not p, q and s + //copy r + imgLabels_row[c] = imgLabels_row_prev[c + 1]; + } + } + } + else{ + //not r and q + if (condition_p){ + //copy p + imgLabels_row[c] = imgLabels_row_prev[c - 1]; + } + else{//not r,q and p + if (condition_s){ + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + } + } + } } } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } } - //write in the follower memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; } + //write in the follower memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; + } #undef condition_p #undef condition_q #undef condition_r #undef condition_s #undef condition_x - }; + }; - class FirstScan4Connectivity{ - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + class FirstScan4Connectivity : public cv::ParallelLoopBody{ + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; - public: - FirstScan4Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + public: + FirstScan4Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} - FirstScan4Connectivity & operator=(const FirstScan4Connectivity &) { return *this; } + FirstScan4Connectivity & operator=(const FirstScan4Connectivity &) { return *this; } - void operator()(const tbb::blocked_range &range) const{ + void operator()(const cv::Range &range) const{ - int r = range.begin(); - _chunksSizeAndLabels[r] = range.end(); + int r = range.start; + _chunksSizeAndLabels[r] = range.end; - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); - const LabelT firstLabel = label; - const int w = _img.cols; - const int limitLine = r, startR = r; + const LabelT firstLabel = label; + const int w = _img.cols; + const int limitLine = r, startR = r; - // Rosenfeld Mask - // +-+-+-+ - // |-|q|-| - // +-+-+-+ - // |s|x| - // +-+-+ - for (; r != range.end(); ++r){ - PixelT const * const img_row = _img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); - for (int c = 0; c < w; ++c) { + // Rosenfeld Mask + // +-+-+-+ + // |-|q|-| + // +-+-+-+ + // |s|x| + // +-+-+ + for (; r != range.end; ++r){ + PixelT const * const img_row = _img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { #define condition_q r > limitLine && img_row_prev[c] > 0 #define condition_s c > 0 && img_row[c - 1] > 0 #define condition_x img_row[c] > 0 - if (condition_x){ - if (condition_q){ - if (condition_s){ - //step s->x->q. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c]); - } - else{ - //copy q - imgLabels_row[c] = imgLabels_row_prev[c]; - } + if (condition_x){ + if (condition_q){ + if (condition_s){ + //step s->x->q. Merge + imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c]); } else{ - if (condition_s){ // copy s - imgLabels_row[c] = imgLabels_row[c - 1]; - } - else{ - //new label - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; - } + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; } } else{ - //x is a background pixel - imgLabels_row[c] = 0; + if (condition_s){ // copy s + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + } } } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } } - //write in the following memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; } + //write in the following memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; + } #undef condition_q #undef condition_s #undef condition_x - }; + }; - class SecondScan{ - cv::Mat &_imgLabels; - const LabelT *_P; - StatsOp &_sop; - StatsOp *_sopArray; - LabelT &_nLabels; - public: - SecondScan(cv::Mat &imgLabels, const LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) - : _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + class SecondScan : public cv::ParallelLoopBody{ + cv::Mat &_imgLabels; + const LabelT *_P; + StatsOp &_sop; + StatsOp *_sopArray; + LabelT &_nLabels; + public: + SecondScan(cv::Mat &imgLabels, const LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) + : _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} - SecondScan & operator=(const SecondScan &) { return *this; } + SecondScan & operator=(const SecondScan &) { return *this; } - void operator()(const tbb::blocked_range &range) const{ + void operator()(const cv::Range &range) const{ - int r = range.begin(); - const int rowBegin = r; - const int rowEnd = range.end(); + int r = range.start; + const int rowBegin = r; + const int rowEnd = range.end; - if (rowBegin > 0){ - _sopArray[rowBegin].initElement(_nLabels); - _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = range.second; + if (rowBegin > 0){ + _sopArray[rowBegin].initElement(_nLabels); + _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; - for (; r < range.end(); ++r) { - LabelT * img_row_start = _imgLabels.ptr(r); - LabelT * const img_row_end = img_row_start + _imgLabels.cols; - for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ - *img_row_start = _P[*img_row_start]; - _sopArray[rowBegin](r, c, *img_row_start); - } - } - } - else{ - //the first thread use sop in order to make less merges - _sop.setNextLoc(rowEnd); - for (; r < range.end(); ++r) { - LabelT * img_row_start = _imgLabels.ptr(r); - LabelT * const img_row_end = img_row_start + _imgLabels.cols; - for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ - *img_row_start = _P[*img_row_start]; - _sop(r, c, *img_row_start); - } + for (; r < rowEnd; ++r) { + LabelT * img_row_start = _imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + _imgLabels.cols; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = _P[*img_row_start]; + _sopArray[rowBegin](r, c, *img_row_start); } } } - }; + else{ + //the first thread uses sop in order to make less merges + _sop.setNextLoc(rowEnd); + for (; r < rowEnd; ++r) { + LabelT * img_row_start = _imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + _imgLabels.cols; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = _P[*img_row_start]; + _sop(r, c, *img_row_start); + } + } + } + } + }; - inline static - void mergeLabels8Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + inline static + void mergeLabels8Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ - // Merge Mask - // +-+-+-+ - // |p|q|r| - // +-+-+-+ - // |x| - // +-+ - const int w = imgLabels.cols, h = imgLabels.rows; + // Merge Mask + // +-+-+-+ + // |p|q|r| + // +-+-+-+ + // |x| + // +-+ + const int w = imgLabels.cols, h = imgLabels.rows; - for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); - for (int c = 0; c < w; ++c){ + for (int c = 0; c < w; ++c){ #define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0 #define condition_q imgLabels_row_prev[c] > 0 #define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0 #define condition_x imgLabels_row[c] > 0 - if (condition_x){ - if (condition_p){ - //merge of two label - imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row[c]); - } - if (condition_r){ - //merge of two label - imgLabels_row[c] = set_union(P, imgLabels_row_prev[c + 1], imgLabels_row[c]); - } - if (condition_q){ - //merge of two label - imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); - } - } + if (condition_x){ + if (condition_p){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row[c]); + } + if (condition_r){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c + 1], imgLabels_row[c]); + } + if (condition_q){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); } } + } + } #undef condition_p #undef condition_q #undef condition_r #undef condition_x - } + } - inline static - void mergeLabels4Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + inline static + void mergeLabels4Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ - // Merge Mask - // +-+-+-+ - // |-|q|-| - // +-+-+-+ - // |x| - // +-+ - const int w = imgLabels.cols, h = imgLabels.rows; + // Merge Mask + // +-+-+-+ + // |-|q|-| + // +-+-+-+ + // |x| + // +-+ + const int w = imgLabels.cols, h = imgLabels.rows; - for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); - for (int c = 0; c < w; ++c){ + for (int c = 0; c < w; ++c){ #define condition_q imgLabels_row_prev[c] > 0 #define condition_x imgLabels_row[c] > 0 - if (condition_x){ - if (condition_q){ - //merge of two label - imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); - } - } + if (condition_x){ + if (condition_q){ + //merge of two label + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]); } } + } + } #undef condition_q #undef condition_x - } + } - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ - CV_Assert(img.rows == imgLabels.rows); - CV_Assert(img.cols == imgLabels.cols); - CV_Assert(connectivity == 8 || connectivity == 4); + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8 || connectivity == 4); - const int nThreads = tbb::task_scheduler_init::default_num_threads(); - tbb::task_scheduler_init init(nThreads); + const int nThreads = cv::getNumThreads(); + cv::setNumThreads(nThreads); - const int h = img.rows; - const int w = img.cols; + const int h = img.rows; + const int w = img.cols; - //A quick and dirty upper bound for the maximimum number of labels. - //Following formula comes from the fact that a 2x2 block in 4-way connectivity - //labeling can never have more than 2 new labels and 1 label for background. - //Worst case image example pattern: - //1 0 1 0 1... - //0 1 0 1 0... - //1 0 1 0 1... - //............ - //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 4-way connectivity + //labeling can never have more than 2 new labels and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 1 0 1 0... + //1 0 1 0 1... + //............ + //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; - //Array used to store info and labeled pixel by each thread. - //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + //Array used to store info and labeled pixel by each thread. + //Different threads affect different memory location of chunksSizeAndLabels + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); - //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); - //First label is for background - P[0] = 0; + //Tree of labels + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + //First label is for background + P[0] = 0; - tbb::blocked_range range(0, h, h / nThreads); + cv::Range range(0, h); - if (connectivity == 8){ - //First scan, each thread works with chunk of img.rows/nThreads rows - //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - tbb::parallel_for(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); + if (connectivity == 8){ + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads); - //merge labels of different chunks - mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels); - } - else{ - //First scan, each thread works with chunk of img.rows/nThreads rows - //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - tbb::parallel_for(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); - - //merge labels of different chunks - mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); - } - LabelT nLabels = 1; - - for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); - } - - //Array for statistics dataof threads - StatsOp *SopArray = new StatsOp[h]; - - sop.init(nLabels); - //Second scan - tbb::parallel_for(range, SecondScan(imgLabels, P, sop, SopArray, nLabels), tbb::static_partitioner()); - StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); - sop.finish(); - - delete[] SopArray; - cv::fastFree(chunksSizeAndLabels); - cv::fastFree(P); - return nLabels; + //merge labels of different chunks + mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels); } -#endif -#else - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ - CV_Assert(imgLabels.rows == img.rows); - CV_Assert(imgLabels.cols == img.cols); - CV_Assert(connectivity == 8 || connectivity == 4); + else{ + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads); - const int h = img.rows; - const int w = img.cols; + //merge labels of different chunks + mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); + } + LabelT nLabels = 1; - //A quick and dirty upper bound for the maximimum number of labels. - //Following formula comes from the fact that a 2x2 block in 4-way connectivity - //labeling can never have more than 2 new labels and 1 label for background. - //Worst case image example pattern: - //1 0 1 0 1... - //0 1 0 1 0... - //1 0 1 0 1... - //............ - //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; - //array P for equivalences resolution - LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); - //first label is for background pixels - P[0] = 0; - LabelT lunique = 1; + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + } - if (connectivity == 8){ - for (int r = 0; r < h; ++r){ - // Get row pointers - PixelT const * const img_row = img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + //Array for statistics dataof threads + StatsOp *SopArray = new StatsOp[h]; - for (int c = 0; c < w; ++c){ + sop.init(nLabels); + //Second scan + cv::parallel_for_(range, SecondScan(imgLabels, P, sop, SopArray, nLabels), nThreads); + StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + sop.finish(); + + delete[] SopArray; + cv::fastFree(chunksSizeAndLabels); + cv::fastFree(P); + return nLabels; + } + };//End struct LabelingWuParallel + + //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant + //using decision trees + //Kesheng Wu, et al + template + struct LabelingWu{ + + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(imgLabels.rows == img.rows); + CV_Assert(imgLabels.cols == img.cols); + CV_Assert(connectivity == 8 || connectivity == 4); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 4-way connectivity + //labeling can never have more than 2 new labels and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 1 0 1 0... + //1 0 1 0 1... + //............ + //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + //array P for equivalences resolution + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); + //first label is for background pixels + P[0] = 0; + LabelT lunique = 1; + + if (connectivity == 8){ + for (int r = 0; r < h; ++r){ + // Get row pointers + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + + for (int c = 0; c < w; ++c){ #define condition_p c>0 && r>0 && img_row_prev[c - 1]>0 #define condition_q r>0 && img_row_prev[c]>0 @@ -686,197 +690,195 @@ namespace cv{ #define condition_s c > 0 && img_row[c - 1] > 0 #define condition_x img_row[c] > 0 - if (condition_x){ - if (condition_q){ - //x <- q - imgLabels_row[c] = imgLabels_row_prev[c]; - } - else{ - // q = 0 - if (condition_r){ - if (condition_p){ - // x <- merge(p,r) - imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); - } - else{ - // p = q = 0 - if (condition_s){ - // x <- merge(s,r) - imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); - } - else{ - // p = q = s = 0 - // x <- r - imgLabels_row[c] = imgLabels_row_prev[c + 1]; - } - } - } - else{ - // r = q = 0 - if (condition_p){ - // x <- p - imgLabels_row[c] = imgLabels_row_prev[c - 1]; - } - else{ - // r = q = p = 0 - if (condition_s){ - imgLabels_row[c] = imgLabels_row[c - 1]; - } - else{ - //new label - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - } - } - } - } + if (condition_x){ + if (condition_q){ + //x <- q + imgLabels_row[c] = imgLabels_row_prev[c]; } else{ - //x is a background pixel - imgLabels_row[c] = 0; + // q = 0 + if (condition_r){ + if (condition_p){ + // x <- merge(p,r) + imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); + } + else{ + // p = q = 0 + if (condition_s){ + // x <- merge(s,r) + imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); + } + else{ + // p = q = s = 0 + // x <- r + imgLabels_row[c] = imgLabels_row_prev[c + 1]; + } + } + } + else{ + // r = q = 0 + if (condition_p){ + // x <- p + imgLabels_row[c] = imgLabels_row_prev[c - 1]; + } + else{ + // r = q = p = 0 + if (condition_s){ + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + } + } + } } } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } } + } #undef condition_p #undef condition_q #undef condition_r #undef condition_s #undef condition_x - } - else{ - for (int r = 0; r < h; ++r){ - PixelT const * const img_row = img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); - for (int c = 0; c < w; ++c) { + } + else{ + for (int r = 0; r < h; ++r){ + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + for (int c = 0; c < w; ++c) { #define condition_q r > 0 && img_row_prev[c] > 0 #define condition_s c > 0 && img_row[c - 1] > 0 #define condition_x img_row[c] > 0 - if (condition_x){ - if (condition_q){ - if (condition_s){ - //Merge s->x->q - imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]); - } - else{ - //copy q - imgLabels_row[c] = imgLabels_row_prev[c]; - } + if (condition_x){ + if (condition_q){ + if (condition_s){ + //Merge s->x->q + imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]); } else{ - if (condition_s){ - // copy s - imgLabels_row[c] = imgLabels_row[c - 1]; - } - else{ - //new label - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - } + //copy q + imgLabels_row[c] = imgLabels_row_prev[c]; } } else{ - //x is a background pixel - imgLabels_row[c] = 0; + if (condition_s){ + // copy s + imgLabels_row[c] = imgLabels_row[c - 1]; + } + else{ + //new label + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + } } } + else{ + //x is a background pixel + imgLabels_row[c] = 0; + } } + } #undef condition_q #undef condition_s #undef condition_x + } + + //analysis + LabelT nLabels = flattenL(P, lunique); + sop.init(nLabels); + + for (int r = 0; r < h; ++r) { + LabelT * img_row_start = imgLabels.ptr(r); + LabelT * const img_row_end = img_row_start + w; + for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ + *img_row_start = P[*img_row_start]; + sop(r, c, *img_row_start); } + } - //analysis - LabelT nLabels = flattenL(P, lunique); - sop.init(nLabels); + sop.finish(); + fastFree(P); - for (int r = 0; r < h; ++r) { - LabelT * img_row_start = imgLabels.ptr(r); - LabelT * const img_row_end = img_row_start + w; - for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ - *img_row_start = P[*img_row_start]; - sop(r, c, *img_row_start); - } - } + return nLabels; + }//End function LabelingWu operator() + };//End struct LabelingWu - sop.finish(); - fastFree(P); - return nLabels; - }//End function LabelingWu operator() -#endif - };//End struct LabelingWu + // Based on “Optimized Block-based Connected Components Labeling with Decision Trees”, Costantino Grana et al + // Only for 8-connectivity + template + struct LabelingGranaParallel{ - // Based on “Optimized Block-based Connected Components Labeling with Decision Trees”, Costantino Grana et al - // Only for 8-connectivity - template - struct LabelingGrana{ -#ifdef HAVE_TBB -# if TBB_VERSION_MAJOR + TBB_VERSION_MINOR >= 2017 + class FirstScan : public cv::ParallelLoopBody{ + private: + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + int *_chunksSizeAndLabels; - class FirstScan{ - private: - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + public: + FirstScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} - public: - FirstScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + FirstScan & operator=(const FirstScan&) { return *this; } - FirstScan & operator=(const FirstScan&) { return *this; } + void operator()(const cv::Range &range) const{ - void operator()(const tbb::blocked_range &range) const{ + int r = range.start; + r += (r % 2); - int r = range.begin(); - r += (r % 2); + _chunksSizeAndLabels[r] = range.end + (range.end % 2); - _chunksSizeAndLabels[r] = range.end() + (range.end() % 2); + LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + const LabelT firstLabel = label; + const int h = _img.rows, w = _img.cols; + const int limitLine = r + 1, startR = r; - const LabelT firstLabel = label; - const int h = _img.rows, w = _img.cols; - const int limitLine = r + 1, startR = r; + for (; r < range.end; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); + const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - _img.step.p[0]); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0] - _imgLabels.step.p[0]); + for (int c = 0; c < w; c += 2) { - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - _img.step.p[0]); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0] - _imgLabels.step.p[0]); - for (int c = 0; c < w; c += 2) { + // We work with 2x2 blocks + // +-+-+-+ + // |P|Q|R| + // +-+-+-+ + // |S|X| + // +-+-+ - // We work with 2x2 blocks - // +-+-+-+ - // |P|Q|R| - // +-+-+-+ - // |S|X| - // +-+-+ + // The pixels are named as follows + // +---+---+---+ + // |a b|c d|e f| + // |g h|i j|k l| + // +---+---+---+ + // |m n|o p| + // |q r|s t| + // +---+---+ - // The pixels are named as follows - // +---+---+---+ - // |a b|c d|e f| - // |g h|i j|k l| - // +---+---+---+ - // |m n|o p| - // |q r|s t| - // +---+---+ + // Pixels a, f, l, q are not needed, since we need to understand the + // the connectivity between these blocks and those pixels only metter + // when considering the outer connectivities - // Pixels a, f, l, q are not needed, since we need to understand the - // the connectivity between these blocks and those pixels only metter - // when considering the outer connectivities - - // A bunch of defines used to check if the pixels are foreground, - // without going outside the image limits. + // A bunch of defines used to check if the pixels are foreground, + // without going outside the image limits. #define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0 #define condition_c r > limitLine && img_row_prev_prev[c]>0 @@ -898,38 +900,130 @@ namespace cv{ #define condition_s r+10 #define condition_t c+10 - // This is a decision tree which allows to choose which action to - // perform, checking as few conditions as possible. - // Actions are available after the tree. + // This is a decision tree which allows to choose which action to + // perform, checking as few conditions as possible. + // Actions are available after the tree. - if (condition_o) { - if (condition_n) { - if (condition_j) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; + if (condition_o) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } } else { - if (condition_c) { - if (condition_h) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { + if (condition_c) { + if (condition_h) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } else { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); @@ -938,40 +1032,82 @@ namespace cv{ } } else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } + else { + if (condition_h) { + if (condition_c) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + else { + //Action_14: Merge labels of block _P, Q and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } } } else { if (condition_p) { if (condition_k) { - if (condition_d) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - if (condition_h) { + if (condition_m) { + if (condition_h) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_12: Merge labels of block R and S @@ -986,167 +1122,27 @@ namespace cv{ continue; } } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - else { - if (condition_r) { - if (condition_j) { - if (condition_m) { - if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_i) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_h) { - if (condition_c) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - //Action_14: Merge labels of block _P, Q and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_p) { - if (condition_k) { - if (condition_m) { - if (condition_h) { - if (condition_d) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { + if (condition_d) { + if (condition_g) { + if (condition_b) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_d) { - if (condition_g) { - if (condition_b) { - if (condition_i) { + if (condition_c) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } } else { //Action_12: Merge labels of block R and S @@ -1155,18 +1151,18 @@ namespace cv{ } } else { - if (condition_i) { - if (condition_g) { - if (condition_b) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } else { //Action_16: labels of block Q, R and S @@ -1175,43 +1171,8 @@ namespace cv{ } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_i) { - if (condition_d) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_h) { - if (condition_d) { - if (condition_c) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_15: Merge labels of block _P, R and S - 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]); - continue; - } - } - else { - //Action_15: Merge labels of block _P, R and S - 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]); + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } @@ -1224,48 +1185,41 @@ namespace cv{ } } else { - if (condition_h) { - if (condition_m) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + if (condition_i) { + if (condition_d) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { - // ACTION_9 Merge labels of block _P and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { - if (condition_i) { - if (condition_m) { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_15: Merge labels of block _P, R and S + 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]); continue; } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_15: Merge labels of block _P, R and S + 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]); continue; } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1319,62 +1273,104 @@ namespace cv{ } } } - } - else { - if (condition_j) { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; + else { + if (condition_h) { + if (condition_m) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + // ACTION_9 Merge labels of block _P and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + continue; + } } else { - if (condition_h) { - if (condition_c) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } } else { - //Action_7: Merge labels of block _P and Q - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } } } + } + } + else { + if (condition_j) { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } else { - if (condition_p) { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } + if (condition_h) { + if (condition_c) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_7: Merge labels of block _P and Q + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + continue; + } + } + else { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } else { - if (condition_h) { - if (condition_d) { - if (condition_c) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - //Action_8: Merge labels of block _P and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); - continue; - } + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } else { //Action_8: Merge labels of block _P and R @@ -1383,31 +1379,15 @@ namespace cv{ } } else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + //Action_8: Merge labels of block _P and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); continue; } } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } else { - if (condition_h) { - //Action_3: Assign label of block _P - imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; - continue; - } - else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; - continue; - } + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } } } @@ -1433,38 +1413,54 @@ namespace cv{ } } } - } - } - } - else { - if (condition_s) { - if (condition_p) { - if (condition_n) { - if (condition_j) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block _P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; continue; } else { - if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } + } + } + } + } + else { + if (condition_s) { + if (condition_p) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_11: Merge labels of block Q and S @@ -1472,17 +1468,80 @@ namespace cv{ continue; } } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } else { - if (condition_k) { - if (condition_d) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -1490,101 +1549,10 @@ namespace cv{ } else { if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - else { - if (condition_r) { - if (condition_j) { - if (condition_m) { - if (condition_h) { - if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } else { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); @@ -1593,135 +1561,18 @@ namespace cv{ } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_k) { - if (condition_d) { - if (condition_m) { - if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_h) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_h) { + if (condition_g) { + if (condition_b) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_11: Merge labels of block Q and S @@ -1737,67 +1588,261 @@ namespace cv{ } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } - } - else { - if (condition_j) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } - else { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; + } + else { + if (condition_k) { + if (condition_d) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } } else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + if (condition_m) { + if (condition_h) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + else { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; continue; } else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } } } } } + } + else { + if (condition_r) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } else { - if (condition_r) { + if (condition_n) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_n) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; + } + } + } + } + else { + if (condition_p) { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; continue; } else { @@ -1811,201 +1856,87 @@ namespace cv{ } } else { - if (condition_p) { - if (condition_j) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } - } - else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; - continue; - } - } - } + if (condition_t) { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = label; + _P[label] = label; + label = label + 1; + continue; } else { - if (condition_t) { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = label; - _P[label] = label; - label = label + 1; - continue; - } - else { - // Action_1: No action (the block has no foreground pixels) - imgLabels_row[c] = 0; - continue; - } + // Action_1: No action (the block has no foreground pixels) + imgLabels_row[c] = 0; + continue; } } } } } - //write in the follower memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; } - }; + //write in the follower memory location + _chunksSizeAndLabels[startR + 1] = label - firstLabel; + } +#undef condition_k +#undef condition_j +#undef condition_i +#undef condition_h +#undef condition_g +#undef condition_e +#undef condition_d +#undef condition_c +#undef condition_b + }; - class SecondScan{ - private: - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - StatsOp &_sop; - StatsOp *_sopArray; - LabelT &_nLabels; + class SecondScan : public cv::ParallelLoopBody{ + private: + const cv::Mat &_img; + cv::Mat &_imgLabels; + LabelT *_P; + StatsOp &_sop; + StatsOp *_sopArray; + LabelT &_nLabels; - public: - SecondScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + public: + SecondScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) + : _img(img), _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} - SecondScan & operator=(const SecondScan &) { return *this; } + SecondScan & operator=(const SecondScan &) { return *this; } - void operator()(const tbb::blocked_range &range) const{ + void operator()(const cv::Range &range) const{ - int r = range.begin(); - r += (r % 2); - const int rowBegin = r; - const int rowEnd = range.end() + range.end() % 2; + int r = range.start; + r += (r % 2); + const int rowBegin = r; + const int rowEnd = range.end + range.end % 2; - if (rowBegin > 0){ - _sopArray[rowBegin].initElement(_nLabels); - _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = range.second; + if (rowBegin > 0){ + _sopArray[rowBegin].initElement(_nLabels); + _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; - if (_imgLabels.rows & 1){ - if (_imgLabels.cols & 1){ - //Case 1: both rows and cols odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + if (_imgLabels.rows & 1){ + if (_imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); - } - if (c + 1 < _imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - } - if (r + 1 < _imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); - } - } - } - else if (r + 1 < _imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); - } - } + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); } - else { + else{ imgLabels_row[c] = 0; _sopArray[rowBegin](r, c, 0); - if (c + 1 < _imgLabels.cols) { - imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); - } - } - else if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); - } } - } - } - }//END Case 1 - else{ - //Case 2: only rows odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); - } + if (c + 1 < _imgLabels.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; _sopArray[rowBegin](r, c + 1, iLabel); @@ -2033,44 +1964,7 @@ namespace cv{ } } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); - } - } - } - } - }// END Case 2 - } - else{ - if (_imgLabels.cols & 1){ - //Case 3: only cols odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); - } + else if (r + 1 < _imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; _sopArray[rowBegin](r + 1, c, iLabel); @@ -2079,69 +1973,59 @@ namespace cv{ imgLabels_row_fol[c] = 0; _sopArray[rowBegin](r + 1, c, 0); } - if (c + 1 < _imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); - } - } } - else{ - imgLabels_row[c] = 0; - imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r + 1, c, 0); - if (c + 1 < _imgLabels.cols) { - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); + _sopArray[rowBegin](r + 1, c, 0); _sopArray[rowBegin](r + 1, c + 1, 0); } } + else if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } } } - }// END case 3 - else{ - //Case 4: nothing odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); - } - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - } + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; _sopArray[rowBegin](r + 1, c, iLabel); @@ -2159,128 +2043,175 @@ namespace cv{ _sopArray[rowBegin](r + 1, c + 1, 0); } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r, c + 1, 0); _sopArray[rowBegin](r + 1, c, 0); _sopArray[rowBegin](r + 1, c + 1, 0); } } - }//END case 4 + } } - } + }// END Case 2 } else{ - //the first thread use sop in order to make less merges - _sop.setNextLoc(rowEnd); - if (_imgLabels.rows & 1){ - if (_imgLabels.cols & 1){ - //Case 1: both rows and cols odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); + if (_imgLabels.cols & 1){ + //Case 3: only cols odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); } else{ - imgLabels_row[c] = 0; - _sop(r, c, 0); - } - if (c + 1 < _imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); - } - if (r + 1 < _imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); - } - } - } - else if (r + 1 < _imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); - } - } - } - else { - imgLabels_row[c] = 0; - _sop(r, c, 0); - if (c + 1 < _imgLabels.cols) { imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c, 0); - _sop(r + 1, c + 1, 0); - } + _sopArray[rowBegin](r, c + 1, 0); } - else if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); } } } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r + 1, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } } - }//END Case 1 - else{ - //Case 2: only rows odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sop(r, c, 0); - } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sopArray[rowBegin](r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sopArray[rowBegin](r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sopArray[rowBegin](r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sopArray[rowBegin](r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sopArray[rowBegin](r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sopArray[rowBegin](r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sopArray[rowBegin](r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sopArray[rowBegin](r, c, 0); + _sopArray[rowBegin](r, c + 1, 0); + _sopArray[rowBegin](r + 1, c, 0); + _sopArray[rowBegin](r + 1, c + 1, 0); + } + } + }//END case 4 + } + } + } + else{ + //the first thread uses sop in order to make less merges + _sop.setNextLoc(rowEnd); + if (_imgLabels.rows & 1){ + if (_imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (c + 1 < _imgLabels.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; _sop(r, c + 1, iLabel); @@ -2308,44 +2239,7 @@ namespace cv{ } } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; - _sop(r, c, 0); - _sop(r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c, 0); - _sop(r + 1, c + 1, 0); - } - } - } - } - }// END Case 2 - } - else{ - if (_imgLabels.cols & 1){ - //Case 3: only cols odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sop(r, c, 0); - } + else if (r + 1 < _imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; _sop(r + 1, c, iLabel); @@ -2354,69 +2248,59 @@ namespace cv{ imgLabels_row_fol[c] = 0; _sop(r + 1, c, 0); } - if (c + 1 < _imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); - } - } } - else{ - imgLabels_row[c] = 0; - imgLabels_row_fol[c] = 0; - _sop(r, c, 0); - _sop(r + 1, c, 0); - if (c + 1 < _imgLabels.cols) { - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + _sop(r, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r, c + 1, 0); + _sop(r + 1, c, 0); _sop(r + 1, c + 1, 0); } } + else if (r + 1 < _imgLabels.rows) { + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } } } - }// END case 3 - else{ - //Case 4: nothing odd - for (; r < range.end(); r += 2){ - // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); - // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = _P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - _sop(r, c, 0); - } - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); - } + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (r + 1 < _imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; _sop(r + 1, c, iLabel); @@ -2434,45 +2318,172 @@ namespace cv{ _sop(r + 1, c + 1, 0); } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + _sop(r, c, 0); + _sop(r, c + 1, 0); + if (r + 1 < _imgLabels.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r, c, 0); - _sop(r, c + 1, 0); _sop(r + 1, c, 0); _sop(r + 1, c + 1, 0); } } - }//END case 4 + } } + }// END Case 2 + } + else{ + if (_imgLabels.cols & 1){ + //Case 3: only cols odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (c + 1 < _imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + _sop(r, c, 0); + _sop(r + 1, c, 0); + if (c + 1 < _imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r, c + 1, 0); + _sop(r + 1, c + 1, 0); + } + } + } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (; r < rowEnd; r += 2){ + // Get rows pointer + const PixelT * const img_row = _img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + LabelT * const imgLabels_row = _imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + // Get rows pointer + for (int c = 0; c < _imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = _P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + _sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + _sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + _sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + _sop(r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + _sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + _sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + _sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + _sop(r + 1, c + 1, 0); + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + _sop(r, c, 0); + _sop(r, c + 1, 0); + _sop(r + 1, c, 0); + _sop(r + 1, c + 1, 0); + } + } + }//END case 4 } } } - }; + } + }; - inline static - void mergeLabels(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels){ + inline static + void mergeLabels(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels){ - // Merge Mask - // +---+---+---+ - // |P -|Q -|R -| - // |- -|- -|- -| - // +---+---+---+ - // |X -| - // |- -| - // +---+ - const int w = imgLabels.cols, h = imgLabels.rows; + // Merge Mask + // +---+---+---+ + // |P -|Q -|R -| + // |- -|- -|- -| + // +---+---+---+ + // |X -| + // |- -| + // +---+ + const int w = imgLabels.cols, h = imgLabels.rows; - for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ + for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - for (int c = 0; c < w; c += 2){ + for (int c = 0; c < w; c += 2){ #define condition_x imgLabels_row[c] > 0 #define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0 @@ -2481,96 +2492,100 @@ namespace cv{ #define condition_qppr2 c < w #define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0 - if (condition_x){ - if (condition_pppr){ - //check in img - if (img_row[c] > 0 && img_row_prev[c - 1] > 0) - //assign the same label - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]); - } - if (condition_qppr){ - if (condition_qppr1){ - if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) || - (img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){ - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); - } - } - else /*if (condition_qppr2)*/{ - if (img_row[c] > 0 && img_row_prev[c] > 0) - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); + if (condition_x){ + if (condition_pppr){ + //check in img + if (img_row[c] > 0 && img_row_prev[c - 1] > 0) + //assign the same label + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]); + } + if (condition_qppr){ + if (condition_qppr1){ + if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) || + (img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){ + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); } } - if (condition_rppr){ - if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0) - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]); + else /*if (condition_qppr2)*/{ + if (img_row[c] > 0 && img_row_prev[c] > 0) + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]); } } + if (condition_rppr){ + if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0) + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]); + } } } } - - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ - CV_Assert(img.rows == imgLabels.rows); - CV_Assert(img.cols == imgLabels.cols); - CV_Assert(connectivity == 8); - - const int nThreads = tbb::task_scheduler_init::default_num_threads(); - tbb::task_scheduler_init init(nThreads); - - const int h = img.rows; - const int w = img.cols; - - //A quick and dirty upper bound for the maximimum number of labels. - //Following formula comes from the fact that a 2x2 block in 8-connectivity case - //can never have more than 1 new label and 1 label for background. - //Worst case image example pattern: - //1 0 1 0 1... - //0 0 0 0 0... - //1 0 1 0 1... - //............ - const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; - - //Array used to store info and labeled pixel by each thread. - //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); - - //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); - //First label is for background - P[0] = 0; - - tbb::blocked_range range(0, h, h / nThreads); - - //First scan, each thread works with chunk of img.rows/nThreads rows - //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows - tbb::parallel_for(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), tbb::static_partitioner()); - - //merge labels of different chunks - mergeLabels(img, imgLabels, P, chunksSizeAndLabels); - - LabelT nLabels = 1; - for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); - } - - //Array for statistics data - StatsOp *SopArray = new StatsOp[h]; - sop.init(nLabels); - - //Second scan - tbb::parallel_for(range, SecondScan(img, imgLabels, P, sop, SopArray, nLabels), tbb::static_partitioner()); - - StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); - sop.finish(); - - delete[] SopArray; - cv::fastFree(chunksSizeAndLabels); - cv::fastFree(P); - return nLabels; } -#endif -#else - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8); + + const int nThreads = cv::getNumThreads(); + cv::setNumThreads(nThreads); + + const int h = img.rows; + const int w = img.cols; + + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 8-connectivity case + //can never have more than 1 new label and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 0 0 0 0... + //1 0 1 0 1... + //............ + const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + + //Array used to store info and labeled pixel by each thread. + //Different threads affect different memory location of chunksSizeAndLabels + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + + //Tree of labels + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + //First label is for background + P[0] = 0; + + cv::Range range(0, h); + + //First scan, each thread works with chunk of img.rows/nThreads rows + //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows + cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nThreads); + + //merge labels of different chunks + mergeLabels(img, imgLabels, P, chunksSizeAndLabels); + + LabelT nLabels = 1; + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + } + + //Array for statistics data + StatsOp *SopArray = new StatsOp[h]; + sop.init(nLabels); + + //Second scan + cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, SopArray, nLabels), nThreads); + + StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + sop.finish(); + + delete[] SopArray; + cv::fastFree(chunksSizeAndLabels); + cv::fastFree(P); + return nLabels; + } + };//End struct LabelingGranaParallel + + // Based on “Optimized Block-based Connected Components Labeling with Decision Trees”, Costantino Grana et al + // Only for 8-connectivity + template + struct LabelingGrana{ + LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ CV_Assert(img.rows == imgLabels.rows); CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8); @@ -3902,53 +3917,73 @@ namespace cv{ return nLabels; } //End function LabelingGrana operator() -#endif - }; //End struct LabelingGrana + };//End struct LabelingGrana }//end namespace connectedcomponents //L's type must have an appropriate depth for the number of pixels in I template static - int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){ + int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){ CV_Assert(L.channels() == 1 && I.channels() == 1); CV_Assert(connectivity == 8 || connectivity == 4); CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT); int lDepth = L.depth(); int iDepth = I.depth(); + const char* currentParallelFramework = cv::currentParallelFramework(); CV_Assert(iDepth == CV_8U || iDepth == CV_8S); if (ccltype == CCL_WU || connectivity == 4){ // Wu algorithm is used using connectedcomponents::LabelingWu; + using connectedcomponents::LabelingWuParallel; //warn if L's depth is not sufficient? if (lDepth == CV_8U){ - return (int)LabelingWu()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); } else if (lDepth == CV_16U){ - return (int)LabelingWu()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); } else if (lDepth == CV_32S){ //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects //OpenCV: how should we proceed? .at typechecks in debug mode - return (int)LabelingWu()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); } } else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){ // Grana algorithm is used using connectedcomponents::LabelingGrana; + using connectedcomponents::LabelingGranaParallel; //warn if L's depth is not sufficient? if (lDepth == CV_8U){ - return (int)LabelingGrana()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); } else if (lDepth == CV_16U){ - return (int)LabelingGrana()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); } else if (lDepth == CV_32S){ //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects //OpenCV: how should we proceed? .at typechecks in debug mode - return (int)LabelingGrana()(I, L, connectivity, sop); + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); } } From 4b7fc5933297e27aadef357e8c27fe6ecc0699d7 Mon Sep 17 00:00:00 2001 From: Michele Cancilla Date: Fri, 25 Nov 2016 13:25:17 +0100 Subject: [PATCH 3/6] Fixed _P reserved variable name problem and changed getNumThreads with getNumberOfCPUs --- modules/imgproc/src/connectedcomponents.cpp | 1205 ++++++++++--------- 1 file changed, 603 insertions(+), 602 deletions(-) diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index 1e2956fee2..86bb8919df 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -52,73 +52,61 @@ namespace cv{ namespace connectedcomponents{ struct NoOp{ - NoOp(){ - } - inline - void init(int /*labels*/){ - } + NoOp(){ + } - inline - void initElement(const int /*nlabels*/){ - } + inline + void init(int /*labels*/){ + } - inline - void operator()(int r, int c, int l){ - (void)r; - (void)c; - (void)l; - } + inline + void initElement(const int /*nlabels*/){ + } - void finish(){} + inline + void operator()(int r, int c, int l){ + (void)r; + (void)c; + (void)l; + } - inline - void setNextLoc(const int /*nextLoc*/){ - } + void finish(){ + } - inline static - void mergeStats(const cv::Mat& /*imgLabels*/, NoOp* /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){ - } + inline + void setNextLoc(const int /*nextLoc*/){ + } - }; + inline static + void mergeStats(const cv::Mat& /*imgLabels*/, NoOp * /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){ + } + + }; struct Point2ui64{ - uint64 x, y; - Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){} + uint64 x, y; + Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){} }; struct CCStatsOp{ - const _OutputArray* _mstatsv; - cv::Mat statsv; - const _OutputArray* _mcentroidsv; - cv::Mat centroidsv; - std::vector integrals; - int _nextLoc; + const _OutputArray *_mstatsv; + cv::Mat statsv; + const _OutputArray *_mcentroidsv; + cv::Mat centroidsv; + std::vector integrals; + int _nextLoc; - CCStatsOp(){} - CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv){} + CCStatsOp(){} + CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv){} - inline - void init(int nlabels){ - _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); - statsv = _mstatsv->getMat(); - _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); - centroidsv = _mcentroidsv->getMat(); + inline + void init(int nlabels){ + _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); + statsv = _mstatsv->getMat(); + _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); + centroidsv = _mcentroidsv->getMat(); - for (int l = 0; l < (int)nlabels; ++l){ - int *row = (int *)&statsv.at(l, 0); - row[CC_STAT_LEFT] = INT_MAX; - row[CC_STAT_TOP] = INT_MAX; - row[CC_STAT_WIDTH] = INT_MIN; - row[CC_STAT_HEIGHT] = INT_MIN; - row[CC_STAT_AREA] = 0; - } - integrals.resize(nlabels, Point2ui64(0, 0)); - } - - inline - void initElement(const int nlabels){ - statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); for (int l = 0; l < (int)nlabels; ++l){ - int *row = (int *)statsv.ptr(l); + int *row = (int *)&statsv.at(l, 0); row[CC_STAT_LEFT] = INT_MAX; row[CC_STAT_TOP] = INT_MAX; row[CC_STAT_WIDTH] = INT_MIN; @@ -128,141 +116,154 @@ namespace cv{ integrals.resize(nlabels, Point2ui64(0, 0)); } - void operator()(int r, int c, int l){ - int *row = &statsv.at(l, 0); - row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c); - row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c); - row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r); - row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r); - row[CC_STAT_AREA]++; - Point2ui64 &integral = integrals[l]; - integral.x += c; - integral.y += r; + inline + void initElement(const int nlabels){ + statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType::type); + for (int l = 0; l < (int)nlabels; ++l){ + int *row = (int *)statsv.ptr(l); + row[CC_STAT_LEFT] = INT_MAX; + row[CC_STAT_TOP] = INT_MAX; + row[CC_STAT_WIDTH] = INT_MIN; + row[CC_STAT_HEIGHT] = INT_MIN; + row[CC_STAT_AREA] = 0; } + integrals.resize(nlabels, Point2ui64(0, 0)); + } - void finish(){ - for (int l = 0; l < statsv.rows; ++l){ - int *row = &statsv.at(l, 0); - row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1; - row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; + void operator()(int r, int c, int l){ + int *row =& statsv.at(l, 0); + row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c); + row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c); + row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r); + row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r); + row[CC_STAT_AREA]++; + Point2ui64& integral = integrals[l]; + integral.x += c; + integral.y += r; + } - Point2ui64 &integral = integrals[l]; - double *centroid = ¢roidsv.at(l, 0); - double area = ((unsigned*)row)[CC_STAT_AREA]; - centroid[0] = double(integral.x) / area; - centroid[1] = double(integral.y) / area; - } + void finish(){ + for (int l = 0; l < statsv.rows; ++l){ + int *row =& statsv.at(l, 0); + row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1; + row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; + + Point2ui64& integral = integrals[l]; + double *centroid =& centroidsv.at(l, 0); + double area = ((unsigned*)row)[CC_STAT_AREA]; + centroid[0] = double(integral.x) / area; + centroid[1] = double(integral.y) / area; } + } - inline - void setNextLoc(const int nextLoc){ - _nextLoc = nextLoc; - } + inline + void setNextLoc(const int nextLoc){ + _nextLoc = nextLoc; + } - inline static - void mergeStats(const cv::Mat &imgLabels, CCStatsOp *SopArray, CCStatsOp &sop, const int &nLabels){ - const int h = imgLabels.rows; + inline static + void mergeStats(const cv::Mat& imgLabels, CCStatsOp *sopArray, CCStatsOp& sop, const int& nLabels){ + const int h = imgLabels.rows; - if (sop._nextLoc != h){ - for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = SopArray[nextLoc]._nextLoc){ - //merge between sopNext and sop - for (int l = 0; l < nLabels; ++l){ - int *rowNext = (int*)SopArray[nextLoc].statsv.ptr(l); - if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats - int *rowMerged = (int*)sop.statsv.ptr(l); - rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]); - rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]); - rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]); - rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]); - rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA]; + if (sop._nextLoc != h){ + for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = sopArray[nextLoc]._nextLoc){ + //merge between sopNext and sop + for (int l = 0; l < nLabels; ++l){ + int *rowNext = (int*)sopArray[nextLoc].statsv.ptr(l); + if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats + int *rowMerged = (int*)sop.statsv.ptr(l); + rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]); + rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]); + rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]); + rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]); + rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA]; - sop.integrals[l].x += SopArray[nextLoc].integrals[l].x; - sop.integrals[l].y += SopArray[nextLoc].integrals[l].y; - } + sop.integrals[l].x += sopArray[nextLoc].integrals[l].x; + sop.integrals[l].y += sopArray[nextLoc].integrals[l].y; } } } } - - }; + } + }; //Find the root of the tree of node i template inline static LabelT findRoot(const LabelT *P, LabelT i){ - LabelT root = i; - while (P[root] < root){ - root = P[root]; - } - return root; - } + LabelT root = i; + while (P[root] < root){ + root = P[root]; + } + return root; + } //Make all nodes in the path of node i point to root template inline static void setRoot(LabelT *P, LabelT i, LabelT root){ - while (P[i] < i){ - LabelT j = P[i]; - P[i] = root; - i = j; - } - P[i] = root; - } + while (P[i] < i){ + LabelT j = P[i]; + P[i] = root; + i = j; + } + P[i] = root; + } //Find the root of the tree of the node i and compress the path in the process template inline static LabelT find(LabelT *P, LabelT i){ - LabelT root = findRoot(P, i); - setRoot(P, i, root); - return root; - } + LabelT root = findRoot(P, i); + setRoot(P, i, root); + return root; + } //unite the two trees containing nodes i and j and return the new root template inline static LabelT set_union(LabelT *P, LabelT i, LabelT j){ - LabelT root = findRoot(P, i); - if (i != j){ - LabelT rootj = findRoot(P, j); - if (root > rootj){ - root = rootj; - } - setRoot(P, j, root); - } - setRoot(P, i, root); - return root; + LabelT root = findRoot(P, i); + if (i != j){ + LabelT rootj = findRoot(P, j); + if (root > rootj){ + root = rootj; } + setRoot(P, j, root); + } + setRoot(P, i, root); + return root; + } //Flatten the Union Find tree and relabel the components template inline static LabelT flattenL(LabelT *P, LabelT length){ - LabelT k = 1; - for (LabelT i = 1; i < length; ++i){ - if (P[i] < i){ - P[i] = P[P[i]]; - } - else{ - P[i] = k; k = k + 1; - } - } - return k; + LabelT k = 1; + for (LabelT i = 1; i < length; ++i){ + if (P[i] < i){ + P[i] = P[P[i]]; } + else{ + P[i] = k; k = k + 1; + } + } + return k; + } template inline static - void flattenL(LabelT *P, const int start, const int nElem, LabelT &k){ - for (int i = start; i < start + nElem; ++i){ - if (P[i] < i){//node that point to root - P[i] = P[P[i]]; - } - else{ //for root node - P[i] = k; - k = k + 1; - } - } + void flattenL(LabelT *P, const int start, const int nElem, LabelT& k){ + for (int i = start; i < start + nElem; ++i){ + if (P[i] < i){//node that point to root + P[i] = P[P[i]]; } + else{ //for root node + P[i] = k; + k = k + 1; + } + } + } //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant //using decision trees @@ -271,26 +272,26 @@ namespace cv{ struct LabelingWuParallel{ class FirstScan8Connectivity : public cv::ParallelLoopBody{ - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + const cv::Mat& img_; + cv::Mat& imgLabels_; + LabelT *P_; + int *chunksSizeAndLabels_; public: - FirstScan8Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + FirstScan8Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels) + : img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){} - FirstScan8Connectivity & operator=(const FirstScan8Connectivity &) { return *this; } + FirstScan8Connectivity& operator=(const FirstScan8Connectivity& ) { return *this; } - void operator()(const cv::Range &range) const{ + void operator()(const cv::Range& range) const{ int r = range.start; - _chunksSizeAndLabels[r] = range.end; + chunksSizeAndLabels_[r] = range.end; - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); const LabelT firstLabel = label; - const int w = _img.cols; + const int w = img_.cols; const int limitLine = r, startR = r; // Rosenfeld Mask @@ -301,10 +302,10 @@ namespace cv{ // +-+-+ for (; r != range.end; ++r) { - PixelT const * const img_row = _img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + PixelT const *const img_row = img_.ptr(r); + PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); for (int c = 0; c < w; ++c) { #define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0 @@ -323,12 +324,12 @@ namespace cv{ if (condition_r){ if (condition_p){ //concavity p->x->r. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]); } else{ //not p and q if (condition_s){ //step s->x->r. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); + imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]); } else{ //not p, q and s //copy r @@ -349,7 +350,7 @@ namespace cv{ else{ //new label imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; } } @@ -363,7 +364,7 @@ namespace cv{ } } //write in the follower memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; + chunksSizeAndLabels_[startR + 1] = label - firstLabel; } #undef condition_p #undef condition_q @@ -373,26 +374,26 @@ namespace cv{ }; class FirstScan4Connectivity : public cv::ParallelLoopBody{ - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + const cv::Mat& img_; + cv::Mat& imgLabels_; + LabelT *P_; + int *chunksSizeAndLabels_; public: - FirstScan4Connectivity(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + FirstScan4Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels) + : img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){} - FirstScan4Connectivity & operator=(const FirstScan4Connectivity &) { return *this; } + FirstScan4Connectivity& operator=(const FirstScan4Connectivity& ) { return *this; } - void operator()(const cv::Range &range) const{ + void operator()(const cv::Range& range) const{ int r = range.start; - _chunksSizeAndLabels[r] = range.end; + chunksSizeAndLabels_[r] = range.end; - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); const LabelT firstLabel = label; - const int w = _img.cols; + const int w = img_.cols; const int limitLine = r, startR = r; // Rosenfeld Mask @@ -402,10 +403,10 @@ namespace cv{ // |s|x| // +-+-+ for (; r != range.end; ++r){ - PixelT const * const img_row = _img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0]); + PixelT const *const img_row = img_.ptr(r); + PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); for (int c = 0; c < w; ++c) { #define condition_q r > limitLine && img_row_prev[c] > 0 @@ -416,7 +417,7 @@ namespace cv{ if (condition_q){ if (condition_s){ //step s->x->q. Merge - imgLabels_row[c] = set_union(_P, imgLabels_row[c - 1], imgLabels_row_prev[c]); + imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c]); } else{ //copy q @@ -430,7 +431,7 @@ namespace cv{ else{ //new label imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; } } @@ -442,7 +443,7 @@ namespace cv{ } } //write in the following memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; + chunksSizeAndLabels_[startR + 1] = label - firstLabel; } #undef condition_q #undef condition_s @@ -450,45 +451,45 @@ namespace cv{ }; class SecondScan : public cv::ParallelLoopBody{ - cv::Mat &_imgLabels; - const LabelT *_P; - StatsOp &_sop; - StatsOp *_sopArray; - LabelT &_nLabels; + cv::Mat& imgLabels_; + const LabelT *P_; + StatsOp& sop_; + StatsOp *sopArray_; + LabelT& nLabels_; public: - SecondScan(cv::Mat &imgLabels, const LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) - : _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + SecondScan(cv::Mat& imgLabels, const LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels) + : imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){} - SecondScan & operator=(const SecondScan &) { return *this; } + SecondScan& operator=(const SecondScan& ) { return *this; } - void operator()(const cv::Range &range) const{ + void operator()(const cv::Range& range) const{ int r = range.start; const int rowBegin = r; const int rowEnd = range.end; if (rowBegin > 0){ - _sopArray[rowBegin].initElement(_nLabels); - _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; + sopArray_[rowBegin].initElement(nLabels_); + sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; for (; r < rowEnd; ++r) { - LabelT * img_row_start = _imgLabels.ptr(r); - LabelT * const img_row_end = img_row_start + _imgLabels.cols; + LabelT * img_row_start = imgLabels_.ptr(r); + LabelT * const img_row_end = img_row_start + imgLabels_.cols; for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ - *img_row_start = _P[*img_row_start]; - _sopArray[rowBegin](r, c, *img_row_start); + *img_row_start = P_[*img_row_start]; + sopArray_[rowBegin](r, c, *img_row_start); } } } else{ //the first thread uses sop in order to make less merges - _sop.setNextLoc(rowEnd); + sop_.setNextLoc(rowEnd); for (; r < rowEnd; ++r) { - LabelT * img_row_start = _imgLabels.ptr(r); - LabelT * const img_row_end = img_row_start + _imgLabels.cols; + LabelT * img_row_start = imgLabels_.ptr(r); + LabelT * const img_row_end = img_row_start + imgLabels_.cols; for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){ - *img_row_start = _P[*img_row_start]; - _sop(r, c, *img_row_start); + *img_row_start = P_[*img_row_start]; + sop_(r, c, *img_row_start); } } } @@ -496,7 +497,7 @@ namespace cv{ }; inline static - void mergeLabels8Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + void mergeLabels8Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){ // Merge Mask // +-+-+-+ @@ -541,7 +542,7 @@ namespace cv{ } inline static - void mergeLabels4Connectivity(cv::Mat &imgLabels, LabelT *P, const int *chunksSizeAndLabels){ + void mergeLabels4Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){ // Merge Mask // +-+-+-+ @@ -573,12 +574,12 @@ namespace cv{ #undef condition_x } - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ CV_Assert(img.rows == imgLabels.rows); CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8 || connectivity == 4); - const int nThreads = cv::getNumThreads(); + const int nThreads = cv::getNumberOfCPUs(); cv::setNumThreads(nThreads); const int h = img.rows; @@ -593,14 +594,14 @@ namespace cv{ //1 0 1 0 1... //............ //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + const size_t Plength = (size_t(h) *size_t(w) + 1) / 2 + 1; //Array used to store info and labeled pixel by each thread. //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h *sizeof(int)); //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + LabelT *P = (LabelT *)cv::fastMalloc(Plength *sizeof(LabelT)); //First label is for background P[0] = 0; @@ -625,19 +626,19 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics dataof threads - StatsOp *SopArray = new StatsOp[h]; + StatsOp *sopArray = new StatsOp[h]; sop.init(nLabels); //Second scan - cv::parallel_for_(range, SecondScan(imgLabels, P, sop, SopArray, nLabels), nThreads); - StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nThreads); + StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels); sop.finish(); - delete[] SopArray; + delete[] sopArray; cv::fastFree(chunksSizeAndLabels); cv::fastFree(P); return nLabels; @@ -650,7 +651,7 @@ namespace cv{ template struct LabelingWu{ - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ CV_Assert(imgLabels.rows == img.rows); CV_Assert(imgLabels.cols == img.cols); CV_Assert(connectivity == 8 || connectivity == 4); @@ -667,9 +668,9 @@ namespace cv{ //1 0 1 0 1... //............ //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; + const size_t Plength = (size_t(h) *size_t(w) + 1) / 2 + 1; //array P for equivalences resolution - LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); //first label is for background pixels P[0] = 0; LabelT lunique = 1; @@ -677,8 +678,8 @@ namespace cv{ if (connectivity == 8){ for (int r = 0; r < h; ++r){ // Get row pointers - PixelT const * const img_row = img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + PixelT const *const img_row = img.ptr(r); + PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); LabelT * const imgLabels_row = imgLabels.ptr(r); LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); @@ -750,8 +751,8 @@ namespace cv{ } else{ for (int r = 0; r < h; ++r){ - PixelT const * const img_row = img.ptr(r); - PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + PixelT const *const img_row = img.ptr(r); + PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); LabelT * const imgLabels_row = imgLabels.ptr(r); LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); for (int c = 0; c < w; ++c) { @@ -823,38 +824,38 @@ namespace cv{ class FirstScan : public cv::ParallelLoopBody{ private: - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - int *_chunksSizeAndLabels; + const cv::Mat& img_; + cv::Mat& imgLabels_; + LabelT *P_; + int *chunksSizeAndLabels_; public: - FirstScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _chunksSizeAndLabels(chunksSizeAndLabels){} + FirstScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels) + : img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){} - FirstScan & operator=(const FirstScan&) { return *this; } + FirstScan& operator=(const FirstScan&) { return *this; } - void operator()(const cv::Range &range) const{ + void operator()(const cv::Range& range) const{ int r = range.start; r += (r % 2); - _chunksSizeAndLabels[r] = range.end + (range.end % 2); + chunksSizeAndLabels_[r] = range.end + (range.end % 2); - LabelT label = LabelT(r * _imgLabels.cols / 4 + 1); + LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); const LabelT firstLabel = label; - const int h = _img.rows, w = _img.cols; + const int h = img_.rows, w = img_.cols; const int limitLine = r + 1, startR = r; for (; r < range.end; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - _img.step.p[0]); - const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - _img.step.p[0]); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - _imgLabels.step.p[0] - _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); + const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img_.step.p[0]); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0] - imgLabels_.step.p[0]); for (int c = 0; c < w; c += 2) { // We work with 2x2 blocks @@ -928,20 +929,20 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -971,27 +972,27 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1026,7 +1027,7 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1047,20 +1048,20 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1068,25 +1069,25 @@ namespace cv{ else { if (condition_i) { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } else { if (condition_h) { if (condition_c) { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } else { - //Action_14: Merge labels of block _P, Q and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); + //Action_14: Merge labels of block P_, Q and S + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1111,14 +1112,14 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1139,20 +1140,20 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1161,24 +1162,24 @@ namespace cv{ if (condition_g) { if (condition_b) { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1188,12 +1189,12 @@ namespace cv{ if (condition_i) { if (condition_d) { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } @@ -1202,24 +1203,24 @@ namespace cv{ if (condition_d) { if (condition_c) { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { - //Action_15: Merge labels of block _P, R and S - 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]); + //Action_15: Merge labels of block P_, R and S + 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]); continue; } } else { - //Action_15: Merge labels of block _P, R and S - 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]); + //Action_15: Merge labels of block P_, R and S + 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]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1233,8 +1234,8 @@ namespace cv{ continue; } else { - // ACTION_9 Merge labels of block _P and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + // ACTION_9 Merge labels of block P_ and S + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); continue; } } @@ -1249,19 +1250,19 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1281,8 +1282,8 @@ namespace cv{ continue; } else { - // ACTION_9 Merge labels of block _P and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + // ACTION_9 Merge labels of block P_ and S + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); continue; } } @@ -1297,19 +1298,19 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1337,8 +1338,8 @@ namespace cv{ continue; } else { - //Action_7: Merge labels of block _P and Q - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + //Action_7: Merge labels of block P_ and Q + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); continue; } } @@ -1360,7 +1361,7 @@ namespace cv{ } else { // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } @@ -1373,14 +1374,14 @@ namespace cv{ continue; } else { - //Action_8: Merge labels of block _P and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + //Action_8: Merge labels of block P_ and R + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); continue; } } else { - //Action_8: Merge labels of block _P and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); + //Action_8: Merge labels of block P_ and R + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); continue; } } @@ -1399,14 +1400,14 @@ namespace cv{ } else { if (condition_h) { - //Action_3: Assign label of block _P + //Action_3: Assign label of block P_ imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; continue; } else { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1421,14 +1422,14 @@ namespace cv{ } else { if (condition_h) { - //Action_3: Assign label of block _P + //Action_3: Assign label of block P_ imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; continue; } else { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1464,20 +1465,20 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1506,27 +1507,27 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1555,7 +1556,7 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1576,27 +1577,27 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1618,7 +1619,7 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1639,27 +1640,27 @@ namespace cv{ } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1668,38 +1669,38 @@ namespace cv{ if (condition_m) { if (condition_h) { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { if (condition_g) { if (condition_b) { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } } else { //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(_P, set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -1721,20 +1722,20 @@ namespace cv{ } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } else { //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } @@ -1762,7 +1763,7 @@ namespace cv{ } else { // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } @@ -1781,7 +1782,7 @@ namespace cv{ else { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1805,7 +1806,7 @@ namespace cv{ else { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1829,7 +1830,7 @@ namespace cv{ } else { // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(_P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } @@ -1848,7 +1849,7 @@ namespace cv{ else { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1859,7 +1860,7 @@ namespace cv{ if (condition_t) { //Action_2: New label (the block has foreground pixels and is not connected to anything else) imgLabels_row[c] = label; - _P[label] = label; + P_[label] = label; label = label + 1; continue; } @@ -1874,7 +1875,7 @@ namespace cv{ } } //write in the follower memory location - _chunksSizeAndLabels[startR + 1] = label - firstLabel; + chunksSizeAndLabels_[startR + 1] = label - firstLabel; } #undef condition_k #undef condition_j @@ -1889,20 +1890,20 @@ namespace cv{ class SecondScan : public cv::ParallelLoopBody{ private: - const cv::Mat &_img; - cv::Mat &_imgLabels; - LabelT *_P; - StatsOp &_sop; - StatsOp *_sopArray; - LabelT &_nLabels; + const cv::Mat& img_; + cv::Mat& imgLabels_; + LabelT *P_; + StatsOp& sop_; + StatsOp *sopArray_; + LabelT& nLabels_; public: - SecondScan(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, StatsOp &sop, StatsOp *SopArray, LabelT &nLabels) - : _img(img), _imgLabels(imgLabels), _P(P), _sop(sop), _sopArray(SopArray), _nLabels(nLabels){} + SecondScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels) + : img_(img), imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){} - SecondScan & operator=(const SecondScan &) { return *this; } + SecondScan& operator=(const SecondScan& ) { return *this; } - void operator()(const cv::Range &range) const{ + void operator()(const cv::Range& range) const{ int r = range.start; r += (r % 2); @@ -1910,87 +1911,87 @@ namespace cv{ const int rowEnd = range.end + range.end % 2; if (rowBegin > 0){ - _sopArray[rowBegin].initElement(_nLabels); - _sopArray[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; + sopArray_[rowBegin].initElement(nLabels_); + sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd; - if (_imgLabels.rows & 1){ - if (_imgLabels.cols & 1){ + if (imgLabels_.rows& 1){ + if (imgLabels_.cols& 1){ //Case 1: both rows and cols odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); + sopArray_[rowBegin](r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c, 0); } - if (c + 1 < _imgLabels.cols) { + if (c + 1 < imgLabels_.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); + sopArray_[rowBegin](r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r, c + 1, 0); } - if (r + 1 < _imgLabels.rows) { + if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); + sopArray_[rowBegin](r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); + sopArray_[rowBegin](r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } } - else if (r + 1 < _imgLabels.rows) { + else if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); + sopArray_[rowBegin](r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } } } else { imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); - if (c + 1 < _imgLabels.cols) { + sopArray_[rowBegin](r, c, 0); + if (c + 1 < imgLabels_.cols) { imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { + sopArray_[rowBegin](r, c + 1, 0); + if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } - else if (r + 1 < _imgLabels.rows) { + else if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } } } @@ -2000,60 +2001,60 @@ namespace cv{ //Case 2: only rows odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); + sopArray_[rowBegin](r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c, 0); } if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); + sopArray_[rowBegin](r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r, c + 1, 0); } - if (r + 1 < _imgLabels.rows) { + if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); + sopArray_[rowBegin](r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); + sopArray_[rowBegin](r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } } else { imgLabels_row[c] = 0; imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { + sopArray_[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c + 1, 0); + if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } } @@ -2061,64 +2062,64 @@ namespace cv{ }// END Case 2 } else{ - if (_imgLabels.cols & 1){ + if (imgLabels_.cols& 1){ //Case 3: only cols odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); + sopArray_[rowBegin](r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c, 0); } if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); + sopArray_[rowBegin](r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } - if (c + 1 < _imgLabels.cols) { + if (c + 1 < imgLabels_.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); + sopArray_[rowBegin](r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r, c + 1, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); + sopArray_[rowBegin](r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } } else{ imgLabels_row[c] = 0; imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r + 1, c, 0); - if (c + 1 < _imgLabels.cols) { + sopArray_[rowBegin](r, c, 0); + sopArray_[rowBegin](r + 1, c, 0); + if (c + 1 < imgLabels_.cols) { imgLabels_row[c + 1] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } } @@ -2128,46 +2129,46 @@ namespace cv{ //Case 4: nothing odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sopArray[rowBegin](r, c, iLabel); + sopArray_[rowBegin](r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sopArray[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c, 0); } if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sopArray[rowBegin](r, c + 1, iLabel); + sopArray_[rowBegin](r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sopArray[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r, c + 1, 0); } if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sopArray[rowBegin](r + 1, c, iLabel); + sopArray_[rowBegin](r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sopArray[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sopArray[rowBegin](r + 1, c + 1, iLabel); + sopArray_[rowBegin](r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } else { @@ -2175,10 +2176,10 @@ namespace cv{ imgLabels_row[c + 1] = 0; imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sopArray[rowBegin](r, c, 0); - _sopArray[rowBegin](r, c + 1, 0); - _sopArray[rowBegin](r + 1, c, 0); - _sopArray[rowBegin](r + 1, c + 1, 0); + sopArray_[rowBegin](r, c, 0); + sopArray_[rowBegin](r, c + 1, 0); + sopArray_[rowBegin](r + 1, c, 0); + sopArray_[rowBegin](r + 1, c + 1, 0); } } }//END case 4 @@ -2187,85 +2188,85 @@ namespace cv{ } else{ //the first thread uses sop in order to make less merges - _sop.setNextLoc(rowEnd); - if (_imgLabels.rows & 1){ - if (_imgLabels.cols & 1){ + sop_.setNextLoc(rowEnd); + if (imgLabels_.rows& 1){ + if (imgLabels_.cols& 1){ //Case 1: both rows and cols odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); + sop_(r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sop(r, c, 0); + sop_(r, c, 0); } - if (c + 1 < _imgLabels.cols) { + if (c + 1 < imgLabels_.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); + sop_(r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); + sop_(r, c + 1, 0); } - if (r + 1 < _imgLabels.rows) { + if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); + sop_(r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); + sop_(r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); + sop_(r + 1, c + 1, 0); } } } - else if (r + 1 < _imgLabels.rows) { + else if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); + sop_(r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } } } else { imgLabels_row[c] = 0; - _sop(r, c, 0); - if (c + 1 < _imgLabels.cols) { + sop_(r, c, 0); + if (c + 1 < imgLabels_.cols) { imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { + sop_(r, c + 1, 0); + if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c, 0); - _sop(r + 1, c + 1, 0); + sop_(r + 1, c, 0); + sop_(r + 1, c + 1, 0); } } - else if (r + 1 < _imgLabels.rows) { + else if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } } } @@ -2275,60 +2276,60 @@ namespace cv{ //Case 2: only rows odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); + sop_(r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sop(r, c, 0); + sop_(r, c, 0); } if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); + sop_(r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); + sop_(r, c + 1, 0); } - if (r + 1 < _imgLabels.rows) { + if (r + 1 < imgLabels_.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); + sop_(r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); + sop_(r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); + sop_(r + 1, c + 1, 0); } } } else { imgLabels_row[c] = 0; imgLabels_row[c + 1] = 0; - _sop(r, c, 0); - _sop(r, c + 1, 0); - if (r + 1 < _imgLabels.rows) { + sop_(r, c, 0); + sop_(r, c + 1, 0); + if (r + 1 < imgLabels_.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c, 0); - _sop(r + 1, c + 1, 0); + sop_(r + 1, c, 0); + sop_(r + 1, c + 1, 0); } } } @@ -2336,64 +2337,64 @@ namespace cv{ }// END Case 2 } else{ - if (_imgLabels.cols & 1){ + if (imgLabels_.cols& 1){ //Case 3: only cols odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); + sop_(r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sop(r, c, 0); + sop_(r, c, 0); } if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); + sop_(r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } - if (c + 1 < _imgLabels.cols) { + if (c + 1 < imgLabels_.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); + sop_(r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); + sop_(r, c + 1, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); + sop_(r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); + sop_(r + 1, c + 1, 0); } } } else{ imgLabels_row[c] = 0; imgLabels_row_fol[c] = 0; - _sop(r, c, 0); - _sop(r + 1, c, 0); - if (c + 1 < _imgLabels.cols) { + sop_(r, c, 0); + sop_(r + 1, c, 0); + if (c + 1 < imgLabels_.cols) { imgLabels_row[c + 1] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r, c + 1, 0); - _sop(r + 1, c + 1, 0); + sop_(r, c + 1, 0); + sop_(r + 1, c + 1, 0); } } } @@ -2403,46 +2404,46 @@ namespace cv{ //Case 4: nothing odd for (; r < rowEnd; r += 2){ // Get rows pointer - const PixelT * const img_row = _img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + _img.step.p[0]); - LabelT * const imgLabels_row = _imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + _imgLabels.step.p[0]); + const PixelT * const img_row = img_.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]); // Get rows pointer - for (int c = 0; c < _imgLabels.cols; c += 2) { + for (int c = 0; c < imgLabels_.cols; c += 2) { LabelT iLabel = imgLabels_row[c]; if (iLabel > 0) { - iLabel = _P[iLabel]; + iLabel = P_[iLabel]; if (img_row[c] > 0){ imgLabels_row[c] = iLabel; - _sop(r, c, iLabel); + sop_(r, c, iLabel); } else{ imgLabels_row[c] = 0; - _sop(r, c, 0); + sop_(r, c, 0); } if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; - _sop(r, c + 1, iLabel); + sop_(r, c + 1, iLabel); } else{ imgLabels_row[c + 1] = 0; - _sop(r, c + 1, 0); + sop_(r, c + 1, 0); } if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; - _sop(r + 1, c, iLabel); + sop_(r + 1, c, iLabel); } else{ imgLabels_row_fol[c] = 0; - _sop(r + 1, c, 0); + sop_(r + 1, c, 0); } if (img_row_fol[c + 1] > 0){ imgLabels_row_fol[c + 1] = iLabel; - _sop(r + 1, c + 1, iLabel); + sop_(r + 1, c + 1, iLabel); } else{ imgLabels_row_fol[c + 1] = 0; - _sop(r + 1, c + 1, 0); + sop_(r + 1, c + 1, 0); } } else { @@ -2450,10 +2451,10 @@ namespace cv{ imgLabels_row[c + 1] = 0; imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - _sop(r, c, 0); - _sop(r, c + 1, 0); - _sop(r + 1, c, 0); - _sop(r + 1, c + 1, 0); + sop_(r, c, 0); + sop_(r, c + 1, 0); + sop_(r + 1, c, 0); + sop_(r + 1, c + 1, 0); } } }//END case 4 @@ -2464,7 +2465,7 @@ namespace cv{ }; inline static - void mergeLabels(const cv::Mat &img, cv::Mat &imgLabels, LabelT *P, int *chunksSizeAndLabels){ + void mergeLabels(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels){ // Merge Mask // +---+---+---+ @@ -2520,12 +2521,12 @@ namespace cv{ } } - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ CV_Assert(img.rows == imgLabels.rows); CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8); - const int nThreads = cv::getNumThreads(); + const int nThreads = cv::getNumberOfCPUs(); cv::setNumThreads(nThreads); const int h = img.rows; @@ -2539,14 +2540,14 @@ namespace cv{ //0 0 0 0 0... //1 0 1 0 1... //............ - const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + const size_t Plength = ((size_t(h) + 1) *(size_t(w) + 1)) / 4 + 1; //Array used to store info and labeled pixel by each thread. //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h *sizeof(int)); //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); + LabelT *P = (LabelT *)cv::fastMalloc(Plength *sizeof(LabelT)); //First label is for background P[0] = 0; @@ -2561,20 +2562,20 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + flattenL(P, i *w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics data - StatsOp *SopArray = new StatsOp[h]; + StatsOp *sopArray = new StatsOp[h]; sop.init(nLabels); //Second scan - cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, SopArray, nLabels), nThreads); + cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nThreads); - StatsOp::mergeStats(imgLabels, SopArray, sop, nLabels); + StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels); sop.finish(); - delete[] SopArray; + delete[] sopArray; cv::fastFree(chunksSizeAndLabels); cv::fastFree(P); return nLabels; @@ -2585,7 +2586,7 @@ namespace cv{ // Only for 8-connectivity template struct LabelingGrana{ - LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity, StatsOp &sop){ + LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ CV_Assert(img.rows == imgLabels.rows); CV_Assert(img.cols == imgLabels.cols); CV_Assert(connectivity == 8); @@ -2601,9 +2602,9 @@ namespace cv{ //0 0 0 0 0... //1 0 1 0 1... //............ - const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + const size_t Plength = ((size_t(h) + 1) *(size_t(w) + 1)) / 4 + 1; - LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength); + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); P[0] = 0; LabelT lunique = 1; @@ -2642,8 +2643,8 @@ namespace cv{ // without going outside the image limits. #define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0 #define condition_c r-2>=0 && img_row_prev_prev[c]>0 -#define condition_d c+1=0 && img_row_prev_prev[c+1]>0 -#define condition_e c+2=0 && img_row_prev_prev[c+2]>0 +#define condition_d c+1=0 && img_row_prev_prev[c+1]>0 +#define condition_e c+2=0 && img_row_prev[c-1]>0 #define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0 #define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0 @@ -3640,8 +3641,8 @@ namespace cv{ LabelT nLabels = flattenL(P, lunique); sop.init(nLabels); - if (imgLabels.rows & 1){ - if (imgLabels.cols & 1){ + if (imgLabels.rows& 1){ + if (imgLabels.cols& 1){ //Case 1: both rows and cols odd for (int r = 0; r < imgLabels.rows; r += 2) { // Get rows pointer @@ -3787,7 +3788,7 @@ namespace cv{ }// END Case 2 } else{ - if (imgLabels.cols & 1){ + if (imgLabels.cols& 1){ //Case 3: only cols odd for (int r = 0; r < imgLabels.rows; r += 2) { // Get rows pointer @@ -3923,83 +3924,83 @@ namespace cv{ //L's type must have an appropriate depth for the number of pixels in I template static - int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){ - CV_Assert(L.channels() == 1 && I.channels() == 1); - CV_Assert(connectivity == 8 || connectivity == 4); - CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT); + int connectedComponents_sub1(const cv::Mat& I, cv::Mat& L, int connectivity, int ccltype, StatsOp& sop){ + CV_Assert(L.channels() == 1 && I.channels() == 1); + CV_Assert(connectivity == 8 || connectivity == 4); + CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT); - int lDepth = L.depth(); - int iDepth = I.depth(); - const char* currentParallelFramework = cv::currentParallelFramework(); + int lDepth = L.depth(); + int iDepth = I.depth(); + const char *currentParallelFramework = cv::currentParallelFramework(); - CV_Assert(iDepth == CV_8U || iDepth == CV_8S); + CV_Assert(iDepth == CV_8U || iDepth == CV_8S); - if (ccltype == CCL_WU || connectivity == 4){ - // Wu algorithm is used - using connectedcomponents::LabelingWu; - using connectedcomponents::LabelingWuParallel; - //warn if L's depth is not sufficient? - if (lDepth == CV_8U){ - if (currentParallelFramework == NULL) - return (int)LabelingWu()(I, L, connectivity, sop); - else - return (int)LabelingWuParallel()(I, L, connectivity, sop); - } - else if (lDepth == CV_16U){ - if (currentParallelFramework == NULL) - return (int)LabelingWu()(I, L, connectivity, sop); - else - return (int)LabelingWuParallel()(I, L, connectivity, sop); - } - else if (lDepth == CV_32S){ - //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects - //OpenCV: how should we proceed? .at typechecks in debug mode - if (currentParallelFramework == NULL) - return (int)LabelingWu()(I, L, connectivity, sop); - else - return (int)LabelingWuParallel()(I, L, connectivity, sop); - } + if (ccltype == CCL_WU || connectivity == 4){ + // Wu algorithm is used + using connectedcomponents::LabelingWu; + using connectedcomponents::LabelingWuParallel; + //warn if L's depth is not sufficient? + if (lDepth == CV_8U){ + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); } - else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){ - // Grana algorithm is used - using connectedcomponents::LabelingGrana; - using connectedcomponents::LabelingGranaParallel; - //warn if L's depth is not sufficient? - if (lDepth == CV_8U){ - if (currentParallelFramework == NULL) - return (int)LabelingGrana()(I, L, connectivity, sop); - else - return (int)LabelingGranaParallel()(I, L, connectivity, sop); - } - else if (lDepth == CV_16U){ - if (currentParallelFramework == NULL) - return (int)LabelingGrana()(I, L, connectivity, sop); - else - return (int)LabelingGranaParallel()(I, L, connectivity, sop); - } - else if (lDepth == CV_32S){ - //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects - //OpenCV: how should we proceed? .at typechecks in debug mode - if (currentParallelFramework == NULL) - return (int)LabelingGrana()(I, L, connectivity, sop); - else - return (int)LabelingGranaParallel()(I, L, connectivity, sop); - } + else if (lDepth == CV_16U){ + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); + } + else if (lDepth == CV_32S){ + //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects + //OpenCV: how should we proceed? .at typechecks in debug mode + if (currentParallelFramework == NULL) + return (int)LabelingWu()(I, L, connectivity, sop); + else + return (int)LabelingWuParallel()(I, L, connectivity, sop); } - - CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type"); - return -1; } + else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){ + // Grana algorithm is used + using connectedcomponents::LabelingGrana; + using connectedcomponents::LabelingGranaParallel; + //warn if L's depth is not sufficient? + if (lDepth == CV_8U){ + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); + } + else if (lDepth == CV_16U){ + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); + } + else if (lDepth == CV_32S){ + //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects + //OpenCV: how should we proceed? .at typechecks in debug mode + if (currentParallelFramework == NULL) + return (int)LabelingGrana()(I, L, connectivity, sop); + else + return (int)LabelingGranaParallel()(I, L, connectivity, sop); + } + } + + CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type"); + return -1; + } } // Simple wrapper to ensure binary and source compatibility (ABI) -int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivity, int ltype){ - return cv::connectedComponents(_img, _labels, connectivity, ltype, CCL_DEFAULT); +int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype){ + return cv::connectedComponents(img_, _labels, connectivity, ltype, CCL_DEFAULT); } -int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivity, int ltype, int ccltype){ - const cv::Mat img = _img.getMat(); +int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype, int ccltype){ + const cv::Mat img = img_.getMat(); _labels.create(img.size(), CV_MAT_DEPTH(ltype)); cv::Mat labels = _labels.getMat(); connectedcomponents::NoOp sop; @@ -4016,16 +4017,16 @@ int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivi } // Simple wrapper to ensure binary and source compatibility (ABI) -int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv, +int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv, OutputArray centroids, int connectivity, int ltype) { - return cv::connectedComponentsWithStats(_img, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT); + return cv::connectedComponentsWithStats(img_, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT); } -int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv, +int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv, OutputArray centroids, int connectivity, int ltype, int ccltype) { - const cv::Mat img = _img.getMat(); + const cv::Mat img = img_.getMat(); _labels.create(img.size(), CV_MAT_DEPTH(ltype)); cv::Mat labels = _labels.getMat(); connectedcomponents::CCStatsOp sop(statsv, centroids); From 89a0a46a69499c84784d4fe4d1120e489d3bea9a Mon Sep 17 00:00:00 2001 From: Michele Cancilla Date: Mon, 28 Nov 2016 14:54:44 +0100 Subject: [PATCH 4/6] Removed parallel version for CV_16U label type --- modules/imgproc/include/opencv2/imgproc.hpp | 4 +- modules/imgproc/src/connectedcomponents.cpp | 1929 +++++++++---------- 2 files changed, 962 insertions(+), 971 deletions(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 1f5c76c7f4..1ef15e6855 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3677,7 +3677,7 @@ the source image. ccltype specifies the connected components labeling algorithm Grana (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. This function uses parallel version of both Grana and Wu's algorithms if at least one allowed -parallel framework is enabled. +parallel framework is enabled and if the rows of the image are at least twice the number returned by getNumberOfCPUs. @param image the 8-bit single-channel image to be labeled @param labels destination labeled image @@ -3709,7 +3709,7 @@ the source image. ccltype specifies the connected components labeling algorithm Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not. This function uses parallel version of both Grana and Wu's algorithms (statistics included) if at least one allowed -parallel framework is enabled. +parallel framework is enabled and if the rows of the image are at least twice the number returned by getNumberOfCPUs. @param image the 8-bit single-channel image to be labeled @param labels destination labeled image diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index 86bb8919df..d94a6a9e4c 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -100,21 +100,21 @@ namespace cv{ inline void init(int nlabels){ - _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); - statsv = _mstatsv->getMat(); - _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); - centroidsv = _mcentroidsv->getMat(); + _mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType::type); + statsv = _mstatsv->getMat(); + _mcentroidsv->create(cv::Size(2, nlabels), cv::DataType::type); + centroidsv = _mcentroidsv->getMat(); - for (int l = 0; l < (int)nlabels; ++l){ - int *row = (int *)&statsv.at(l, 0); - row[CC_STAT_LEFT] = INT_MAX; - row[CC_STAT_TOP] = INT_MAX; - row[CC_STAT_WIDTH] = INT_MIN; - row[CC_STAT_HEIGHT] = INT_MIN; - row[CC_STAT_AREA] = 0; - } - integrals.resize(nlabels, Point2ui64(0, 0)); + for (int l = 0; l < (int)nlabels; ++l){ + int *row = (int *)&statsv.at(l, 0); + row[CC_STAT_LEFT] = INT_MAX; + row[CC_STAT_TOP] = INT_MAX; + row[CC_STAT_WIDTH] = INT_MIN; + row[CC_STAT_HEIGHT] = INT_MIN; + row[CC_STAT_AREA] = 0; } + integrals.resize(nlabels, Point2ui64(0, 0)); + } inline void initElement(const int nlabels){ @@ -149,7 +149,7 @@ namespace cv{ row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1; Point2ui64& integral = integrals[l]; - double *centroid =& centroidsv.at(l, 0); + double *centroid = ¢roidsv.at(l, 0); double area = ((unsigned*)row)[CC_STAT_AREA]; centroid[0] = double(integral.x) / area; centroid[1] = double(integral.y) / area; @@ -288,7 +288,7 @@ namespace cv{ int r = range.start; chunksSizeAndLabels_[r] = range.end; - LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); + LabelT label = LabelT((r * imgLabels_.cols + 1) / 2 + 1); const LabelT firstLabel = label; const int w = img_.cols; @@ -302,10 +302,10 @@ namespace cv{ // +-+-+ for (; r != range.end; ++r) { - PixelT const *const img_row = img_.ptr(r); - PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); - LabelT * const imgLabels_row = imgLabels_.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); + PixelT const * const img_row = img_.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); for (int c = 0; c < w; ++c) { #define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0 @@ -390,7 +390,7 @@ namespace cv{ int r = range.start; chunksSizeAndLabels_[r] = range.end; - LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); + LabelT label = LabelT((r * imgLabels_.cols + 1) / 2 + 1); const LabelT firstLabel = label; const int w = img_.cols; @@ -403,10 +403,10 @@ namespace cv{ // |s|x| // +-+-+ for (; r != range.end; ++r){ - PixelT const *const img_row = img_.ptr(r); - PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); - LabelT * const imgLabels_row = imgLabels_.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); + PixelT const * const img_row = img_.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]); + LabelT * const imgLabels_row = imgLabels_.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]); for (int c = 0; c < w; ++c) { #define condition_q r > limitLine && img_row_prev[c] > 0 @@ -510,7 +510,7 @@ namespace cv{ for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); for (int c = 0; c < w; ++c){ @@ -555,7 +555,7 @@ namespace cv{ for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){ LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); for (int c = 0; c < w; ++c){ @@ -594,18 +594,19 @@ namespace cv{ //1 0 1 0 1... //............ //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) *size_t(w) + 1) / 2 + 1; + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; //Array used to store info and labeled pixel by each thread. //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h *sizeof(int)); + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength *sizeof(LabelT)); + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); //First label is for background P[0] = 0; cv::Range range(0, h); + LabelT nLabels = 1; if (connectivity == 8){ //First scan, each thread works with chunk of img.rows/nThreads rows @@ -623,10 +624,9 @@ namespace cv{ //merge labels of different chunks mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); } - LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i * w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + flattenL(P, (i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics dataof threads @@ -650,7 +650,6 @@ namespace cv{ //Kesheng Wu, et al template struct LabelingWu{ - LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ CV_Assert(imgLabels.rows == img.rows); CV_Assert(imgLabels.cols == img.cols); @@ -668,7 +667,7 @@ namespace cv{ //1 0 1 0 1... //............ //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling - const size_t Plength = (size_t(h) *size_t(w) + 1) / 2 + 1; + const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1; //array P for equivalences resolution LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); //first label is for background pixels @@ -678,10 +677,10 @@ namespace cv{ if (connectivity == 8){ for (int r = 0; r < h; ++r){ // Get row pointers - PixelT const *const img_row = img.ptr(r); - PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); for (int c = 0; c < w; ++c){ @@ -751,10 +750,10 @@ namespace cv{ } else{ for (int r = 0; r < h; ++r){ - PixelT const *const img_row = img.ptr(r); - PixelT const *const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); + PixelT const * const img_row = img.ptr(r); + PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]); for (int c = 0; c < w; ++c) { #define condition_q r > 0 && img_row_prev[c] > 0 @@ -842,7 +841,7 @@ namespace cv{ chunksSizeAndLabels_[r] = range.end + (range.end % 2); - LabelT label = LabelT(r *imgLabels_.cols / 4 + 1); + LabelT label = LabelT((r + 1) * (imgLabels_.cols + 1) / 4); const LabelT firstLabel = label; const int h = img_.rows, w = img_.cols; @@ -2540,14 +2539,14 @@ namespace cv{ //0 0 0 0 0... //1 0 1 0 1... //............ - const size_t Plength = ((size_t(h) + 1) *(size_t(w) + 1)) / 4 + 1; + const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; //Array used to store info and labeled pixel by each thread. //Different threads affect different memory location of chunksSizeAndLabels - int *chunksSizeAndLabels = (int *)cv::fastMalloc(h *sizeof(int)); + int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int)); //Tree of labels - LabelT *P = (LabelT *)cv::fastMalloc(Plength *sizeof(LabelT)); + LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT)); //First label is for background P[0] = 0; @@ -2562,7 +2561,7 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, i *w / 4 + 1, chunksSizeAndLabels[i + 1], nLabels); + flattenL(P, (i + 1) * (w + 1) / 4, chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics data @@ -2587,60 +2586,60 @@ namespace cv{ template struct LabelingGrana{ LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){ - CV_Assert(img.rows == imgLabels.rows); - CV_Assert(img.cols == imgLabels.cols); - CV_Assert(connectivity == 8); + CV_Assert(img.rows == imgLabels.rows); + CV_Assert(img.cols == imgLabels.cols); + CV_Assert(connectivity == 8); - const int h = img.rows; - const int w = img.cols; + const int h = img.rows; + const int w = img.cols; - //A quick and dirty upper bound for the maximimum number of labels. - //Following formula comes from the fact that a 2x2 block in 8-connectivity case - //can never have more than 1 new label and 1 label for background. - //Worst case image example pattern: - //1 0 1 0 1... - //0 0 0 0 0... - //1 0 1 0 1... - //............ - const size_t Plength = ((size_t(h) + 1) *(size_t(w) + 1)) / 4 + 1; + //A quick and dirty upper bound for the maximimum number of labels. + //Following formula comes from the fact that a 2x2 block in 8-connectivity case + //can never have more than 1 new label and 1 label for background. + //Worst case image example pattern: + //1 0 1 0 1... + //0 0 0 0 0... + //1 0 1 0 1... + //............ + const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; - LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); - P[0] = 0; - LabelT lunique = 1; + LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); + P[0] = 0; + LabelT lunique = 1; - // First scan - for (int r = 0; r < h; r += 2) { - // Get rows pointer - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); - const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); - for (int c = 0; c < w; c += 2) { + // First scan + for (int r = 0; r < h; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]); + const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]); + for (int c = 0; c < w; c += 2) { - // We work with 2x2 blocks - // +-+-+-+ - // |P|Q|R| - // +-+-+-+ - // |S|X| - // +-+-+ + // We work with 2x2 blocks + // +-+-+-+ + // |P|Q|R| + // +-+-+-+ + // |S|X| + // +-+-+ - // The pixels are named as follows - // +---+---+---+ - // |a b|c d|e f| - // |g h|i j|k l| - // +---+---+---+ - // |m n|o p| - // |q r|s t| - // +---+---+ + // The pixels are named as follows + // +---+---+---+ + // |a b|c d|e f| + // |g h|i j|k l| + // +---+---+---+ + // |m n|o p| + // |q r|s t| + // +---+---+ - // Pixels a, f, l, q are not needed, since we need to understand the - // the connectivity between these blocks and those pixels only metter - // when considering the outer connectivities + // Pixels a, f, l, q are not needed, since we need to understand the + // the connectivity between these blocks and those pixels only metter + // when considering the outer connectivities - // A bunch of defines used to check if the pixels are foreground, - // without going outside the image limits. + // A bunch of defines used to check if the pixels are foreground, + // without going outside the image limits. #define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0 #define condition_c r-2>=0 && img_row_prev_prev[c]>0 #define condition_d c+1=0 && img_row_prev_prev[c+1]>0 @@ -2661,39 +2660,131 @@ namespace cv{ #define condition_s r+10 #define condition_t c+10 - // This is a decision tree which allows to choose which action to - // perform, checking as few conditions as possible. - // Actions: the blocks label are provisionally stored in the top left - // pixel of the block in the labels image + // This is a decision tree which allows to choose which action to + // perform, checking as few conditions as possible. + // Actions: the blocks label are provisionally stored in the top left + // pixel of the block in the labels image - if (condition_o) { - if (condition_n) { - if (condition_j) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; + if (condition_o) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } } else { - if (condition_c) { - if (condition_h) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { + if (condition_c) { + if (condition_h) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } else { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); @@ -2702,40 +2793,82 @@ namespace cv{ } } else { + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } + else { + if (condition_h) { + if (condition_c) { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + else { + //Action_14: Merge labels of block P, Q and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } } } else { if (condition_p) { if (condition_k) { - if (condition_d) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - if (condition_h) { + if (condition_m) { + if (condition_h) { + if (condition_d) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_12: Merge labels of block R and S @@ -2750,167 +2883,27 @@ namespace cv{ continue; } } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - else { - if (condition_r) { - if (condition_j) { - if (condition_m) { - if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_i) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_h) { - if (condition_c) { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - else { - //Action_14: Merge labels of block P, Q and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_p) { - if (condition_k) { - if (condition_m) { - if (condition_h) { - if (condition_d) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { + if (condition_d) { + if (condition_g) { + if (condition_b) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_d) { - if (condition_g) { - if (condition_b) { - if (condition_i) { + if (condition_c) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } } else { //Action_12: Merge labels of block R and S @@ -2919,18 +2912,18 @@ namespace cv{ } } else { - if (condition_i) { - if (condition_g) { - if (condition_b) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + if (condition_i) { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } else { //Action_16: labels of block Q, R and S @@ -2939,43 +2932,8 @@ namespace cv{ } } else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - } - else { - if (condition_i) { - if (condition_d) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_h) { - if (condition_d) { - if (condition_c) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_15: Merge labels of block P, R and S - 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]); - continue; - } - } - else { - //Action_15: Merge labels of block P, R and S - 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]); + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } @@ -2988,48 +2946,41 @@ namespace cv{ } } else { - if (condition_h) { - if (condition_m) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + if (condition_i) { + if (condition_d) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } else { - // ACTION_9 Merge labels of block P and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); continue; } } else { - if (condition_i) { - if (condition_m) { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_15: Merge labels of block P, R and S + 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]); continue; } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + //Action_15: Merge labels of block P, R and S + 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]); continue; } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } @@ -3083,62 +3034,104 @@ namespace cv{ } } } - } - else { - if (condition_j) { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; + else { + if (condition_h) { + if (condition_m) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + // ACTION_9 Merge labels of block P and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]); + continue; + } } else { - if (condition_h) { - if (condition_c) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; + if (condition_i) { + if (condition_m) { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } } else { - //Action_7: Merge labels of block P and Q - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } else { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } } } + } + } + else { + if (condition_j) { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } else { - if (condition_p) { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } + if (condition_h) { + if (condition_c) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_7: Merge labels of block P and Q + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]); + continue; + } + } + else { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + } + } + else { + if (condition_p) { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } else { - if (condition_h) { - if (condition_d) { - if (condition_c) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - //Action_8: Merge labels of block P and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); - continue; - } + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + if (condition_h) { + if (condition_d) { + if (condition_c) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } else { //Action_8: Merge labels of block P and R @@ -3147,31 +3140,15 @@ namespace cv{ } } else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + //Action_8: Merge labels of block P and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]); continue; } } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } else { - if (condition_h) { - //Action_3: Assign label of block P - imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; - continue; - } - else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; } } } @@ -3197,38 +3174,54 @@ namespace cv{ } } } - } - } - } - else { - if (condition_s) { - if (condition_p) { - if (condition_n) { - if (condition_j) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_h) { + //Action_3: Assign label of block P + imgLabels_row[c] = imgLabels_row_prev_prev[c - 2]; continue; } else { - if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } + } + } + } + } + } + else { + if (condition_s) { + if (condition_p) { + if (condition_n) { + if (condition_j) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_11: Merge labels of block Q and S @@ -3236,17 +3229,80 @@ namespace cv{ continue; } } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_k) { + if (condition_d) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; continue; } + else { + if (condition_c) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; } } else { - if (condition_k) { - if (condition_d) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + else { + if (condition_r) { + if (condition_j) { + if (condition_m) { + if (condition_h) { if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; @@ -3254,101 +3310,10 @@ namespace cv{ } else { if (condition_c) { - if (condition_h) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - } - } - else { - if (condition_r) { - if (condition_j) { - if (condition_m) { - if (condition_h) { - if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } else { //Action_11: Merge labels of block Q and S imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); @@ -3357,135 +3322,18 @@ namespace cv{ } } else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_k) { - if (condition_d) { - if (condition_m) { - if (condition_h) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_g) { - if (condition_b) { - if (condition_i) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - if (condition_c) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_h) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - if (condition_g) { - if (condition_b) { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - } - else { - //Action_16: labels of block Q, R and S - imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); - continue; - } - } - else { - //Action_12: Merge labels of block R and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); - continue; - } - } - } - else { - if (condition_i) { - if (condition_m) { - if (condition_h) { + if (condition_g) { + if (condition_b) { + if (condition_i) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_g) { - if (condition_b) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; - continue; - } - else { - //Action_11: Merge labels of block Q and S - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); - continue; - } + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; } else { //Action_11: Merge labels of block Q and S @@ -3501,67 +3349,261 @@ namespace cv{ } } else { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } } } - } - else { - if (condition_j) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); continue; } - else { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; + } + else { + if (condition_k) { + if (condition_d) { + if (condition_m) { + if (condition_h) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } } else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; + if (condition_g) { + if (condition_b) { + if (condition_i) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_c) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } } } else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); continue; } } else { if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; + if (condition_m) { + if (condition_h) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_16: labels of block Q, R and S + imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_12: Merge labels of block R and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]); + continue; + } + } + } + else { + if (condition_i) { + if (condition_m) { + if (condition_h) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + if (condition_g) { + if (condition_b) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + } + else { + //Action_11: Merge labels of block Q and S + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]); + continue; + } + } + else { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } + } + } + } + else { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; continue; } else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); continue; } } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } } } } } + } + else { + if (condition_r) { + //Action_6: Assign label of block S + imgLabels_row[c] = imgLabels_row[c - 2]; + continue; + } else { - if (condition_r) { + if (condition_n) { //Action_6: Assign label of block S imgLabels_row[c] = imgLabels_row[c - 2]; continue; } else { - if (condition_n) { - //Action_6: Assign label of block S - imgLabels_row[c] = imgLabels_row[c - 2]; + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; + } + } + } + } + else { + if (condition_p) { + if (condition_j) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; + continue; + } + else { + if (condition_k) { + if (condition_i) { + if (condition_d) { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + else { + // ACTION_10 Merge labels of block Q and R + imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); + continue; + } + } + else { + //Action_5: Assign label of block R + imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; + continue; + } + } + else { + if (condition_i) { + //Action_4: Assign label of block Q + imgLabels_row[c] = imgLabels_row_prev_prev[c]; continue; } else { @@ -3575,175 +3617,52 @@ namespace cv{ } } else { - if (condition_p) { - if (condition_j) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - if (condition_k) { - if (condition_i) { - if (condition_d) { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - else { - // ACTION_10 Merge labels of block Q and R - imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]); - continue; - } - } - else { - //Action_5: Assign label of block R - imgLabels_row[c] = imgLabels_row_prev_prev[c + 2]; - continue; - } - } - else { - if (condition_i) { - //Action_4: Assign label of block Q - imgLabels_row[c] = imgLabels_row_prev_prev[c]; - continue; - } - else { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } - } - } + if (condition_t) { + //Action_2: New label (the block has foreground pixels and is not connected to anything else) + imgLabels_row[c] = lunique; + P[lunique] = lunique; + lunique = lunique + 1; + continue; } else { - if (condition_t) { - //Action_2: New label (the block has foreground pixels and is not connected to anything else) - imgLabels_row[c] = lunique; - P[lunique] = lunique; - lunique = lunique + 1; - continue; - } - else { - // Action_1: No action (the block has no foreground pixels) - imgLabels_row[c] = 0; - continue; - } + // Action_1: No action (the block has no foreground pixels) + imgLabels_row[c] = 0; + continue; } } } } - } - // Second scan + analysis - LabelT nLabels = flattenL(P, lunique); - sop.init(nLabels); + } - if (imgLabels.rows& 1){ - if (imgLabels.cols& 1){ - //Case 1: both rows and cols odd - for (int r = 0; r < imgLabels.rows; r += 2) { - // Get rows pointer - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + // Second scan + analysis + LabelT nLabels = flattenL(P, lunique); + sop.init(nLabels); - for (int c = 0; c < imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (c + 1 < imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (r + 1 < imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - sop(r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c + 1, 0); - } - } - } - else if (r + 1 < imgLabels.rows) { - if (img_row_fol[c] > 0){ - imgLabels_row_fol[c] = iLabel; - sop(r + 1, c, iLabel); - } - else{ - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } - } + if (imgLabels.rows & 1){ + if (imgLabels.cols & 1){ + //Case 1: both rows and cols odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); } - else { + else{ imgLabels_row[c] = 0; sop(r, c, 0); - if (c + 1 < imgLabels.cols) { - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - if (r + 1 < imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c, 0); - sop(r + 1, c + 1, 0); - } - } - else if (r + 1 < imgLabels.rows) { - imgLabels_row_fol[c] = 0; - sop(r + 1, c, 0); - } } - } - } - }//END Case 1 - else{ - //Case 2: only rows odd - for (int r = 0; r < imgLabels.rows; r += 2) { - // Get rows pointer - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - - for (int c = 0; c < imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } + if (c + 1 < imgLabels.cols) { if (img_row[c + 1] > 0){ imgLabels_row[c + 1] = iLabel; sop(r, c + 1, iLabel); @@ -3771,44 +3690,7 @@ namespace cv{ } } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; - sop(r, c, 0); - sop(r, c + 1, 0); - if (r + 1 < imgLabels.rows) { - imgLabels_row_fol[c] = 0; - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c, 0); - sop(r + 1, c + 1, 0); - } - } - } - } - }// END Case 2 - } - else{ - if (imgLabels.cols& 1){ - //Case 3: only cols odd - for (int r = 0; r < imgLabels.rows; r += 2) { - // Get rows pointer - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - - for (int c = 0; c < imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } + else if (r + 1 < imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; sop(r + 1, c, iLabel); @@ -3817,69 +3699,59 @@ namespace cv{ imgLabels_row_fol[c] = 0; sop(r + 1, c, 0); } - if (c + 1 < imgLabels.cols) { - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } - if (img_row_fol[c + 1] > 0){ - imgLabels_row_fol[c + 1] = iLabel; - sop(r + 1, c + 1, iLabel); - } - else{ - imgLabels_row_fol[c + 1] = 0; - sop(r + 1, c + 1, 0); - } - } } - else{ - imgLabels_row[c] = 0; - imgLabels_row_fol[c] = 0; - sop(r, c, 0); - sop(r + 1, c, 0); - if (c + 1 < imgLabels.cols) { - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + sop(r, c, 0); + if (c + 1 < imgLabels.cols) { + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + if (r + 1 < imgLabels.rows) { + imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - sop(r, c + 1, 0); + sop(r + 1, c, 0); sop(r + 1, c + 1, 0); } } + else if (r + 1 < imgLabels.rows) { + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } } } - }// END case 3 - else{ - //Case 4: nothing odd - for (int r = 0; r < imgLabels.rows; r += 2) { - // Get rows pointer - const PixelT * const img_row = img.ptr(r); - const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); - LabelT * const imgLabels_row = imgLabels.ptr(r); - LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); + } + }//END Case 1 + else{ + //Case 2: only rows odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - for (int c = 0; c < imgLabels.cols; c += 2) { - LabelT iLabel = imgLabels_row[c]; - if (iLabel > 0) { - iLabel = P[iLabel]; - if (img_row[c] > 0){ - imgLabels_row[c] = iLabel; - sop(r, c, iLabel); - } - else{ - imgLabels_row[c] = 0; - sop(r, c, 0); - } - if (img_row[c + 1] > 0){ - imgLabels_row[c + 1] = iLabel; - sop(r, c + 1, iLabel); - } - else{ - imgLabels_row[c + 1] = 0; - sop(r, c + 1, 0); - } + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (r + 1 < imgLabels.rows) { if (img_row_fol[c] > 0){ imgLabels_row_fol[c] = iLabel; sop(r + 1, c, iLabel); @@ -3897,27 +3769,154 @@ namespace cv{ sop(r + 1, c + 1, 0); } } - else { - imgLabels_row[c] = 0; - imgLabels_row[c + 1] = 0; + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + sop(r, c, 0); + sop(r, c + 1, 0); + if (r + 1 < imgLabels.rows) { imgLabels_row_fol[c] = 0; imgLabels_row_fol[c + 1] = 0; - sop(r, c, 0); - sop(r, c + 1, 0); sop(r + 1, c, 0); sop(r + 1, c + 1, 0); } } } - }//END case 4 - } + } + }// END Case 2 + } + else{ + if (imgLabels.cols & 1){ + //Case 3: only cols odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - sop.finish(); - fastFree(P); + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (c + 1 < imgLabels.cols) { + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c + 1, 0); + } + } + } + else{ + imgLabels_row[c] = 0; + imgLabels_row_fol[c] = 0; + sop(r, c, 0); + sop(r + 1, c, 0); + if (c + 1 < imgLabels.cols) { + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c + 1] = 0; + sop(r, c + 1, 0); + sop(r + 1, c + 1, 0); + } + } + } + } + }// END case 3 + else{ + //Case 4: nothing odd + for (int r = 0; r < imgLabels.rows; r += 2) { + // Get rows pointer + const PixelT * const img_row = img.ptr(r); + const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]); + LabelT * const imgLabels_row = imgLabels.ptr(r); + LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]); - return nLabels; + for (int c = 0; c < imgLabels.cols; c += 2) { + LabelT iLabel = imgLabels_row[c]; + if (iLabel > 0) { + iLabel = P[iLabel]; + if (img_row[c] > 0){ + imgLabels_row[c] = iLabel; + sop(r, c, iLabel); + } + else{ + imgLabels_row[c] = 0; + sop(r, c, 0); + } + if (img_row[c + 1] > 0){ + imgLabels_row[c + 1] = iLabel; + sop(r, c + 1, iLabel); + } + else{ + imgLabels_row[c + 1] = 0; + sop(r, c + 1, 0); + } + if (img_row_fol[c] > 0){ + imgLabels_row_fol[c] = iLabel; + sop(r + 1, c, iLabel); + } + else{ + imgLabels_row_fol[c] = 0; + sop(r + 1, c, 0); + } + if (img_row_fol[c + 1] > 0){ + imgLabels_row_fol[c + 1] = iLabel; + sop(r + 1, c + 1, iLabel); + } + else{ + imgLabels_row_fol[c + 1] = 0; + sop(r + 1, c + 1, 0); + } + } + else { + imgLabels_row[c] = 0; + imgLabels_row[c + 1] = 0; + imgLabels_row_fol[c] = 0; + imgLabels_row_fol[c + 1] = 0; + sop(r, c, 0); + sop(r, c + 1, 0); + sop(r + 1, c, 0); + sop(r + 1, c + 1, 0); + } + } + } + }//END case 4 + } - } //End function LabelingGrana operator() + sop.finish(); + fastFree(P); + + return nLabels; + + } //End function LabelingGrana operator() };//End struct LabelingGrana }//end namespace connectedcomponents @@ -3932,30 +3931,28 @@ namespace cv{ int lDepth = L.depth(); int iDepth = I.depth(); const char *currentParallelFramework = cv::currentParallelFramework(); + const int numberOfCPUs = cv::getNumberOfCPUs(); CV_Assert(iDepth == CV_8U || iDepth == CV_8S); + //Run parallel labeling only if the rows of the image are at least twice the number returned by getNumberOfCPUs + const bool is_parallel = currentParallelFramework != NULL && numberOfCPUs > 1 && L.rows / numberOfCPUs >= 2; + if (ccltype == CCL_WU || connectivity == 4){ // Wu algorithm is used using connectedcomponents::LabelingWu; using connectedcomponents::LabelingWuParallel; //warn if L's depth is not sufficient? if (lDepth == CV_8U){ - if (currentParallelFramework == NULL) - return (int)LabelingWu()(I, L, connectivity, sop); - else - return (int)LabelingWuParallel()(I, L, connectivity, sop); + //Not supported yet } else if (lDepth == CV_16U){ - if (currentParallelFramework == NULL) - return (int)LabelingWu()(I, L, connectivity, sop); - else - return (int)LabelingWuParallel()(I, L, connectivity, sop); + return (int)LabelingWu()(I, L, connectivity, sop); } else if (lDepth == CV_32S){ //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects //OpenCV: how should we proceed? .at typechecks in debug mode - if (currentParallelFramework == NULL) + if (!is_parallel) return (int)LabelingWu()(I, L, connectivity, sop); else return (int)LabelingWuParallel()(I, L, connectivity, sop); @@ -3967,21 +3964,15 @@ namespace cv{ using connectedcomponents::LabelingGranaParallel; //warn if L's depth is not sufficient? if (lDepth == CV_8U){ - if (currentParallelFramework == NULL) - return (int)LabelingGrana()(I, L, connectivity, sop); - else - return (int)LabelingGranaParallel()(I, L, connectivity, sop); + //Not supported yet } else if (lDepth == CV_16U){ - if (currentParallelFramework == NULL) - return (int)LabelingGrana()(I, L, connectivity, sop); - else - return (int)LabelingGranaParallel()(I, L, connectivity, sop); + return (int)LabelingGrana()(I, L, connectivity, sop); } else if (lDepth == CV_32S){ //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects //OpenCV: how should we proceed? .at typechecks in debug mode - if (currentParallelFramework == NULL) + if (!is_parallel) return (int)LabelingGrana()(I, L, connectivity, sop); else return (int)LabelingGranaParallel()(I, L, connectivity, sop); From 9405c6d2061edc4f8ee1c762a672bbf719c9978a Mon Sep 17 00:00:00 2001 From: Michele Cancilla Date: Thu, 27 Apr 2017 12:53:33 +0200 Subject: [PATCH 5/6] =?UTF-8?q?Improvement=20of=20array=20of=20equivalence?= =?UTF-8?q?s=E2=80=99=20upper=20bound=20+=20fix=20some=20wrong=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/imgproc/src/connectedcomponents.cpp | 22 +++++++++++-------- .../include/opencv2/video/background_segm.hpp | 4 ++-- modules/video/src/bgfg_KNN.cpp | 2 +- modules/video/src/bgfg_gaussmix2.cpp | 6 ++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index d80cbaaf15..f03e568823 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -288,7 +288,7 @@ namespace cv{ int r = range.start; chunksSizeAndLabels_[r] = range.end; - LabelT label = LabelT((r * imgLabels_.cols + 1) / 2 + 1); + LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1; const LabelT firstLabel = label; const int w = img_.cols; @@ -615,6 +615,10 @@ namespace cv{ //merge labels of different chunks mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels); + + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, int((i + 1) / 2) * int((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels); + } } else{ //First scan, each thread works with chunk of img.rows/nThreads rows @@ -623,10 +627,10 @@ namespace cv{ //merge labels of different chunks mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); - } - - for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, (i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels); + + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ + flattenL(P, int(i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels); + } } //Array for statistics dataof threads @@ -842,7 +846,7 @@ namespace cv{ chunksSizeAndLabels_[r] = range.end + (range.end % 2); - LabelT label = LabelT((r + 1) * (imgLabels_.cols + 1) / 4); + LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1; const LabelT firstLabel = label; const int h = img_.rows, w = img_.cols; @@ -2540,7 +2544,7 @@ namespace cv{ //0 0 0 0 0... //1 0 1 0 1... //............ - const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1; //Array used to store info and labeled pixel by each thread. //Different threads affect different memory location of chunksSizeAndLabels @@ -2562,7 +2566,7 @@ namespace cv{ LabelT nLabels = 1; for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ - flattenL(P, (i + 1) * (w + 1) / 4, chunksSizeAndLabels[i + 1], nLabels); + flattenL(P, LabelT((i + 1) / 2) * LabelT((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels); } //Array for statistics data @@ -2602,7 +2606,7 @@ namespace cv{ //0 0 0 0 0... //1 0 1 0 1... //............ - const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1; + const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1; LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength); P[0] = 0; diff --git a/modules/video/include/opencv2/video/background_segm.hpp b/modules/video/include/opencv2/video/background_segm.hpp index f4c6e4cf0d..8a2d40b1a7 100644 --- a/modules/video/include/opencv2/video/background_segm.hpp +++ b/modules/video/include/opencv2/video/background_segm.hpp @@ -188,7 +188,7 @@ public: A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel - is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiarra, + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, *Detecting Moving Shadows...*, IEEE PAMI,2003. */ CV_WRAP virtual double getShadowThreshold() const = 0; @@ -289,7 +289,7 @@ public: A shadow is detected if pixel is a darker version of the background. The shadow threshold (Tau in the paper) is a threshold defining how much darker the shadow can be. Tau= 0.5 means that if a pixel - is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiarra, + is more than twice darker then it is not shadow. See Prati, Mikic, Trivedi and Cucchiara, *Detecting Moving Shadows...*, IEEE PAMI,2003. */ CV_WRAP virtual double getShadowThreshold() const = 0; diff --git a/modules/video/src/bgfg_KNN.cpp b/modules/video/src/bgfg_KNN.cpp index 66be34a00f..434f51f94b 100755 --- a/modules/video/src/bgfg_KNN.cpp +++ b/modules/video/src/bgfg_KNN.cpp @@ -235,7 +235,7 @@ protected: // Tau - shadow threshold. The shadow is detected if the pixel is darker //version of the background. Tau is a threshold on how much darker the shadow can be. //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow - //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003. + //See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003. //model data int nLongCounter;//circular counter diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp index ebe449825c..7a1786cd35 100644 --- a/modules/video/src/bgfg_gaussmix2.cpp +++ b/modules/video/src/bgfg_gaussmix2.cpp @@ -386,7 +386,7 @@ protected: // Tau - shadow threshold. The shadow is detected if the pixel is darker //version of the background. Tau is a threshold on how much darker the shadow can be. //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow - //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003. + //See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003. String name_; @@ -461,7 +461,7 @@ struct GaussBGStatModel2Params // Tau - shadow threshold. The shadow is detected if the pixel is darker //version of the background. Tau is a threshold on how much darker the shadow can be. //Tau= 0.5 means that if pixel is more than 2 times darker then it is not shadow - //See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003. + //See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003. }; struct GMM @@ -472,7 +472,7 @@ struct GMM // shadow detection performed per pixel // should work for rgb data, could be usefull for gray scale and depth data as well -// See: Prati,Mikic,Trivedi,Cucchiarra,"Detecting Moving Shadows...",IEEE PAMI,2003. +// See: Prati,Mikic,Trivedi,Cucchiara,"Detecting Moving Shadows...",IEEE PAMI,2003. CV_INLINE bool detectShadowGMM(const float* data, int nchannels, int nmodes, const GMM* gmm, const float* mean, From 6473018d6936a5c307a1cd101485c049336e388a Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 24 May 2017 16:54:12 +0300 Subject: [PATCH 6/6] eliminated trailing whitespaces --- modules/imgproc/src/connectedcomponents.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp index f03e568823..1887f3be13 100644 --- a/modules/imgproc/src/connectedcomponents.cpp +++ b/modules/imgproc/src/connectedcomponents.cpp @@ -627,7 +627,7 @@ namespace cv{ //merge labels of different chunks mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels); - + for (int i = 0; i < h; i = chunksSizeAndLabels[i]){ flattenL(P, int(i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels); }