Path: blob/master/modules/imgproc/src/connectedcomponents.cpp
16354 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39// 2011 Jason Newton <[email protected]>40// 2016 Costantino Grama <[email protected]>41// 2016 Federico Bolelli <[email protected]>42// 2016 Lorenzo Baraldi <[email protected]>43// 2016 Roberto Vezzani <[email protected]>44// 2016 Michele Cancilla <[email protected]>45//M*/46//47#include "precomp.hpp"48#include <vector>4950namespace cv{51namespace connectedcomponents{5253struct NoOp{54NoOp(){55}5657inline58void init(int /*labels*/){59}6061inline62void initElement(const int /*nlabels*/){63}6465inline66void operator()(int r, int c, int l){67CV_UNUSED(r);68CV_UNUSED(c);69CV_UNUSED(l);70}7172void finish(){73}7475inline76void setNextLoc(const int /*nextLoc*/){77}7879inline static80void mergeStats(const cv::Mat& /*imgLabels*/, NoOp * /*sopArray*/, NoOp& /*sop*/, const int& /*nLabels*/){81}8283};84struct Point2ui64{85uint64 x, y;86Point2ui64(uint64 _x, uint64 _y) :x(_x), y(_y){}87};8889struct CCStatsOp{90const _OutputArray *_mstatsv;91cv::Mat statsv;92const _OutputArray *_mcentroidsv;93cv::Mat centroidsv;94std::vector<Point2ui64> integrals;95int _nextLoc;9697CCStatsOp() : _mstatsv(0), _mcentroidsv(0), _nextLoc(0) {}98CCStatsOp(OutputArray _statsv, OutputArray _centroidsv) : _mstatsv(&_statsv), _mcentroidsv(&_centroidsv), _nextLoc(0){}99100inline101void init(int nlabels){102_mstatsv->create(cv::Size(CC_STAT_MAX, nlabels), cv::DataType<int>::type);103statsv = _mstatsv->getMat();104_mcentroidsv->create(cv::Size(2, nlabels), cv::DataType<double>::type);105centroidsv = _mcentroidsv->getMat();106107for (int l = 0; l < (int)nlabels; ++l){108int *row = (int *)&statsv.at<int>(l, 0);109row[CC_STAT_LEFT] = INT_MAX;110row[CC_STAT_TOP] = INT_MAX;111row[CC_STAT_WIDTH] = INT_MIN;112row[CC_STAT_HEIGHT] = INT_MIN;113row[CC_STAT_AREA] = 0;114}115integrals.resize(nlabels, Point2ui64(0, 0));116}117118inline119void initElement(const int nlabels){120statsv = cv::Mat(nlabels, CC_STAT_MAX, cv::DataType<int>::type);121for (int l = 0; l < (int)nlabels; ++l){122int *row = (int *)statsv.ptr(l);123row[CC_STAT_LEFT] = INT_MAX;124row[CC_STAT_TOP] = INT_MAX;125row[CC_STAT_WIDTH] = INT_MIN;126row[CC_STAT_HEIGHT] = INT_MIN;127row[CC_STAT_AREA] = 0;128}129integrals.resize(nlabels, Point2ui64(0, 0));130}131132void operator()(int r, int c, int l){133int *row =& statsv.at<int>(l, 0);134row[CC_STAT_LEFT] = MIN(row[CC_STAT_LEFT], c);135row[CC_STAT_WIDTH] = MAX(row[CC_STAT_WIDTH], c);136row[CC_STAT_TOP] = MIN(row[CC_STAT_TOP], r);137row[CC_STAT_HEIGHT] = MAX(row[CC_STAT_HEIGHT], r);138row[CC_STAT_AREA]++;139Point2ui64& integral = integrals[l];140integral.x += c;141integral.y += r;142}143144void finish(){145for (int l = 0; l < statsv.rows; ++l){146int *row =& statsv.at<int>(l, 0);147row[CC_STAT_WIDTH] = row[CC_STAT_WIDTH] - row[CC_STAT_LEFT] + 1;148row[CC_STAT_HEIGHT] = row[CC_STAT_HEIGHT] - row[CC_STAT_TOP] + 1;149150Point2ui64& integral = integrals[l];151double *centroid = ¢roidsv.at<double>(l, 0);152double area = ((unsigned*)row)[CC_STAT_AREA];153centroid[0] = double(integral.x) / area;154centroid[1] = double(integral.y) / area;155}156}157158inline159void setNextLoc(const int nextLoc){160_nextLoc = nextLoc;161}162163inline static164void mergeStats(const cv::Mat& imgLabels, CCStatsOp *sopArray, CCStatsOp& sop, const int& nLabels){165const int h = imgLabels.rows;166167if (sop._nextLoc != h){168for (int nextLoc = sop._nextLoc; nextLoc < h; nextLoc = sopArray[nextLoc]._nextLoc){169//merge between sopNext and sop170for (int l = 0; l < nLabels; ++l){171int *rowNext = (int*)sopArray[nextLoc].statsv.ptr(l);172if (rowNext[CC_STAT_AREA] > 0){ //if changed merge all the stats173int *rowMerged = (int*)sop.statsv.ptr(l);174rowMerged[CC_STAT_LEFT] = MIN(rowMerged[CC_STAT_LEFT], rowNext[CC_STAT_LEFT]);175rowMerged[CC_STAT_WIDTH] = MAX(rowMerged[CC_STAT_WIDTH], rowNext[CC_STAT_WIDTH]);176rowMerged[CC_STAT_TOP] = MIN(rowMerged[CC_STAT_TOP], rowNext[CC_STAT_TOP]);177rowMerged[CC_STAT_HEIGHT] = MAX(rowMerged[CC_STAT_HEIGHT], rowNext[CC_STAT_HEIGHT]);178rowMerged[CC_STAT_AREA] += rowNext[CC_STAT_AREA];179180sop.integrals[l].x += sopArray[nextLoc].integrals[l].x;181sop.integrals[l].y += sopArray[nextLoc].integrals[l].y;182}183}184}185}186}187};188189//Find the root of the tree of node i190template<typename LabelT>191inline static192LabelT findRoot(const LabelT *P, LabelT i){193LabelT root = i;194while (P[root] < root){195root = P[root];196}197return root;198}199200//Make all nodes in the path of node i point to root201template<typename LabelT>202inline static203void setRoot(LabelT *P, LabelT i, LabelT root){204while (P[i] < i){205LabelT j = P[i];206P[i] = root;207i = j;208}209P[i] = root;210}211212//Find the root of the tree of the node i and compress the path in the process213template<typename LabelT>214inline static215LabelT find(LabelT *P, LabelT i){216LabelT root = findRoot(P, i);217setRoot(P, i, root);218return root;219}220221//unite the two trees containing nodes i and j and return the new root222template<typename LabelT>223inline static224LabelT set_union(LabelT *P, LabelT i, LabelT j){225LabelT root = findRoot(P, i);226if (i != j){227LabelT rootj = findRoot(P, j);228if (root > rootj){229root = rootj;230}231setRoot(P, j, root);232}233setRoot(P, i, root);234return root;235}236237//Flatten the Union Find tree and relabel the components238template<typename LabelT>239inline static240LabelT flattenL(LabelT *P, LabelT length){241LabelT k = 1;242for (LabelT i = 1; i < length; ++i){243if (P[i] < i){244P[i] = P[P[i]];245}246else{247P[i] = k; k = k + 1;248}249}250return k;251}252253template<typename LabelT>254inline static255void flattenL(LabelT *P, const int start, const int nElem, LabelT& k){256for (int i = start; i < start + nElem; ++i){257if (P[i] < i){//node that point to root258P[i] = P[P[i]];259}260else{ //for root node261P[i] = k;262k = k + 1;263}264}265}266267//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant268//using decision trees269//Kesheng Wu, et al270template<typename LabelT, typename PixelT, typename StatsOp = NoOp >271struct LabelingWuParallel{272273class FirstScan8Connectivity : public cv::ParallelLoopBody{274const cv::Mat& img_;275cv::Mat& imgLabels_;276LabelT *P_;277int *chunksSizeAndLabels_;278279public:280FirstScan8Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)281: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}282283FirstScan8Connectivity& operator=(const FirstScan8Connectivity& ) { return *this; }284285void operator()(const cv::Range& range) const CV_OVERRIDE286{287int r = range.start;288chunksSizeAndLabels_[r] = range.end;289290LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1;291292const LabelT firstLabel = label;293const int w = img_.cols;294const int limitLine = r, startR = r;295296// Rosenfeld Mask297// +-+-+-+298// |p|q|r|299// +-+-+-+300// |s|x|301// +-+-+302for (; r != range.end; ++r)303{304PixelT const * const img_row = img_.ptr<PixelT>(r);305PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);306LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);307LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);308for (int c = 0; c < w; ++c) {309310#define condition_p c > 0 && r > limitLine && img_row_prev[c - 1] > 0311#define condition_q r > limitLine && img_row_prev[c] > 0312#define condition_r c < w - 1 && r > limitLine && img_row_prev[c + 1] > 0313#define condition_s c > 0 && img_row[c - 1] > 0314#define condition_x img_row[c] > 0315316if (condition_x){317if (condition_q){318//copy q319imgLabels_row[c] = imgLabels_row_prev[c];320}321else{322//not q323if (condition_r){324if (condition_p){325//concavity p->x->r. Merge326imgLabels_row[c] = set_union(P_, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]);327}328else{ //not p and q329if (condition_s){330//step s->x->r. Merge331imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]);332}333else{ //not p, q and s334//copy r335imgLabels_row[c] = imgLabels_row_prev[c + 1];336}337}338}339else{340//not r and q341if (condition_p){342//copy p343imgLabels_row[c] = imgLabels_row_prev[c - 1];344}345else{//not r,q and p346if (condition_s){347imgLabels_row[c] = imgLabels_row[c - 1];348}349else{350//new label351imgLabels_row[c] = label;352P_[label] = label;353label = label + 1;354}355}356}357}358}359else{360//x is a background pixel361imgLabels_row[c] = 0;362}363}364}365//write in the follower memory location366chunksSizeAndLabels_[startR + 1] = label - firstLabel;367}368#undef condition_p369#undef condition_q370#undef condition_r371#undef condition_s372#undef condition_x373};374375class FirstScan4Connectivity : public cv::ParallelLoopBody{376const cv::Mat& img_;377cv::Mat& imgLabels_;378LabelT *P_;379int *chunksSizeAndLabels_;380381public:382FirstScan4Connectivity(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)383: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}384385FirstScan4Connectivity& operator=(const FirstScan4Connectivity& ) { return *this; }386387void operator()(const cv::Range& range) const CV_OVERRIDE388{389int r = range.start;390chunksSizeAndLabels_[r] = range.end;391392LabelT label = LabelT((r * imgLabels_.cols + 1) / 2 + 1);393394const LabelT firstLabel = label;395const int w = img_.cols;396const int limitLine = r, startR = r;397398// Rosenfeld Mask399// +-+-+-+400// |-|q|-|401// +-+-+-+402// |s|x|403// +-+-+404for (; r != range.end; ++r){405PixelT const * const img_row = img_.ptr<PixelT>(r);406PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);407LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);408LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0]);409for (int c = 0; c < w; ++c) {410411#define condition_q r > limitLine && img_row_prev[c] > 0412#define condition_s c > 0 && img_row[c - 1] > 0413#define condition_x img_row[c] > 0414415if (condition_x){416if (condition_q){417if (condition_s){418//step s->x->q. Merge419imgLabels_row[c] = set_union(P_, imgLabels_row[c - 1], imgLabels_row_prev[c]);420}421else{422//copy q423imgLabels_row[c] = imgLabels_row_prev[c];424}425}426else{427if (condition_s){ // copy s428imgLabels_row[c] = imgLabels_row[c - 1];429}430else{431//new label432imgLabels_row[c] = label;433P_[label] = label;434label = label + 1;435}436}437}438else{439//x is a background pixel440imgLabels_row[c] = 0;441}442}443}444//write in the following memory location445chunksSizeAndLabels_[startR + 1] = label - firstLabel;446}447#undef condition_q448#undef condition_s449#undef condition_x450};451452class SecondScan : public cv::ParallelLoopBody{453cv::Mat& imgLabels_;454const LabelT *P_;455StatsOp& sop_;456StatsOp *sopArray_;457LabelT& nLabels_;458public:459SecondScan(cv::Mat& imgLabels, const LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels)460: imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){}461462SecondScan& operator=(const SecondScan& ) { return *this; }463464void operator()(const cv::Range& range) const CV_OVERRIDE465{466int r = range.start;467const int rowBegin = r;468const int rowEnd = range.end;469470if (rowBegin > 0){471sopArray_[rowBegin].initElement(nLabels_);472sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd;473474for (; r < rowEnd; ++r) {475LabelT * img_row_start = imgLabels_.ptr<LabelT>(r);476LabelT * const img_row_end = img_row_start + imgLabels_.cols;477for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){478*img_row_start = P_[*img_row_start];479sopArray_[rowBegin](r, c, *img_row_start);480}481}482}483else{484//the first thread uses sop in order to make less merges485sop_.setNextLoc(rowEnd);486for (; r < rowEnd; ++r) {487LabelT * img_row_start = imgLabels_.ptr<LabelT>(r);488LabelT * const img_row_end = img_row_start + imgLabels_.cols;489for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){490*img_row_start = P_[*img_row_start];491sop_(r, c, *img_row_start);492}493}494}495}496};497498inline static499void mergeLabels8Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){500501// Merge Mask502// +-+-+-+503// |p|q|r|504// +-+-+-+505// |x|506// +-+507const int w = imgLabels.cols, h = imgLabels.rows;508509for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){510511LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);512LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);513514for (int c = 0; c < w; ++c){515516#define condition_p c > 0 && imgLabels_row_prev[c - 1] > 0517#define condition_q imgLabels_row_prev[c] > 0518#define condition_r c < w - 1 && imgLabels_row_prev[c + 1] > 0519#define condition_x imgLabels_row[c] > 0520521if (condition_x){522if (condition_p){523//merge of two label524imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row[c]);525}526if (condition_r){527//merge of two label528imgLabels_row[c] = set_union(P, imgLabels_row_prev[c + 1], imgLabels_row[c]);529}530if (condition_q){531//merge of two label532imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]);533}534}535}536}537#undef condition_p538#undef condition_q539#undef condition_r540#undef condition_x541}542543inline static544void mergeLabels4Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){545546// Merge Mask547// +-+-+-+548// |-|q|-|549// +-+-+-+550// |x|551// +-+552const int w = imgLabels.cols, h = imgLabels.rows;553554for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){555556LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);557LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);558559for (int c = 0; c < w; ++c){560561#define condition_q imgLabels_row_prev[c] > 0562#define condition_x imgLabels_row[c] > 0563564if (condition_x){565if (condition_q){566//merge of two label567imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]);568}569}570}571}572#undef condition_q573#undef condition_x574}575576LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){577CV_Assert(img.rows == imgLabels.rows);578CV_Assert(img.cols == imgLabels.cols);579CV_Assert(connectivity == 8 || connectivity == 4);580581const int h = img.rows;582const int w = img.cols;583584//A quick and dirty upper bound for the maximum number of labels.585//Following formula comes from the fact that a 2x2 block in 4-way connectivity586//labeling can never have more than 2 new labels and 1 label for background.587//Worst case image example pattern:588//1 0 1 0 1...589//0 1 0 1 0...590//1 0 1 0 1...591//............592//Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling593const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;594595//Array used to store info and labeled pixel by each thread.596//Different threads affect different memory location of chunksSizeAndLabels597int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));598599//Tree of labels600LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));601//First label is for background602P[0] = 0;603604cv::Range range(0, h);605const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4));606607LabelT nLabels = 1;608609if (connectivity == 8){610//First scan611cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);612613//merge labels of different chunks614mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels);615616for (int i = 0; i < h; i = chunksSizeAndLabels[i]){617flattenL(P, int((i + 1) / 2) * int((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels);618}619}620else{621//First scan622cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);623624//merge labels of different chunks625mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels);626627for (int i = 0; i < h; i = chunksSizeAndLabels[i]){628flattenL(P, int(i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels);629}630}631632//Array for statistics dataof threads633StatsOp *sopArray = new StatsOp[h];634635sop.init(nLabels);636//Second scan637cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nParallelStripes);638StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);639sop.finish();640641delete[] sopArray;642cv::fastFree(chunksSizeAndLabels);643cv::fastFree(P);644return nLabels;645}646};//End struct LabelingWuParallel647648649//Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant650//using decision trees651//Kesheng Wu, et al652template<typename LabelT, typename PixelT, typename StatsOp = NoOp >653struct LabelingWu{654LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){655CV_Assert(imgLabels.rows == img.rows);656CV_Assert(imgLabels.cols == img.cols);657CV_Assert(connectivity == 8 || connectivity == 4);658659const int h = img.rows;660const int w = img.cols;661662//A quick and dirty upper bound for the maximum number of labels.663//Following formula comes from the fact that a 2x2 block in 4-way connectivity664//labeling can never have more than 2 new labels and 1 label for background.665//Worst case image example pattern:666//1 0 1 0 1...667//0 1 0 1 0...668//1 0 1 0 1...669//............670//Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling671const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;672//array P for equivalences resolution673LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);674//first label is for background pixels675P[0] = 0;676LabelT lunique = 1;677678if (connectivity == 8){679for (int r = 0; r < h; ++r){680// Get row pointers681PixelT const * const img_row = img.ptr<PixelT>(r);682PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);683LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);684LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);685686for (int c = 0; c < w; ++c){687688#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0689#define condition_q r>0 && img_row_prev[c]>0690#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0691#define condition_s c > 0 && img_row[c - 1] > 0692#define condition_x img_row[c] > 0693694if (condition_x){695if (condition_q){696//x <- q697imgLabels_row[c] = imgLabels_row_prev[c];698}699else{700// q = 0701if (condition_r){702if (condition_p){703// x <- merge(p,r)704imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]);705}706else{707// p = q = 0708if (condition_s){709// x <- merge(s,r)710imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]);711}712else{713// p = q = s = 0714// x <- r715imgLabels_row[c] = imgLabels_row_prev[c + 1];716}717}718}719else{720// r = q = 0721if (condition_p){722// x <- p723imgLabels_row[c] = imgLabels_row_prev[c - 1];724}725else{726// r = q = p = 0727if (condition_s){728imgLabels_row[c] = imgLabels_row[c - 1];729}730else{731//new label732imgLabels_row[c] = lunique;733P[lunique] = lunique;734lunique = lunique + 1;735}736}737}738}739}740else{741//x is a background pixel742imgLabels_row[c] = 0;743}744}745}746#undef condition_p747#undef condition_q748#undef condition_r749#undef condition_s750#undef condition_x751}752else{753for (int r = 0; r < h; ++r){754PixelT const * const img_row = img.ptr<PixelT>(r);755PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);756LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);757LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);758for (int c = 0; c < w; ++c) {759760#define condition_q r > 0 && img_row_prev[c] > 0761#define condition_s c > 0 && img_row[c - 1] > 0762#define condition_x img_row[c] > 0763764if (condition_x){765if (condition_q){766if (condition_s){767//Merge s->x->q768imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]);769}770else{771//copy q772imgLabels_row[c] = imgLabels_row_prev[c];773}774}775else{776if (condition_s){777// copy s778imgLabels_row[c] = imgLabels_row[c - 1];779}780else{781//new label782imgLabels_row[c] = lunique;783P[lunique] = lunique;784lunique = lunique + 1;785}786}787}788else{789//x is a background pixel790imgLabels_row[c] = 0;791}792}793}794#undef condition_q795#undef condition_s796#undef condition_x797}798799//analysis800LabelT nLabels = flattenL(P, lunique);801sop.init(nLabels);802803for (int r = 0; r < h; ++r) {804LabelT * img_row_start = imgLabels.ptr<LabelT>(r);805LabelT * const img_row_end = img_row_start + w;806for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){807*img_row_start = P[*img_row_start];808sop(r, c, *img_row_start);809}810}811812sop.finish();813fastFree(P);814815return nLabels;816}//End function LabelingWu operator()817};//End struct LabelingWu818819820// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al821// Only for 8-connectivity822template<typename LabelT, typename PixelT, typename StatsOp = NoOp >823struct LabelingGranaParallel{824825class FirstScan : public cv::ParallelLoopBody{826private:827const cv::Mat& img_;828cv::Mat& imgLabels_;829LabelT *P_;830int *chunksSizeAndLabels_;831832public:833FirstScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)834: img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}835836FirstScan& operator=(const FirstScan&) { return *this; }837838void operator()(const cv::Range& range) const CV_OVERRIDE839{840int r = range.start;841r += (r % 2);842843chunksSizeAndLabels_[r] = range.end + (range.end % 2);844845LabelT label = LabelT((r + 1) / 2) * LabelT((imgLabels_.cols + 1) / 2) + 1;846847const LabelT firstLabel = label;848const int h = img_.rows, w = img_.cols;849const int limitLine = r + 1, startR = r;850851for (; r < range.end; r += 2){852// Get rows pointer853const PixelT * const img_row = img_.ptr<uchar>(r);854const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);855const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img_.step.p[0]);856const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);857LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);858LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0] - imgLabels_.step.p[0]);859for (int c = 0; c < w; c += 2) {860861// We work with 2x2 blocks862// +-+-+-+863// |P|Q|R|864// +-+-+-+865// |S|X|866// +-+-+867868// The pixels are named as follows869// +---+---+---+870// |a b|c d|e f|871// |g h|i j|k l|872// +---+---+---+873// |m n|o p|874// |q r|s t|875// +---+---+876877// Pixels a, f, l, q are not needed, since we need to understand the878// the connectivity between these blocks and those pixels only metter879// when considering the outer connectivities880881// A bunch of defines used to check if the pixels are foreground,882// without going outside the image limits.883884#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0885#define condition_c r > limitLine && img_row_prev_prev[c]>0886#define condition_d c+1<w && r > limitLine && img_row_prev_prev[c+1]>0887#define condition_e c+2<w && r > limitLine && img_row_prev_prev[c+2]>0888889#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0890#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0891#define condition_i r > limitLine - 1 && img_row_prev[c]>0892#define condition_j c+1<w && r > limitLine - 1 && img_row_prev[c+1]>0893#define condition_k c+2<w && r > limitLine - 1 && img_row_prev[c+2]>0894895#define condition_m c-2>=0 && img_row[c-2]>0896#define condition_n c-1>=0 && img_row[c-1]>0897#define condition_o img_row[c]>0898#define condition_p c+1<w && img_row[c+1]>0899900#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0901#define condition_s r+1<h && img_row_fol[c]>0902#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0903904// This is a decision tree which allows to choose which action to905// perform, checking as few conditions as possible.906// Actions are available after the tree.907908if (condition_o) {909if (condition_n) {910if (condition_j) {911if (condition_i) {912//Action_6: Assign label of block S913imgLabels_row[c] = imgLabels_row[c - 2];914continue;915}916else {917if (condition_c) {918if (condition_h) {919//Action_6: Assign label of block S920imgLabels_row[c] = imgLabels_row[c - 2];921continue;922}923else {924if (condition_g) {925if (condition_b) {926//Action_6: Assign label of block S927imgLabels_row[c] = imgLabels_row[c - 2];928continue;929}930else {931//Action_11: Merge labels of block Q and S932imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);933continue;934}935}936else {937//Action_11: Merge labels of block Q and S938imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);939continue;940}941}942}943else {944//Action_11: Merge labels of block Q and S945imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);946continue;947}948}949}950else {951if (condition_p) {952if (condition_k) {953if (condition_d) {954if (condition_i) {955//Action_6: Assign label of block S956imgLabels_row[c] = imgLabels_row[c - 2];957continue;958}959else {960if (condition_c) {961if (condition_h) {962//Action_6: Assign label of block S963imgLabels_row[c] = imgLabels_row[c - 2];964continue;965}966else {967if (condition_g) {968if (condition_b) {969//Action_6: Assign label of block S970imgLabels_row[c] = imgLabels_row[c - 2];971continue;972}973else {974//Action_12: Merge labels of block R and S975imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);976continue;977}978}979else {980//Action_12: Merge labels of block R and S981imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);982continue;983}984}985}986else {987//Action_12: Merge labels of block R and S988imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);989continue;990}991}992}993else {994//Action_12: Merge labels of block R and S995imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);996continue;997}998}999else {1000//Action_6: Assign label of block S1001imgLabels_row[c] = imgLabels_row[c - 2];1002continue;1003}1004}1005else {1006//Action_6: Assign label of block S1007imgLabels_row[c] = imgLabels_row[c - 2];1008continue;1009}1010}1011}1012else {1013if (condition_r) {1014if (condition_j) {1015if (condition_m) {1016if (condition_h) {1017if (condition_i) {1018//Action_6: Assign label of block S1019imgLabels_row[c] = imgLabels_row[c - 2];1020continue;1021}1022else {1023if (condition_c) {1024//Action_6: Assign label of block S1025imgLabels_row[c] = imgLabels_row[c - 2];1026continue;1027}1028else {1029//Action_11: Merge labels of block Q and S1030imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1031continue;1032}1033}1034}1035else {1036if (condition_g) {1037if (condition_b) {1038if (condition_i) {1039//Action_6: Assign label of block S1040imgLabels_row[c] = imgLabels_row[c - 2];1041continue;1042}1043else {1044if (condition_c) {1045//Action_6: Assign label of block S1046imgLabels_row[c] = imgLabels_row[c - 2];1047continue;1048}1049else {1050//Action_11: Merge labels of block Q and S1051imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1052continue;1053}1054}1055}1056else {1057//Action_11: Merge labels of block Q and S1058imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1059continue;1060}1061}1062else {1063//Action_11: Merge labels of block Q and S1064imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1065continue;1066}1067}1068}1069else {1070if (condition_i) {1071//Action_11: Merge labels of block Q and S1072imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1073continue;1074}1075else {1076if (condition_h) {1077if (condition_c) {1078//Action_11: Merge labels of block Q and S1079imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1080continue;1081}1082else {1083//Action_14: Merge labels of block P_, Q and S1084imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);1085continue;1086}1087}1088else {1089//Action_11: Merge labels of block Q and S1090imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1091continue;1092}1093}1094}1095}1096else {1097if (condition_p) {1098if (condition_k) {1099if (condition_m) {1100if (condition_h) {1101if (condition_d) {1102if (condition_i) {1103//Action_6: Assign label of block S1104imgLabels_row[c] = imgLabels_row[c - 2];1105continue;1106}1107else {1108if (condition_c) {1109//Action_6: Assign label of block S1110imgLabels_row[c] = imgLabels_row[c - 2];1111continue;1112}1113else {1114//Action_12: Merge labels of block R and S1115imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1116continue;1117}1118}1119}1120else {1121//Action_12: Merge labels of block R and S1122imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1123continue;1124}1125}1126else {1127if (condition_d) {1128if (condition_g) {1129if (condition_b) {1130if (condition_i) {1131//Action_6: Assign label of block S1132imgLabels_row[c] = imgLabels_row[c - 2];1133continue;1134}1135else {1136if (condition_c) {1137//Action_6: Assign label of block S1138imgLabels_row[c] = imgLabels_row[c - 2];1139continue;1140}1141else {1142//Action_12: Merge labels of block R and S1143imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1144continue;1145}1146}1147}1148else {1149//Action_12: Merge labels of block R and S1150imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1151continue;1152}1153}1154else {1155//Action_12: Merge labels of block R and S1156imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1157continue;1158}1159}1160else {1161if (condition_i) {1162if (condition_g) {1163if (condition_b) {1164//Action_12: Merge labels of block R and S1165imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1166continue;1167}1168else {1169//Action_16: labels of block Q, R and S1170imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1171continue;1172}1173}1174else {1175//Action_16: labels of block Q, R and S1176imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1177continue;1178}1179}1180else {1181//Action_12: Merge labels of block R and S1182imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1183continue;1184}1185}1186}1187}1188else {1189if (condition_i) {1190if (condition_d) {1191//Action_12: Merge labels of block R and S1192imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1193continue;1194}1195else {1196//Action_16: labels of block Q, R and S1197imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1198continue;1199}1200}1201else {1202if (condition_h) {1203if (condition_d) {1204if (condition_c) {1205//Action_12: Merge labels of block R and S1206imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1207continue;1208}1209else {1210//Action_15: Merge labels of block P_, R and S1211imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1212continue;1213}1214}1215else {1216//Action_15: Merge labels of block P_, R and S1217imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1218continue;1219}1220}1221else {1222//Action_12: Merge labels of block R and S1223imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1224continue;1225}1226}1227}1228}1229else {1230if (condition_h) {1231if (condition_m) {1232//Action_6: Assign label of block S1233imgLabels_row[c] = imgLabels_row[c - 2];1234continue;1235}1236else {1237// ACTION_9 Merge labels of block P_ and S1238imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);1239continue;1240}1241}1242else {1243if (condition_i) {1244if (condition_m) {1245if (condition_g) {1246if (condition_b) {1247//Action_6: Assign label of block S1248imgLabels_row[c] = imgLabels_row[c - 2];1249continue;1250}1251else {1252//Action_11: Merge labels of block Q and S1253imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1254continue;1255}1256}1257else {1258//Action_11: Merge labels of block Q and S1259imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1260continue;1261}1262}1263else {1264//Action_11: Merge labels of block Q and S1265imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1266continue;1267}1268}1269else {1270//Action_6: Assign label of block S1271imgLabels_row[c] = imgLabels_row[c - 2];1272continue;1273}1274}1275}1276}1277else {1278if (condition_h) {1279if (condition_m) {1280//Action_6: Assign label of block S1281imgLabels_row[c] = imgLabels_row[c - 2];1282continue;1283}1284else {1285// ACTION_9 Merge labels of block P_ and S1286imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);1287continue;1288}1289}1290else {1291if (condition_i) {1292if (condition_m) {1293if (condition_g) {1294if (condition_b) {1295//Action_6: Assign label of block S1296imgLabels_row[c] = imgLabels_row[c - 2];1297continue;1298}1299else {1300//Action_11: Merge labels of block Q and S1301imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1302continue;1303}1304}1305else {1306//Action_11: Merge labels of block Q and S1307imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1308continue;1309}1310}1311else {1312//Action_11: Merge labels of block Q and S1313imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1314continue;1315}1316}1317else {1318//Action_6: Assign label of block S1319imgLabels_row[c] = imgLabels_row[c - 2];1320continue;1321}1322}1323}1324}1325}1326else {1327if (condition_j) {1328if (condition_i) {1329//Action_4: Assign label of block Q1330imgLabels_row[c] = imgLabels_row_prev_prev[c];1331continue;1332}1333else {1334if (condition_h) {1335if (condition_c) {1336//Action_4: Assign label of block Q1337imgLabels_row[c] = imgLabels_row_prev_prev[c];1338continue;1339}1340else {1341//Action_7: Merge labels of block P_ and Q1342imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);1343continue;1344}1345}1346else {1347//Action_4: Assign label of block Q1348imgLabels_row[c] = imgLabels_row_prev_prev[c];1349continue;1350}1351}1352}1353else {1354if (condition_p) {1355if (condition_k) {1356if (condition_i) {1357if (condition_d) {1358//Action_5: Assign label of block R1359imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1360continue;1361}1362else {1363// ACTION_10 Merge labels of block Q and R1364imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);1365continue;1366}1367}1368else {1369if (condition_h) {1370if (condition_d) {1371if (condition_c) {1372//Action_5: Assign label of block R1373imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1374continue;1375}1376else {1377//Action_8: Merge labels of block P_ and R1378imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);1379continue;1380}1381}1382else {1383//Action_8: Merge labels of block P_ and R1384imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);1385continue;1386}1387}1388else {1389//Action_5: Assign label of block R1390imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1391continue;1392}1393}1394}1395else {1396if (condition_i) {1397//Action_4: Assign label of block Q1398imgLabels_row[c] = imgLabels_row_prev_prev[c];1399continue;1400}1401else {1402if (condition_h) {1403//Action_3: Assign label of block P_1404imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];1405continue;1406}1407else {1408//Action_2: New label (the block has foreground pixels and is not connected to anything else)1409imgLabels_row[c] = label;1410P_[label] = label;1411label = label + 1;1412continue;1413}1414}1415}1416}1417else {1418if (condition_i) {1419//Action_4: Assign label of block Q1420imgLabels_row[c] = imgLabels_row_prev_prev[c];1421continue;1422}1423else {1424if (condition_h) {1425//Action_3: Assign label of block P_1426imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];1427continue;1428}1429else {1430//Action_2: New label (the block has foreground pixels and is not connected to anything else)1431imgLabels_row[c] = label;1432P_[label] = label;1433label = label + 1;1434continue;1435}1436}1437}1438}1439}1440}1441}1442else {1443if (condition_s) {1444if (condition_p) {1445if (condition_n) {1446if (condition_j) {1447if (condition_i) {1448//Action_6: Assign label of block S1449imgLabels_row[c] = imgLabels_row[c - 2];1450continue;1451}1452else {1453if (condition_c) {1454if (condition_h) {1455//Action_6: Assign label of block S1456imgLabels_row[c] = imgLabels_row[c - 2];1457continue;1458}1459else {1460if (condition_g) {1461if (condition_b) {1462//Action_6: Assign label of block S1463imgLabels_row[c] = imgLabels_row[c - 2];1464continue;1465}1466else {1467//Action_11: Merge labels of block Q and S1468imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1469continue;1470}1471}1472else {1473//Action_11: Merge labels of block Q and S1474imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1475continue;1476}1477}1478}1479else {1480//Action_11: Merge labels of block Q and S1481imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1482continue;1483}1484}1485}1486else {1487if (condition_k) {1488if (condition_d) {1489if (condition_i) {1490//Action_6: Assign label of block S1491imgLabels_row[c] = imgLabels_row[c - 2];1492continue;1493}1494else {1495if (condition_c) {1496if (condition_h) {1497//Action_6: Assign label of block S1498imgLabels_row[c] = imgLabels_row[c - 2];1499continue;1500}1501else {1502if (condition_g) {1503if (condition_b) {1504//Action_6: Assign label of block S1505imgLabels_row[c] = imgLabels_row[c - 2];1506continue;1507}1508else {1509//Action_12: Merge labels of block R and S1510imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1511continue;1512}1513}1514else {1515//Action_12: Merge labels of block R and S1516imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1517continue;1518}1519}1520}1521else {1522//Action_12: Merge labels of block R and S1523imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1524continue;1525}1526}1527}1528else {1529//Action_12: Merge labels of block R and S1530imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1531continue;1532}1533}1534else {1535//Action_6: Assign label of block S1536imgLabels_row[c] = imgLabels_row[c - 2];1537continue;1538}1539}1540}1541else {1542if (condition_r) {1543if (condition_j) {1544if (condition_m) {1545if (condition_h) {1546if (condition_i) {1547//Action_6: Assign label of block S1548imgLabels_row[c] = imgLabels_row[c - 2];1549continue;1550}1551else {1552if (condition_c) {1553//Action_6: Assign label of block S1554imgLabels_row[c] = imgLabels_row[c - 2];1555continue;1556}1557else {1558//Action_11: Merge labels of block Q and S1559imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1560continue;1561}1562}1563}1564else {1565if (condition_g) {1566if (condition_b) {1567if (condition_i) {1568//Action_6: Assign label of block S1569imgLabels_row[c] = imgLabels_row[c - 2];1570continue;1571}1572else {1573if (condition_c) {1574//Action_6: Assign label of block S1575imgLabels_row[c] = imgLabels_row[c - 2];1576continue;1577}1578else {1579//Action_11: Merge labels of block Q and S1580imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1581continue;1582}1583}1584}1585else {1586//Action_11: Merge labels of block Q and S1587imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1588continue;1589}1590}1591else {1592//Action_11: Merge labels of block Q and S1593imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1594continue;1595}1596}1597}1598else {1599//Action_11: Merge labels of block Q and S1600imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1601continue;1602}1603}1604else {1605if (condition_k) {1606if (condition_d) {1607if (condition_m) {1608if (condition_h) {1609if (condition_i) {1610//Action_6: Assign label of block S1611imgLabels_row[c] = imgLabels_row[c - 2];1612continue;1613}1614else {1615if (condition_c) {1616//Action_6: Assign label of block S1617imgLabels_row[c] = imgLabels_row[c - 2];1618continue;1619}1620else {1621//Action_12: Merge labels of block R and S1622imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1623continue;1624}1625}1626}1627else {1628if (condition_g) {1629if (condition_b) {1630if (condition_i) {1631//Action_6: Assign label of block S1632imgLabels_row[c] = imgLabels_row[c - 2];1633continue;1634}1635else {1636if (condition_c) {1637//Action_6: Assign label of block S1638imgLabels_row[c] = imgLabels_row[c - 2];1639continue;1640}1641else {1642//Action_12: Merge labels of block R and S1643imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1644continue;1645}1646}1647}1648else {1649//Action_12: Merge labels of block R and S1650imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1651continue;1652}1653}1654else {1655//Action_12: Merge labels of block R and S1656imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1657continue;1658}1659}1660}1661else {1662//Action_12: Merge labels of block R and S1663imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1664continue;1665}1666}1667else {1668if (condition_i) {1669if (condition_m) {1670if (condition_h) {1671//Action_12: Merge labels of block R and S1672imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1673continue;1674}1675else {1676if (condition_g) {1677if (condition_b) {1678//Action_12: Merge labels of block R and S1679imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1680continue;1681}1682else {1683//Action_16: labels of block Q, R and S1684imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1685continue;1686}1687}1688else {1689//Action_16: labels of block Q, R and S1690imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1691continue;1692}1693}1694}1695else {1696//Action_16: labels of block Q, R and S1697imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);1698continue;1699}1700}1701else {1702//Action_12: Merge labels of block R and S1703imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);1704continue;1705}1706}1707}1708else {1709if (condition_i) {1710if (condition_m) {1711if (condition_h) {1712//Action_6: Assign label of block S1713imgLabels_row[c] = imgLabels_row[c - 2];1714continue;1715}1716else {1717if (condition_g) {1718if (condition_b) {1719//Action_6: Assign label of block S1720imgLabels_row[c] = imgLabels_row[c - 2];1721continue;1722}1723else {1724//Action_11: Merge labels of block Q and S1725imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1726continue;1727}1728}1729else {1730//Action_11: Merge labels of block Q and S1731imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1732continue;1733}1734}1735}1736else {1737//Action_11: Merge labels of block Q and S1738imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);1739continue;1740}1741}1742else {1743//Action_6: Assign label of block S1744imgLabels_row[c] = imgLabels_row[c - 2];1745continue;1746}1747}1748}1749}1750else {1751if (condition_j) {1752//Action_4: Assign label of block Q1753imgLabels_row[c] = imgLabels_row_prev_prev[c];1754continue;1755}1756else {1757if (condition_k) {1758if (condition_i) {1759if (condition_d) {1760//Action_5: Assign label of block R1761imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1762continue;1763}1764else {1765// ACTION_10 Merge labels of block Q and R1766imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);1767continue;1768}1769}1770else {1771//Action_5: Assign label of block R1772imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1773continue;1774}1775}1776else {1777if (condition_i) {1778//Action_4: Assign label of block Q1779imgLabels_row[c] = imgLabels_row_prev_prev[c];1780continue;1781}1782else {1783//Action_2: New label (the block has foreground pixels and is not connected to anything else)1784imgLabels_row[c] = label;1785P_[label] = label;1786label = label + 1;1787continue;1788}1789}1790}1791}1792}1793}1794else {1795if (condition_r) {1796//Action_6: Assign label of block S1797imgLabels_row[c] = imgLabels_row[c - 2];1798continue;1799}1800else {1801if (condition_n) {1802//Action_6: Assign label of block S1803imgLabels_row[c] = imgLabels_row[c - 2];1804continue;1805}1806else {1807//Action_2: New label (the block has foreground pixels and is not connected to anything else)1808imgLabels_row[c] = label;1809P_[label] = label;1810label = label + 1;1811continue;1812}1813}1814}1815}1816else {1817if (condition_p) {1818if (condition_j) {1819//Action_4: Assign label of block Q1820imgLabels_row[c] = imgLabels_row_prev_prev[c];1821continue;1822}1823else {1824if (condition_k) {1825if (condition_i) {1826if (condition_d) {1827//Action_5: Assign label of block R1828imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1829continue;1830}1831else {1832// ACTION_10 Merge labels of block Q and R1833imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);1834continue;1835}1836}1837else {1838//Action_5: Assign label of block R1839imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];1840continue;1841}1842}1843else {1844if (condition_i) {1845//Action_4: Assign label of block Q1846imgLabels_row[c] = imgLabels_row_prev_prev[c];1847continue;1848}1849else {1850//Action_2: New label (the block has foreground pixels and is not connected to anything else)1851imgLabels_row[c] = label;1852P_[label] = label;1853label = label + 1;1854continue;1855}1856}1857}1858}1859else {1860if (condition_t) {1861//Action_2: New label (the block has foreground pixels and is not connected to anything else)1862imgLabels_row[c] = label;1863P_[label] = label;1864label = label + 1;1865continue;1866}1867else {1868// Action_1: No action (the block has no foreground pixels)1869imgLabels_row[c] = 0;1870continue;1871}1872}1873}1874}1875}1876}1877//write in the follower memory location1878chunksSizeAndLabels_[startR + 1] = label - firstLabel;1879}1880#undef condition_k1881#undef condition_j1882#undef condition_i1883#undef condition_h1884#undef condition_g1885#undef condition_e1886#undef condition_d1887#undef condition_c1888#undef condition_b1889};18901891class SecondScan : public cv::ParallelLoopBody{1892private:1893const cv::Mat& img_;1894cv::Mat& imgLabels_;1895LabelT *P_;1896StatsOp& sop_;1897StatsOp *sopArray_;1898LabelT& nLabels_;18991900public:1901SecondScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels)1902: img_(img), imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){}19031904SecondScan& operator=(const SecondScan& ) { return *this; }19051906void operator()(const cv::Range& range) const CV_OVERRIDE1907{1908int r = range.start;1909r += (r % 2);1910const int rowBegin = r;1911const int rowEnd = range.end + range.end % 2;19121913if (rowBegin > 0){1914sopArray_[rowBegin].initElement(nLabels_);1915sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd;19161917if (imgLabels_.rows& 1){1918if (imgLabels_.cols& 1){1919//Case 1: both rows and cols odd1920for (; r < rowEnd; r += 2){1921// Get rows pointer1922const PixelT * const img_row = img_.ptr<PixelT>(r);1923const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);19241925LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);1926LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);1927// Get rows pointer1928for (int c = 0; c < imgLabels_.cols; c += 2) {1929LabelT iLabel = imgLabels_row[c];1930if (iLabel > 0) {1931iLabel = P_[iLabel];1932if (img_row[c] > 0){1933imgLabels_row[c] = iLabel;1934sopArray_[rowBegin](r, c, iLabel);1935}1936else{1937imgLabels_row[c] = 0;1938sopArray_[rowBegin](r, c, 0);1939}1940if (c + 1 < imgLabels_.cols) {1941if (img_row[c + 1] > 0){1942imgLabels_row[c + 1] = iLabel;1943sopArray_[rowBegin](r, c + 1, iLabel);1944}1945else{1946imgLabels_row[c + 1] = 0;1947sopArray_[rowBegin](r, c + 1, 0);1948}1949if (r + 1 < imgLabels_.rows) {1950if (img_row_fol[c] > 0){1951imgLabels_row_fol[c] = iLabel;1952sopArray_[rowBegin](r + 1, c, iLabel);1953}1954else{1955imgLabels_row_fol[c] = 0;1956sopArray_[rowBegin](r + 1, c, 0);1957}1958if (img_row_fol[c + 1] > 0){1959imgLabels_row_fol[c + 1] = iLabel;1960sopArray_[rowBegin](r + 1, c + 1, iLabel);1961}1962else{1963imgLabels_row_fol[c + 1] = 0;1964sopArray_[rowBegin](r + 1, c + 1, 0);1965}1966}1967}1968else if (r + 1 < imgLabels_.rows) {1969if (img_row_fol[c] > 0){1970imgLabels_row_fol[c] = iLabel;1971sopArray_[rowBegin](r + 1, c, iLabel);1972}1973else{1974imgLabels_row_fol[c] = 0;1975sopArray_[rowBegin](r + 1, c, 0);1976}1977}1978}1979else {1980imgLabels_row[c] = 0;1981sopArray_[rowBegin](r, c, 0);1982if (c + 1 < imgLabels_.cols) {1983imgLabels_row[c + 1] = 0;1984sopArray_[rowBegin](r, c + 1, 0);1985if (r + 1 < imgLabels_.rows) {1986imgLabels_row_fol[c] = 0;1987imgLabels_row_fol[c + 1] = 0;1988sopArray_[rowBegin](r + 1, c, 0);1989sopArray_[rowBegin](r + 1, c + 1, 0);1990}1991}1992else if (r + 1 < imgLabels_.rows) {1993imgLabels_row_fol[c] = 0;1994sopArray_[rowBegin](r + 1, c, 0);1995}1996}1997}1998}1999}//END Case 12000else{2001//Case 2: only rows odd2002for (; r < rowEnd; r += 2){2003// Get rows pointer2004const PixelT * const img_row = img_.ptr<PixelT>(r);2005const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2006LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2007LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2008// Get rows pointer2009for (int c = 0; c < imgLabels_.cols; c += 2) {2010LabelT iLabel = imgLabels_row[c];2011if (iLabel > 0) {2012iLabel = P_[iLabel];2013if (img_row[c] > 0){2014imgLabels_row[c] = iLabel;2015sopArray_[rowBegin](r, c, iLabel);2016}2017else{2018imgLabels_row[c] = 0;2019sopArray_[rowBegin](r, c, 0);2020}2021if (img_row[c + 1] > 0){2022imgLabels_row[c + 1] = iLabel;2023sopArray_[rowBegin](r, c + 1, iLabel);2024}2025else{2026imgLabels_row[c + 1] = 0;2027sopArray_[rowBegin](r, c + 1, 0);2028}2029if (r + 1 < imgLabels_.rows) {2030if (img_row_fol[c] > 0){2031imgLabels_row_fol[c] = iLabel;2032sopArray_[rowBegin](r + 1, c, iLabel);2033}2034else{2035imgLabels_row_fol[c] = 0;2036sopArray_[rowBegin](r + 1, c, 0);2037}2038if (img_row_fol[c + 1] > 0){2039imgLabels_row_fol[c + 1] = iLabel;2040sopArray_[rowBegin](r + 1, c + 1, iLabel);2041}2042else{2043imgLabels_row_fol[c + 1] = 0;2044sopArray_[rowBegin](r + 1, c + 1, 0);2045}2046}2047}2048else {2049imgLabels_row[c] = 0;2050imgLabels_row[c + 1] = 0;2051sopArray_[rowBegin](r, c, 0);2052sopArray_[rowBegin](r, c + 1, 0);2053if (r + 1 < imgLabels_.rows) {2054imgLabels_row_fol[c] = 0;2055imgLabels_row_fol[c + 1] = 0;2056sopArray_[rowBegin](r + 1, c, 0);2057sopArray_[rowBegin](r + 1, c + 1, 0);2058}2059}2060}2061}2062}// END Case 22063}2064else{2065if (imgLabels_.cols& 1){2066//Case 3: only cols odd2067for (; r < rowEnd; r += 2){2068// Get rows pointer2069const PixelT * const img_row = img_.ptr<PixelT>(r);2070const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2071LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2072LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2073// Get rows pointer2074for (int c = 0; c < imgLabels_.cols; c += 2) {2075LabelT iLabel = imgLabels_row[c];2076if (iLabel > 0) {2077iLabel = P_[iLabel];2078if (img_row[c] > 0){2079imgLabels_row[c] = iLabel;2080sopArray_[rowBegin](r, c, iLabel);2081}2082else{2083imgLabels_row[c] = 0;2084sopArray_[rowBegin](r, c, 0);2085}2086if (img_row_fol[c] > 0){2087imgLabels_row_fol[c] = iLabel;2088sopArray_[rowBegin](r + 1, c, iLabel);2089}2090else{2091imgLabels_row_fol[c] = 0;2092sopArray_[rowBegin](r + 1, c, 0);2093}2094if (c + 1 < imgLabels_.cols) {2095if (img_row[c + 1] > 0){2096imgLabels_row[c + 1] = iLabel;2097sopArray_[rowBegin](r, c + 1, iLabel);2098}2099else{2100imgLabels_row[c + 1] = 0;2101sopArray_[rowBegin](r, c + 1, 0);2102}2103if (img_row_fol[c + 1] > 0){2104imgLabels_row_fol[c + 1] = iLabel;2105sopArray_[rowBegin](r + 1, c + 1, iLabel);2106}2107else{2108imgLabels_row_fol[c + 1] = 0;2109sopArray_[rowBegin](r + 1, c + 1, 0);2110}2111}2112}2113else{2114imgLabels_row[c] = 0;2115imgLabels_row_fol[c] = 0;2116sopArray_[rowBegin](r, c, 0);2117sopArray_[rowBegin](r + 1, c, 0);2118if (c + 1 < imgLabels_.cols) {2119imgLabels_row[c + 1] = 0;2120imgLabels_row_fol[c + 1] = 0;2121sopArray_[rowBegin](r, c + 1, 0);2122sopArray_[rowBegin](r + 1, c + 1, 0);2123}2124}2125}2126}2127}// END case 32128else{2129//Case 4: nothing odd2130for (; r < rowEnd; r += 2){2131// Get rows pointer2132const PixelT * const img_row = img_.ptr<PixelT>(r);2133const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2134LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2135LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2136// Get rows pointer2137for (int c = 0; c < imgLabels_.cols; c += 2) {2138LabelT iLabel = imgLabels_row[c];2139if (iLabel > 0) {2140iLabel = P_[iLabel];2141if (img_row[c] > 0){2142imgLabels_row[c] = iLabel;2143sopArray_[rowBegin](r, c, iLabel);2144}2145else{2146imgLabels_row[c] = 0;2147sopArray_[rowBegin](r, c, 0);2148}2149if (img_row[c + 1] > 0){2150imgLabels_row[c + 1] = iLabel;2151sopArray_[rowBegin](r, c + 1, iLabel);2152}2153else{2154imgLabels_row[c + 1] = 0;2155sopArray_[rowBegin](r, c + 1, 0);2156}2157if (img_row_fol[c] > 0){2158imgLabels_row_fol[c] = iLabel;2159sopArray_[rowBegin](r + 1, c, iLabel);2160}2161else{2162imgLabels_row_fol[c] = 0;2163sopArray_[rowBegin](r + 1, c, 0);2164}2165if (img_row_fol[c + 1] > 0){2166imgLabels_row_fol[c + 1] = iLabel;2167sopArray_[rowBegin](r + 1, c + 1, iLabel);2168}2169else{2170imgLabels_row_fol[c + 1] = 0;2171sopArray_[rowBegin](r + 1, c + 1, 0);2172}2173}2174else {2175imgLabels_row[c] = 0;2176imgLabels_row[c + 1] = 0;2177imgLabels_row_fol[c] = 0;2178imgLabels_row_fol[c + 1] = 0;2179sopArray_[rowBegin](r, c, 0);2180sopArray_[rowBegin](r, c + 1, 0);2181sopArray_[rowBegin](r + 1, c, 0);2182sopArray_[rowBegin](r + 1, c + 1, 0);2183}2184}2185}//END case 42186}2187}2188}2189else{2190//the first thread uses sop in order to make less merges2191sop_.setNextLoc(rowEnd);2192if (imgLabels_.rows& 1){2193if (imgLabels_.cols& 1){2194//Case 1: both rows and cols odd2195for (; r < rowEnd; r += 2){2196// Get rows pointer2197const PixelT * const img_row = img_.ptr<PixelT>(r);2198const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);21992200LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2201LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2202// Get rows pointer2203for (int c = 0; c < imgLabels_.cols; c += 2) {2204LabelT iLabel = imgLabels_row[c];2205if (iLabel > 0) {2206iLabel = P_[iLabel];2207if (img_row[c] > 0){2208imgLabels_row[c] = iLabel;2209sop_(r, c, iLabel);2210}2211else{2212imgLabels_row[c] = 0;2213sop_(r, c, 0);2214}2215if (c + 1 < imgLabels_.cols) {2216if (img_row[c + 1] > 0){2217imgLabels_row[c + 1] = iLabel;2218sop_(r, c + 1, iLabel);2219}2220else{2221imgLabels_row[c + 1] = 0;2222sop_(r, c + 1, 0);2223}2224if (r + 1 < imgLabels_.rows) {2225if (img_row_fol[c] > 0){2226imgLabels_row_fol[c] = iLabel;2227sop_(r + 1, c, iLabel);2228}2229else{2230imgLabels_row_fol[c] = 0;2231sop_(r + 1, c, 0);2232}2233if (img_row_fol[c + 1] > 0){2234imgLabels_row_fol[c + 1] = iLabel;2235sop_(r + 1, c + 1, iLabel);2236}2237else{2238imgLabels_row_fol[c + 1] = 0;2239sop_(r + 1, c + 1, 0);2240}2241}2242}2243else if (r + 1 < imgLabels_.rows) {2244if (img_row_fol[c] > 0){2245imgLabels_row_fol[c] = iLabel;2246sop_(r + 1, c, iLabel);2247}2248else{2249imgLabels_row_fol[c] = 0;2250sop_(r + 1, c, 0);2251}2252}2253}2254else {2255imgLabels_row[c] = 0;2256sop_(r, c, 0);2257if (c + 1 < imgLabels_.cols) {2258imgLabels_row[c + 1] = 0;2259sop_(r, c + 1, 0);2260if (r + 1 < imgLabels_.rows) {2261imgLabels_row_fol[c] = 0;2262imgLabels_row_fol[c + 1] = 0;2263sop_(r + 1, c, 0);2264sop_(r + 1, c + 1, 0);2265}2266}2267else if (r + 1 < imgLabels_.rows) {2268imgLabels_row_fol[c] = 0;2269sop_(r + 1, c, 0);2270}2271}2272}2273}2274}//END Case 12275else{2276//Case 2: only rows odd2277for (; r < rowEnd; r += 2){2278// Get rows pointer2279const PixelT * const img_row = img_.ptr<PixelT>(r);2280const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2281LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2282LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2283// Get rows pointer2284for (int c = 0; c < imgLabels_.cols; c += 2) {2285LabelT iLabel = imgLabels_row[c];2286if (iLabel > 0) {2287iLabel = P_[iLabel];2288if (img_row[c] > 0){2289imgLabels_row[c] = iLabel;2290sop_(r, c, iLabel);2291}2292else{2293imgLabels_row[c] = 0;2294sop_(r, c, 0);2295}2296if (img_row[c + 1] > 0){2297imgLabels_row[c + 1] = iLabel;2298sop_(r, c + 1, iLabel);2299}2300else{2301imgLabels_row[c + 1] = 0;2302sop_(r, c + 1, 0);2303}2304if (r + 1 < imgLabels_.rows) {2305if (img_row_fol[c] > 0){2306imgLabels_row_fol[c] = iLabel;2307sop_(r + 1, c, iLabel);2308}2309else{2310imgLabels_row_fol[c] = 0;2311sop_(r + 1, c, 0);2312}2313if (img_row_fol[c + 1] > 0){2314imgLabels_row_fol[c + 1] = iLabel;2315sop_(r + 1, c + 1, iLabel);2316}2317else{2318imgLabels_row_fol[c + 1] = 0;2319sop_(r + 1, c + 1, 0);2320}2321}2322}2323else {2324imgLabels_row[c] = 0;2325imgLabels_row[c + 1] = 0;2326sop_(r, c, 0);2327sop_(r, c + 1, 0);2328if (r + 1 < imgLabels_.rows) {2329imgLabels_row_fol[c] = 0;2330imgLabels_row_fol[c + 1] = 0;2331sop_(r + 1, c, 0);2332sop_(r + 1, c + 1, 0);2333}2334}2335}2336}2337}// END Case 22338}2339else{2340if (imgLabels_.cols& 1){2341//Case 3: only cols odd2342for (; r < rowEnd; r += 2){2343// Get rows pointer2344const PixelT * const img_row = img_.ptr<PixelT>(r);2345const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2346LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2347LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2348// Get rows pointer2349for (int c = 0; c < imgLabels_.cols; c += 2) {2350LabelT iLabel = imgLabels_row[c];2351if (iLabel > 0) {2352iLabel = P_[iLabel];2353if (img_row[c] > 0){2354imgLabels_row[c] = iLabel;2355sop_(r, c, iLabel);2356}2357else{2358imgLabels_row[c] = 0;2359sop_(r, c, 0);2360}2361if (img_row_fol[c] > 0){2362imgLabels_row_fol[c] = iLabel;2363sop_(r + 1, c, iLabel);2364}2365else{2366imgLabels_row_fol[c] = 0;2367sop_(r + 1, c, 0);2368}2369if (c + 1 < imgLabels_.cols) {2370if (img_row[c + 1] > 0){2371imgLabels_row[c + 1] = iLabel;2372sop_(r, c + 1, iLabel);2373}2374else{2375imgLabels_row[c + 1] = 0;2376sop_(r, c + 1, 0);2377}2378if (img_row_fol[c + 1] > 0){2379imgLabels_row_fol[c + 1] = iLabel;2380sop_(r + 1, c + 1, iLabel);2381}2382else{2383imgLabels_row_fol[c + 1] = 0;2384sop_(r + 1, c + 1, 0);2385}2386}2387}2388else{2389imgLabels_row[c] = 0;2390imgLabels_row_fol[c] = 0;2391sop_(r, c, 0);2392sop_(r + 1, c, 0);2393if (c + 1 < imgLabels_.cols) {2394imgLabels_row[c + 1] = 0;2395imgLabels_row_fol[c + 1] = 0;2396sop_(r, c + 1, 0);2397sop_(r + 1, c + 1, 0);2398}2399}2400}2401}2402}// END case 32403else{2404//Case 4: nothing odd2405for (; r < rowEnd; r += 2){2406// Get rows pointer2407const PixelT * const img_row = img_.ptr<PixelT>(r);2408const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);2409LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);2410LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);2411// Get rows pointer2412for (int c = 0; c < imgLabels_.cols; c += 2) {2413LabelT iLabel = imgLabels_row[c];2414if (iLabel > 0) {2415iLabel = P_[iLabel];2416if (img_row[c] > 0){2417imgLabels_row[c] = iLabel;2418sop_(r, c, iLabel);2419}2420else{2421imgLabels_row[c] = 0;2422sop_(r, c, 0);2423}2424if (img_row[c + 1] > 0){2425imgLabels_row[c + 1] = iLabel;2426sop_(r, c + 1, iLabel);2427}2428else{2429imgLabels_row[c + 1] = 0;2430sop_(r, c + 1, 0);2431}2432if (img_row_fol[c] > 0){2433imgLabels_row_fol[c] = iLabel;2434sop_(r + 1, c, iLabel);2435}2436else{2437imgLabels_row_fol[c] = 0;2438sop_(r + 1, c, 0);2439}2440if (img_row_fol[c + 1] > 0){2441imgLabels_row_fol[c + 1] = iLabel;2442sop_(r + 1, c + 1, iLabel);2443}2444else{2445imgLabels_row_fol[c + 1] = 0;2446sop_(r + 1, c + 1, 0);2447}2448}2449else {2450imgLabels_row[c] = 0;2451imgLabels_row[c + 1] = 0;2452imgLabels_row_fol[c] = 0;2453imgLabels_row_fol[c + 1] = 0;2454sop_(r, c, 0);2455sop_(r, c + 1, 0);2456sop_(r + 1, c, 0);2457sop_(r + 1, c + 1, 0);2458}2459}2460}//END case 42461}2462}2463}2464}2465};24662467inline static2468void mergeLabels(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels){24692470// Merge Mask2471// +---+---+---+2472// |P -|Q -|R -|2473// |- -|- -|- -|2474// +---+---+---+2475// |X -|2476// |- -|2477// +---+2478const int w = imgLabels.cols, h = imgLabels.rows;24792480for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){24812482LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);2483LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);2484const PixelT * const img_row = img.ptr<PixelT>(r);2485const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);24862487for (int c = 0; c < w; c += 2){24882489#define condition_x imgLabels_row[c] > 02490#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 02491#define condition_qppr imgLabels_row_prev_prev[c] > 02492#define condition_qppr1 c < w - 12493#define condition_qppr2 c < w2494#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 024952496if (condition_x){2497if (condition_pppr){2498//check in img2499if (img_row[c] > 0 && img_row_prev[c - 1] > 0)2500//assign the same label2501imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]);2502}2503if (condition_qppr){2504if (condition_qppr1){2505if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) ||2506(img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){2507imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);2508}2509}2510else /*if (condition_qppr2)*/{2511if (img_row[c] > 0 && img_row_prev[c] > 0)2512imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);2513}2514}2515if (condition_rppr){2516if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0)2517imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]);2518}2519}2520}2521}2522}25232524LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){2525CV_Assert(img.rows == imgLabels.rows);2526CV_Assert(img.cols == imgLabels.cols);2527CV_Assert(connectivity == 8);25282529const int h = img.rows;2530const int w = img.cols;25312532//A quick and dirty upper bound for the maximum number of labels.2533//Following formula comes from the fact that a 2x2 block in 8-connectivity case2534//can never have more than 1 new label and 1 label for background.2535//Worst case image example pattern:2536//1 0 1 0 1...2537//0 0 0 0 0...2538//1 0 1 0 1...2539//............2540const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;25412542//Array used to store info and labeled pixel by each thread.2543//Different threads affect different memory location of chunksSizeAndLabels2544int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));25452546//Tree of labels2547LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));2548//First label is for background2549P[0] = 0;25502551cv::Range range(0, h);2552const double nParallelStripes = std::max(1, std::min(h / 2, getNumThreads()*4));25532554//First scan, each thread works with chunk of img.rows/nThreads rows2555//e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows2556cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nParallelStripes);25572558//merge labels of different chunks2559mergeLabels(img, imgLabels, P, chunksSizeAndLabels);25602561LabelT nLabels = 1;2562for (int i = 0; i < h; i = chunksSizeAndLabels[i]){2563flattenL(P, LabelT((i + 1) / 2) * LabelT((w + 1) / 2) + 1, chunksSizeAndLabels[i + 1], nLabels);2564}25652566//Array for statistics data2567StatsOp *sopArray = new StatsOp[h];2568sop.init(nLabels);25692570//Second scan2571cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nParallelStripes);25722573StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);2574sop.finish();25752576delete[] sopArray;2577cv::fastFree(chunksSizeAndLabels);2578cv::fastFree(P);2579return nLabels;2580}2581};//End struct LabelingGranaParallel25822583// Based on "Optimized Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al2584// Only for 8-connectivity2585template<typename LabelT, typename PixelT, typename StatsOp = NoOp >2586struct LabelingGrana{2587LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){2588CV_Assert(img.rows == imgLabels.rows);2589CV_Assert(img.cols == imgLabels.cols);2590CV_Assert(connectivity == 8);25912592const int h = img.rows;2593const int w = img.cols;25942595//A quick and dirty upper bound for the maximum number of labels.2596//Following formula comes from the fact that a 2x2 block in 8-connectivity case2597//can never have more than 1 new label and 1 label for background.2598//Worst case image example pattern:2599//1 0 1 0 1...2600//0 0 0 0 0...2601//1 0 1 0 1...2602//............2603const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;26042605LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);2606P[0] = 0;2607LabelT lunique = 1;26082609// First scan2610for (int r = 0; r < h; r += 2) {2611// Get rows pointer2612const PixelT * const img_row = img.ptr<PixelT>(r);2613const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);2614const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]);2615const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);2616LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);2617LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);2618for (int c = 0; c < w; c += 2) {26192620// We work with 2x2 blocks2621// +-+-+-+2622// |P|Q|R|2623// +-+-+-+2624// |S|X|2625// +-+-+26262627// The pixels are named as follows2628// +---+---+---+2629// |a b|c d|e f|2630// |g h|i j|k l|2631// +---+---+---+2632// |m n|o p|2633// |q r|s t|2634// +---+---+26352636// Pixels a, f, l, q are not needed, since we need to understand the2637// the connectivity between these blocks and those pixels only metter2638// when considering the outer connectivities26392640// A bunch of defines used to check if the pixels are foreground,2641// without going outside the image limits.2642#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>02643#define condition_c r-2>=0 && img_row_prev_prev[c]>02644#define condition_d c+1<w&& r-2>=0 && img_row_prev_prev[c+1]>02645#define condition_e c+2<w && r-1>=0 && img_row_prev[c-1]>026462647#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>02648#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>02649#define condition_i r-1>=0 && img_row_prev[c]>02650#define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>02651#define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>026522653#define condition_m c-2>=0 && img_row[c-2]>02654#define condition_n c-1>=0 && img_row[c-1]>02655#define condition_o img_row[c]>02656#define condition_p c+1<w && img_row[c+1]>026572658#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>02659#define condition_s r+1<h && img_row_fol[c]>02660#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>026612662// This is a decision tree which allows to choose which action to2663// perform, checking as few conditions as possible.2664// Actions: the blocks label are provisionally stored in the top left2665// pixel of the block in the labels image26662667if (condition_o) {2668if (condition_n) {2669if (condition_j) {2670if (condition_i) {2671//Action_6: Assign label of block S2672imgLabels_row[c] = imgLabels_row[c - 2];2673continue;2674}2675else {2676if (condition_c) {2677if (condition_h) {2678//Action_6: Assign label of block S2679imgLabels_row[c] = imgLabels_row[c - 2];2680continue;2681}2682else {2683if (condition_g) {2684if (condition_b) {2685//Action_6: Assign label of block S2686imgLabels_row[c] = imgLabels_row[c - 2];2687continue;2688}2689else {2690//Action_11: Merge labels of block Q and S2691imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2692continue;2693}2694}2695else {2696//Action_11: Merge labels of block Q and S2697imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2698continue;2699}2700}2701}2702else {2703//Action_11: Merge labels of block Q and S2704imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2705continue;2706}2707}2708}2709else {2710if (condition_p) {2711if (condition_k) {2712if (condition_d) {2713if (condition_i) {2714//Action_6: Assign label of block S2715imgLabels_row[c] = imgLabels_row[c - 2];2716continue;2717}2718else {2719if (condition_c) {2720if (condition_h) {2721//Action_6: Assign label of block S2722imgLabels_row[c] = imgLabels_row[c - 2];2723continue;2724}2725else {2726if (condition_g) {2727if (condition_b) {2728//Action_6: Assign label of block S2729imgLabels_row[c] = imgLabels_row[c - 2];2730continue;2731}2732else {2733//Action_12: Merge labels of block R and S2734imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2735continue;2736}2737}2738else {2739//Action_12: Merge labels of block R and S2740imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2741continue;2742}2743}2744}2745else {2746//Action_12: Merge labels of block R and S2747imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2748continue;2749}2750}2751}2752else {2753//Action_12: Merge labels of block R and S2754imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2755continue;2756}2757}2758else {2759//Action_6: Assign label of block S2760imgLabels_row[c] = imgLabels_row[c - 2];2761continue;2762}2763}2764else {2765//Action_6: Assign label of block S2766imgLabels_row[c] = imgLabels_row[c - 2];2767continue;2768}2769}2770}2771else {2772if (condition_r) {2773if (condition_j) {2774if (condition_m) {2775if (condition_h) {2776if (condition_i) {2777//Action_6: Assign label of block S2778imgLabels_row[c] = imgLabels_row[c - 2];2779continue;2780}2781else {2782if (condition_c) {2783//Action_6: Assign label of block S2784imgLabels_row[c] = imgLabels_row[c - 2];2785continue;2786}2787else {2788//Action_11: Merge labels of block Q and S2789imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2790continue;2791}2792}2793}2794else {2795if (condition_g) {2796if (condition_b) {2797if (condition_i) {2798//Action_6: Assign label of block S2799imgLabels_row[c] = imgLabels_row[c - 2];2800continue;2801}2802else {2803if (condition_c) {2804//Action_6: Assign label of block S2805imgLabels_row[c] = imgLabels_row[c - 2];2806continue;2807}2808else {2809//Action_11: Merge labels of block Q and S2810imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2811continue;2812}2813}2814}2815else {2816//Action_11: Merge labels of block Q and S2817imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2818continue;2819}2820}2821else {2822//Action_11: Merge labels of block Q and S2823imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2824continue;2825}2826}2827}2828else {2829if (condition_i) {2830//Action_11: Merge labels of block Q and S2831imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2832continue;2833}2834else {2835if (condition_h) {2836if (condition_c) {2837//Action_11: Merge labels of block Q and S2838imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2839continue;2840}2841else {2842//Action_14: Merge labels of block P, Q and S2843imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);2844continue;2845}2846}2847else {2848//Action_11: Merge labels of block Q and S2849imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);2850continue;2851}2852}2853}2854}2855else {2856if (condition_p) {2857if (condition_k) {2858if (condition_m) {2859if (condition_h) {2860if (condition_d) {2861if (condition_i) {2862//Action_6: Assign label of block S2863imgLabels_row[c] = imgLabels_row[c - 2];2864continue;2865}2866else {2867if (condition_c) {2868//Action_6: Assign label of block S2869imgLabels_row[c] = imgLabels_row[c - 2];2870continue;2871}2872else {2873//Action_12: Merge labels of block R and S2874imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2875continue;2876}2877}2878}2879else {2880//Action_12: Merge labels of block R and S2881imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2882continue;2883}2884}2885else {2886if (condition_d) {2887if (condition_g) {2888if (condition_b) {2889if (condition_i) {2890//Action_6: Assign label of block S2891imgLabels_row[c] = imgLabels_row[c - 2];2892continue;2893}2894else {2895if (condition_c) {2896//Action_6: Assign label of block S2897imgLabels_row[c] = imgLabels_row[c - 2];2898continue;2899}2900else {2901//Action_12: Merge labels of block R and S2902imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2903continue;2904}2905}2906}2907else {2908//Action_12: Merge labels of block R and S2909imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2910continue;2911}2912}2913else {2914//Action_12: Merge labels of block R and S2915imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2916continue;2917}2918}2919else {2920if (condition_i) {2921if (condition_g) {2922if (condition_b) {2923//Action_12: Merge labels of block R and S2924imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2925continue;2926}2927else {2928//Action_16: labels of block Q, R and S2929imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);2930continue;2931}2932}2933else {2934//Action_16: labels of block Q, R and S2935imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);2936continue;2937}2938}2939else {2940//Action_12: Merge labels of block R and S2941imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2942continue;2943}2944}2945}2946}2947else {2948if (condition_i) {2949if (condition_d) {2950//Action_12: Merge labels of block R and S2951imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2952continue;2953}2954else {2955//Action_16: labels of block Q, R and S2956imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);2957continue;2958}2959}2960else {2961if (condition_h) {2962if (condition_d) {2963if (condition_c) {2964//Action_12: Merge labels of block R and S2965imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2966continue;2967}2968else {2969//Action_15: Merge labels of block P, R and S2970imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);2971continue;2972}2973}2974else {2975//Action_15: Merge labels of block P, R and S2976imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);2977continue;2978}2979}2980else {2981//Action_12: Merge labels of block R and S2982imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);2983continue;2984}2985}2986}2987}2988else {2989if (condition_h) {2990if (condition_m) {2991//Action_6: Assign label of block S2992imgLabels_row[c] = imgLabels_row[c - 2];2993continue;2994}2995else {2996// ACTION_9 Merge labels of block P and S2997imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);2998continue;2999}3000}3001else {3002if (condition_i) {3003if (condition_m) {3004if (condition_g) {3005if (condition_b) {3006//Action_6: Assign label of block S3007imgLabels_row[c] = imgLabels_row[c - 2];3008continue;3009}3010else {3011//Action_11: Merge labels of block Q and S3012imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3013continue;3014}3015}3016else {3017//Action_11: Merge labels of block Q and S3018imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3019continue;3020}3021}3022else {3023//Action_11: Merge labels of block Q and S3024imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3025continue;3026}3027}3028else {3029//Action_6: Assign label of block S3030imgLabels_row[c] = imgLabels_row[c - 2];3031continue;3032}3033}3034}3035}3036else {3037if (condition_h) {3038if (condition_m) {3039//Action_6: Assign label of block S3040imgLabels_row[c] = imgLabels_row[c - 2];3041continue;3042}3043else {3044// ACTION_9 Merge labels of block P and S3045imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);3046continue;3047}3048}3049else {3050if (condition_i) {3051if (condition_m) {3052if (condition_g) {3053if (condition_b) {3054//Action_6: Assign label of block S3055imgLabels_row[c] = imgLabels_row[c - 2];3056continue;3057}3058else {3059//Action_11: Merge labels of block Q and S3060imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3061continue;3062}3063}3064else {3065//Action_11: Merge labels of block Q and S3066imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3067continue;3068}3069}3070else {3071//Action_11: Merge labels of block Q and S3072imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3073continue;3074}3075}3076else {3077//Action_6: Assign label of block S3078imgLabels_row[c] = imgLabels_row[c - 2];3079continue;3080}3081}3082}3083}3084}3085else {3086if (condition_j) {3087if (condition_i) {3088//Action_4: Assign label of block Q3089imgLabels_row[c] = imgLabels_row_prev_prev[c];3090continue;3091}3092else {3093if (condition_h) {3094if (condition_c) {3095//Action_4: Assign label of block Q3096imgLabels_row[c] = imgLabels_row_prev_prev[c];3097continue;3098}3099else {3100//Action_7: Merge labels of block P and Q3101imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);3102continue;3103}3104}3105else {3106//Action_4: Assign label of block Q3107imgLabels_row[c] = imgLabels_row_prev_prev[c];3108continue;3109}3110}3111}3112else {3113if (condition_p) {3114if (condition_k) {3115if (condition_i) {3116if (condition_d) {3117//Action_5: Assign label of block R3118imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3119continue;3120}3121else {3122// ACTION_10 Merge labels of block Q and R3123imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);3124continue;3125}3126}3127else {3128if (condition_h) {3129if (condition_d) {3130if (condition_c) {3131//Action_5: Assign label of block R3132imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3133continue;3134}3135else {3136//Action_8: Merge labels of block P and R3137imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);3138continue;3139}3140}3141else {3142//Action_8: Merge labels of block P and R3143imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);3144continue;3145}3146}3147else {3148//Action_5: Assign label of block R3149imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3150continue;3151}3152}3153}3154else {3155if (condition_i) {3156//Action_4: Assign label of block Q3157imgLabels_row[c] = imgLabels_row_prev_prev[c];3158continue;3159}3160else {3161if (condition_h) {3162//Action_3: Assign label of block P3163imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];3164continue;3165}3166else {3167//Action_2: New label (the block has foreground pixels and is not connected to anything else)3168imgLabels_row[c] = lunique;3169P[lunique] = lunique;3170lunique = lunique + 1;3171continue;3172}3173}3174}3175}3176else {3177if (condition_i) {3178//Action_4: Assign label of block Q3179imgLabels_row[c] = imgLabels_row_prev_prev[c];3180continue;3181}3182else {3183if (condition_h) {3184//Action_3: Assign label of block P3185imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];3186continue;3187}3188else {3189//Action_2: New label (the block has foreground pixels and is not connected to anything else)3190imgLabels_row[c] = lunique;3191P[lunique] = lunique;3192lunique = lunique + 1;3193continue;3194}3195}3196}3197}3198}3199}3200}3201else {3202if (condition_s) {3203if (condition_p) {3204if (condition_n) {3205if (condition_j) {3206if (condition_i) {3207//Action_6: Assign label of block S3208imgLabels_row[c] = imgLabels_row[c - 2];3209continue;3210}3211else {3212if (condition_c) {3213if (condition_h) {3214//Action_6: Assign label of block S3215imgLabels_row[c] = imgLabels_row[c - 2];3216continue;3217}3218else {3219if (condition_g) {3220if (condition_b) {3221//Action_6: Assign label of block S3222imgLabels_row[c] = imgLabels_row[c - 2];3223continue;3224}3225else {3226//Action_11: Merge labels of block Q and S3227imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3228continue;3229}3230}3231else {3232//Action_11: Merge labels of block Q and S3233imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3234continue;3235}3236}3237}3238else {3239//Action_11: Merge labels of block Q and S3240imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3241continue;3242}3243}3244}3245else {3246if (condition_k) {3247if (condition_d) {3248if (condition_i) {3249//Action_6: Assign label of block S3250imgLabels_row[c] = imgLabels_row[c - 2];3251continue;3252}3253else {3254if (condition_c) {3255if (condition_h) {3256//Action_6: Assign label of block S3257imgLabels_row[c] = imgLabels_row[c - 2];3258continue;3259}3260else {3261if (condition_g) {3262if (condition_b) {3263//Action_6: Assign label of block S3264imgLabels_row[c] = imgLabels_row[c - 2];3265continue;3266}3267else {3268//Action_12: Merge labels of block R and S3269imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3270continue;3271}3272}3273else {3274//Action_12: Merge labels of block R and S3275imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3276continue;3277}3278}3279}3280else {3281//Action_12: Merge labels of block R and S3282imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3283continue;3284}3285}3286}3287else {3288//Action_12: Merge labels of block R and S3289imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3290continue;3291}3292}3293else {3294//Action_6: Assign label of block S3295imgLabels_row[c] = imgLabels_row[c - 2];3296continue;3297}3298}3299}3300else {3301if (condition_r) {3302if (condition_j) {3303if (condition_m) {3304if (condition_h) {3305if (condition_i) {3306//Action_6: Assign label of block S3307imgLabels_row[c] = imgLabels_row[c - 2];3308continue;3309}3310else {3311if (condition_c) {3312//Action_6: Assign label of block S3313imgLabels_row[c] = imgLabels_row[c - 2];3314continue;3315}3316else {3317//Action_11: Merge labels of block Q and S3318imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3319continue;3320}3321}3322}3323else {3324if (condition_g) {3325if (condition_b) {3326if (condition_i) {3327//Action_6: Assign label of block S3328imgLabels_row[c] = imgLabels_row[c - 2];3329continue;3330}3331else {3332if (condition_c) {3333//Action_6: Assign label of block S3334imgLabels_row[c] = imgLabels_row[c - 2];3335continue;3336}3337else {3338//Action_11: Merge labels of block Q and S3339imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3340continue;3341}3342}3343}3344else {3345//Action_11: Merge labels of block Q and S3346imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3347continue;3348}3349}3350else {3351//Action_11: Merge labels of block Q and S3352imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3353continue;3354}3355}3356}3357else {3358//Action_11: Merge labels of block Q and S3359imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3360continue;3361}3362}3363else {3364if (condition_k) {3365if (condition_d) {3366if (condition_m) {3367if (condition_h) {3368if (condition_i) {3369//Action_6: Assign label of block S3370imgLabels_row[c] = imgLabels_row[c - 2];3371continue;3372}3373else {3374if (condition_c) {3375//Action_6: Assign label of block S3376imgLabels_row[c] = imgLabels_row[c - 2];3377continue;3378}3379else {3380//Action_12: Merge labels of block R and S3381imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3382continue;3383}3384}3385}3386else {3387if (condition_g) {3388if (condition_b) {3389if (condition_i) {3390//Action_6: Assign label of block S3391imgLabels_row[c] = imgLabels_row[c - 2];3392continue;3393}3394else {3395if (condition_c) {3396//Action_6: Assign label of block S3397imgLabels_row[c] = imgLabels_row[c - 2];3398continue;3399}3400else {3401//Action_12: Merge labels of block R and S3402imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3403continue;3404}3405}3406}3407else {3408//Action_12: Merge labels of block R and S3409imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3410continue;3411}3412}3413else {3414//Action_12: Merge labels of block R and S3415imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3416continue;3417}3418}3419}3420else {3421//Action_12: Merge labels of block R and S3422imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3423continue;3424}3425}3426else {3427if (condition_i) {3428if (condition_m) {3429if (condition_h) {3430//Action_12: Merge labels of block R and S3431imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3432continue;3433}3434else {3435if (condition_g) {3436if (condition_b) {3437//Action_12: Merge labels of block R and S3438imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3439continue;3440}3441else {3442//Action_16: labels of block Q, R and S3443imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);3444continue;3445}3446}3447else {3448//Action_16: labels of block Q, R and S3449imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);3450continue;3451}3452}3453}3454else {3455//Action_16: labels of block Q, R and S3456imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);3457continue;3458}3459}3460else {3461//Action_12: Merge labels of block R and S3462imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);3463continue;3464}3465}3466}3467else {3468if (condition_i) {3469if (condition_m) {3470if (condition_h) {3471//Action_6: Assign label of block S3472imgLabels_row[c] = imgLabels_row[c - 2];3473continue;3474}3475else {3476if (condition_g) {3477if (condition_b) {3478//Action_6: Assign label of block S3479imgLabels_row[c] = imgLabels_row[c - 2];3480continue;3481}3482else {3483//Action_11: Merge labels of block Q and S3484imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3485continue;3486}3487}3488else {3489//Action_11: Merge labels of block Q and S3490imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3491continue;3492}3493}3494}3495else {3496//Action_11: Merge labels of block Q and S3497imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);3498continue;3499}3500}3501else {3502//Action_6: Assign label of block S3503imgLabels_row[c] = imgLabels_row[c - 2];3504continue;3505}3506}3507}3508}3509else {3510if (condition_j) {3511//Action_4: Assign label of block Q3512imgLabels_row[c] = imgLabels_row_prev_prev[c];3513continue;3514}3515else {3516if (condition_k) {3517if (condition_i) {3518if (condition_d) {3519//Action_5: Assign label of block R3520imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3521continue;3522}3523else {3524// ACTION_10 Merge labels of block Q and R3525imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);3526continue;3527}3528}3529else {3530//Action_5: Assign label of block R3531imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3532continue;3533}3534}3535else {3536if (condition_i) {3537//Action_4: Assign label of block Q3538imgLabels_row[c] = imgLabels_row_prev_prev[c];3539continue;3540}3541else {3542//Action_2: New label (the block has foreground pixels and is not connected to anything else)3543imgLabels_row[c] = lunique;3544P[lunique] = lunique;3545lunique = lunique + 1;3546continue;3547}3548}3549}3550}3551}3552}3553else {3554if (condition_r) {3555//Action_6: Assign label of block S3556imgLabels_row[c] = imgLabels_row[c - 2];3557continue;3558}3559else {3560if (condition_n) {3561//Action_6: Assign label of block S3562imgLabels_row[c] = imgLabels_row[c - 2];3563continue;3564}3565else {3566//Action_2: New label (the block has foreground pixels and is not connected to anything else)3567imgLabels_row[c] = lunique;3568P[lunique] = lunique;3569lunique = lunique + 1;3570continue;3571}3572}3573}3574}3575else {3576if (condition_p) {3577if (condition_j) {3578//Action_4: Assign label of block Q3579imgLabels_row[c] = imgLabels_row_prev_prev[c];3580continue;3581}3582else {3583if (condition_k) {3584if (condition_i) {3585if (condition_d) {3586//Action_5: Assign label of block R3587imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3588continue;3589}3590else {3591// ACTION_10 Merge labels of block Q and R3592imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);3593continue;3594}3595}3596else {3597//Action_5: Assign label of block R3598imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];3599continue;3600}3601}3602else {3603if (condition_i) {3604//Action_4: Assign label of block Q3605imgLabels_row[c] = imgLabels_row_prev_prev[c];3606continue;3607}3608else {3609//Action_2: New label (the block has foreground pixels and is not connected to anything else)3610imgLabels_row[c] = lunique;3611P[lunique] = lunique;3612lunique = lunique + 1;3613continue;3614}3615}3616}3617}3618else {3619if (condition_t) {3620//Action_2: New label (the block has foreground pixels and is not connected to anything else)3621imgLabels_row[c] = lunique;3622P[lunique] = lunique;3623lunique = lunique + 1;3624continue;3625}3626else {3627// Action_1: No action (the block has no foreground pixels)3628imgLabels_row[c] = 0;3629continue;3630}3631}3632}3633}3634}36353636}36373638// Second scan + analysis3639LabelT nLabels = flattenL(P, lunique);3640sop.init(nLabels);36413642if (imgLabels.rows & 1){3643if (imgLabels.cols & 1){3644//Case 1: both rows and cols odd3645for (int r = 0; r < imgLabels.rows; r += 2) {3646// Get rows pointer3647const PixelT * const img_row = img.ptr<PixelT>(r);3648const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);3649LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);3650LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);36513652for (int c = 0; c < imgLabels.cols; c += 2) {3653LabelT iLabel = imgLabels_row[c];3654if (iLabel > 0) {3655iLabel = P[iLabel];3656if (img_row[c] > 0){3657imgLabels_row[c] = iLabel;3658sop(r, c, iLabel);3659}3660else{3661imgLabels_row[c] = 0;3662sop(r, c, 0);3663}3664if (c + 1 < imgLabels.cols) {3665if (img_row[c + 1] > 0){3666imgLabels_row[c + 1] = iLabel;3667sop(r, c + 1, iLabel);3668}3669else{3670imgLabels_row[c + 1] = 0;3671sop(r, c + 1, 0);3672}3673if (r + 1 < imgLabels.rows) {3674if (img_row_fol[c] > 0){3675imgLabels_row_fol[c] = iLabel;3676sop(r + 1, c, iLabel);3677}3678else{3679imgLabels_row_fol[c] = 0;3680sop(r + 1, c, 0);3681}3682if (img_row_fol[c + 1] > 0){3683imgLabels_row_fol[c + 1] = iLabel;3684sop(r + 1, c + 1, iLabel);3685}3686else{3687imgLabels_row_fol[c + 1] = 0;3688sop(r + 1, c + 1, 0);3689}3690}3691}3692else if (r + 1 < imgLabels.rows) {3693if (img_row_fol[c] > 0){3694imgLabels_row_fol[c] = iLabel;3695sop(r + 1, c, iLabel);3696}3697else{3698imgLabels_row_fol[c] = 0;3699sop(r + 1, c, 0);3700}3701}3702}3703else {3704imgLabels_row[c] = 0;3705sop(r, c, 0);3706if (c + 1 < imgLabels.cols) {3707imgLabels_row[c + 1] = 0;3708sop(r, c + 1, 0);3709if (r + 1 < imgLabels.rows) {3710imgLabels_row_fol[c] = 0;3711imgLabels_row_fol[c + 1] = 0;3712sop(r + 1, c, 0);3713sop(r + 1, c + 1, 0);3714}3715}3716else if (r + 1 < imgLabels.rows) {3717imgLabels_row_fol[c] = 0;3718sop(r + 1, c, 0);3719}3720}3721}3722}3723}//END Case 13724else{3725//Case 2: only rows odd3726for (int r = 0; r < imgLabels.rows; r += 2) {3727// Get rows pointer3728const PixelT * const img_row = img.ptr<PixelT>(r);3729const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);3730LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);3731LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);37323733for (int c = 0; c < imgLabels.cols; c += 2) {3734LabelT iLabel = imgLabels_row[c];3735if (iLabel > 0) {3736iLabel = P[iLabel];3737if (img_row[c] > 0){3738imgLabels_row[c] = iLabel;3739sop(r, c, iLabel);3740}3741else{3742imgLabels_row[c] = 0;3743sop(r, c, 0);3744}3745if (img_row[c + 1] > 0){3746imgLabels_row[c + 1] = iLabel;3747sop(r, c + 1, iLabel);3748}3749else{3750imgLabels_row[c + 1] = 0;3751sop(r, c + 1, 0);3752}3753if (r + 1 < imgLabels.rows) {3754if (img_row_fol[c] > 0){3755imgLabels_row_fol[c] = iLabel;3756sop(r + 1, c, iLabel);3757}3758else{3759imgLabels_row_fol[c] = 0;3760sop(r + 1, c, 0);3761}3762if (img_row_fol[c + 1] > 0){3763imgLabels_row_fol[c + 1] = iLabel;3764sop(r + 1, c + 1, iLabel);3765}3766else{3767imgLabels_row_fol[c + 1] = 0;3768sop(r + 1, c + 1, 0);3769}3770}3771}3772else {3773imgLabels_row[c] = 0;3774imgLabels_row[c + 1] = 0;3775sop(r, c, 0);3776sop(r, c + 1, 0);3777if (r + 1 < imgLabels.rows) {3778imgLabels_row_fol[c] = 0;3779imgLabels_row_fol[c + 1] = 0;3780sop(r + 1, c, 0);3781sop(r + 1, c + 1, 0);3782}3783}3784}3785}3786}// END Case 23787}3788else{3789if (imgLabels.cols & 1){3790//Case 3: only cols odd3791for (int r = 0; r < imgLabels.rows; r += 2) {3792// Get rows pointer3793const PixelT * const img_row = img.ptr<PixelT>(r);3794const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);3795LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);3796LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);37973798for (int c = 0; c < imgLabels.cols; c += 2) {3799LabelT iLabel = imgLabels_row[c];3800if (iLabel > 0) {3801iLabel = P[iLabel];3802if (img_row[c] > 0){3803imgLabels_row[c] = iLabel;3804sop(r, c, iLabel);3805}3806else{3807imgLabels_row[c] = 0;3808sop(r, c, 0);3809}3810if (img_row_fol[c] > 0){3811imgLabels_row_fol[c] = iLabel;3812sop(r + 1, c, iLabel);3813}3814else{3815imgLabels_row_fol[c] = 0;3816sop(r + 1, c, 0);3817}3818if (c + 1 < imgLabels.cols) {3819if (img_row[c + 1] > 0){3820imgLabels_row[c + 1] = iLabel;3821sop(r, c + 1, iLabel);3822}3823else{3824imgLabels_row[c + 1] = 0;3825sop(r, c + 1, 0);3826}3827if (img_row_fol[c + 1] > 0){3828imgLabels_row_fol[c + 1] = iLabel;3829sop(r + 1, c + 1, iLabel);3830}3831else{3832imgLabels_row_fol[c + 1] = 0;3833sop(r + 1, c + 1, 0);3834}3835}3836}3837else{3838imgLabels_row[c] = 0;3839imgLabels_row_fol[c] = 0;3840sop(r, c, 0);3841sop(r + 1, c, 0);3842if (c + 1 < imgLabels.cols) {3843imgLabels_row[c + 1] = 0;3844imgLabels_row_fol[c + 1] = 0;3845sop(r, c + 1, 0);3846sop(r + 1, c + 1, 0);3847}3848}3849}3850}3851}// END case 33852else{3853//Case 4: nothing odd3854for (int r = 0; r < imgLabels.rows; r += 2) {3855// Get rows pointer3856const PixelT * const img_row = img.ptr<PixelT>(r);3857const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);3858LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);3859LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);38603861for (int c = 0; c < imgLabels.cols; c += 2) {3862LabelT iLabel = imgLabels_row[c];3863if (iLabel > 0) {3864iLabel = P[iLabel];3865if (img_row[c] > 0){3866imgLabels_row[c] = iLabel;3867sop(r, c, iLabel);3868}3869else{3870imgLabels_row[c] = 0;3871sop(r, c, 0);3872}3873if (img_row[c + 1] > 0){3874imgLabels_row[c + 1] = iLabel;3875sop(r, c + 1, iLabel);3876}3877else{3878imgLabels_row[c + 1] = 0;3879sop(r, c + 1, 0);3880}3881if (img_row_fol[c] > 0){3882imgLabels_row_fol[c] = iLabel;3883sop(r + 1, c, iLabel);3884}3885else{3886imgLabels_row_fol[c] = 0;3887sop(r + 1, c, 0);3888}3889if (img_row_fol[c + 1] > 0){3890imgLabels_row_fol[c + 1] = iLabel;3891sop(r + 1, c + 1, iLabel);3892}3893else{3894imgLabels_row_fol[c + 1] = 0;3895sop(r + 1, c + 1, 0);3896}3897}3898else {3899imgLabels_row[c] = 0;3900imgLabels_row[c + 1] = 0;3901imgLabels_row_fol[c] = 0;3902imgLabels_row_fol[c + 1] = 0;3903sop(r, c, 0);3904sop(r, c + 1, 0);3905sop(r + 1, c, 0);3906sop(r + 1, c + 1, 0);3907}3908}3909}3910}//END case 43911}39123913sop.finish();3914fastFree(P);39153916return nLabels;39173918} //End function LabelingGrana operator()3919};//End struct LabelingGrana3920}//end namespace connectedcomponents39213922//L's type must have an appropriate depth for the number of pixels in I3923template<typename StatsOp>3924static3925int connectedComponents_sub1(const cv::Mat& I, cv::Mat& L, int connectivity, int ccltype, StatsOp& sop){3926CV_Assert(L.channels() == 1 && I.channels() == 1);3927CV_Assert(connectivity == 8 || connectivity == 4);3928CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT);39293930int lDepth = L.depth();3931int iDepth = I.depth();3932const char *currentParallelFramework = cv::currentParallelFramework();3933const int nThreads = cv::getNumThreads();39343935CV_Assert(iDepth == CV_8U || iDepth == CV_8S);39363937//Run parallel labeling only if the rows of the image are at least twice the number of available threads3938const bool is_parallel = currentParallelFramework != NULL && nThreads > 1 && L.rows / nThreads >= 2;39393940if (ccltype == CCL_WU || connectivity == 4){3941// Wu algorithm is used3942using connectedcomponents::LabelingWu;3943using connectedcomponents::LabelingWuParallel;3944//warn if L's depth is not sufficient?3945if (lDepth == CV_8U){3946//Not supported yet3947}3948else if (lDepth == CV_16U){3949return (int)LabelingWu<ushort, uchar, StatsOp>()(I, L, connectivity, sop);3950}3951else if (lDepth == CV_32S){3952//note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects3953//OpenCV: how should we proceed? .at<T> typechecks in debug mode3954if (!is_parallel)3955return (int)LabelingWu<int, uchar, StatsOp>()(I, L, connectivity, sop);3956else3957return (int)LabelingWuParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);3958}3959}3960else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){3961// Grana algorithm is used3962using connectedcomponents::LabelingGrana;3963using connectedcomponents::LabelingGranaParallel;3964//warn if L's depth is not sufficient?3965if (lDepth == CV_8U){3966//Not supported yet3967}3968else if (lDepth == CV_16U){3969return (int)LabelingGrana<ushort, uchar, StatsOp>()(I, L, connectivity, sop);3970}3971else if (lDepth == CV_32S){3972//note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects3973//OpenCV: how should we proceed? .at<T> typechecks in debug mode3974if (!is_parallel)3975return (int)LabelingGrana<int, uchar, StatsOp>()(I, L, connectivity, sop);3976else3977return (int)LabelingGranaParallel<int, uchar, StatsOp>()(I, L, connectivity, sop);3978}3979}39803981CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");3982}39833984}39853986// Simple wrapper to ensure binary and source compatibility (ABI)3987int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype){3988return cv::connectedComponents(img_, _labels, connectivity, ltype, CCL_DEFAULT);3989}39903991int cv::connectedComponents(InputArray img_, OutputArray _labels, int connectivity, int ltype, int ccltype){3992const cv::Mat img = img_.getMat();3993_labels.create(img.size(), CV_MAT_DEPTH(ltype));3994cv::Mat labels = _labels.getMat();3995connectedcomponents::NoOp sop;3996if (ltype == CV_16U){3997return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);3998}3999else if (ltype == CV_32S){4000return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);4001}4002else{4003CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");4004}4005}40064007// Simple wrapper to ensure binary and source compatibility (ABI)4008int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv,4009OutputArray centroids, int connectivity, int ltype)4010{4011return cv::connectedComponentsWithStats(img_, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT);4012}40134014int cv::connectedComponentsWithStats(InputArray img_, OutputArray _labels, OutputArray statsv,4015OutputArray centroids, int connectivity, int ltype, int ccltype)4016{4017const cv::Mat img = img_.getMat();4018_labels.create(img.size(), CV_MAT_DEPTH(ltype));4019cv::Mat labels = _labels.getMat();4020connectedcomponents::CCStatsOp sop(statsv, centroids);4021if (ltype == CV_16U){4022return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);4023}4024else if (ltype == CV_32S){4025return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);4026}4027else{4028CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");4029return 0;4030}4031}403240334034