Merge branch 'master' into master
authorMaksim Shabunin <maksim.shabunin@gmail.com>
Sun, 26 Feb 2017 04:46:59 +0000 (07:46 +0300)
committerGitHub <noreply@github.com>
Sun, 26 Feb 2017 04:46:59 +0000 (07:46 +0300)
1  2 
modules/imgproc/include/opencv2/imgproc.hpp
modules/imgproc/src/connectedcomponents.cpp

@@@ -535,386 -312,222 +535,387 @@@ namespace cv
                      }
                  }
              }
 +#undef condition_p
 +#undef condition_q
 +#undef condition_r
 +#undef condition_x
          }
  
 -        //analysis
 -        LabelT nLabels = flattenL(P, lunique);
 -        sop.init(nLabels);
 -
 -        for(int r_i = 0; r_i < rows; ++r_i){
 -            LabelT *Lrow_start = L.ptr<LabelT>(r_i);
 -            LabelT *Lrow_end = Lrow_start + cols;
 -            LabelT *Lrow = Lrow_start;
 -            for(int c_i = 0; Lrow != Lrow_end; ++Lrow, ++c_i){
 -                const LabelT l = P[*Lrow];
 -                *Lrow = l;
 -                sop(r_i, c_i, l);
 +        inline static
 +        void mergeLabels4Connectivity(cv::Mat& imgLabels, LabelT *P, const int *chunksSizeAndLabels){
 +
 +            // Merge Mask
 +            // +-+-+-+
 +            // |-|q|-|
 +            // +-+-+-+
 +            //         |x|
 +            //   +-+
 +            const int w = imgLabels.cols, h = imgLabels.rows;
 +
 +            for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){
 +
 +                LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
 +                LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
 +
 +                for (int c = 0; c < w; ++c){
 +
 +#define condition_q imgLabels_row_prev[c] > 0
 +#define condition_x imgLabels_row[c] > 0
 +
 +                    if (condition_x){
 +                        if (condition_q){
 +                            //merge of two label
 +                            imgLabels_row[c] = set_union(P, imgLabels_row_prev[c], imgLabels_row[c]);
 +                        }
 +                    }
 +                }
              }
 +#undef condition_q
 +#undef condition_x
          }
  
 -        sop.finish();
 -        fastFree(P);
 +        LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
 +            CV_Assert(img.rows == imgLabels.rows);
 +            CV_Assert(img.cols == imgLabels.cols);
 +            CV_Assert(connectivity == 8 || connectivity == 4);
  
 -        return nLabels;
 -    }//End function LabelingWu operator()
 -    };//End struct LabelingWu
 +            const int nThreads = cv::getNumberOfCPUs();
 +            cv::setNumThreads(nThreads);
  
 -    // Based on "Optimized  Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
 -    // Only for 8-connectivity
 +            const int h = img.rows;
 +            const int w = img.cols;
 +
 +            //A quick and dirty upper bound for the maximimum number of labels.
 +            //Following formula comes from the fact that a 2x2 block in 4-way connectivity
 +            //labeling can never have more than 2 new labels and 1 label for background.
 +            //Worst case image example pattern:
 +            //1 0 1 0 1...
 +            //0 1 0 1 0...
 +            //1 0 1 0 1...
 +            //............
 +            //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling
 +            const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;
 +
 +            //Array used to store info and labeled pixel by each thread.
 +            //Different threads affect different memory location of chunksSizeAndLabels
 +            int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));
 +
 +            //Tree of labels
 +            LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));
 +            //First label is for background
 +            P[0] = 0;
 +
 +            cv::Range range(0, h);
 +            LabelT nLabels = 1;
 +
 +            if (connectivity == 8){
 +                //First scan, each thread works with chunk of img.rows/nThreads rows
 +                //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows
 +                cv::parallel_for_(range, FirstScan8Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads);
 +
 +                //merge labels of different chunks
 +                mergeLabels8Connectivity(imgLabels, P, chunksSizeAndLabels);
 +            }
 +            else{
 +                //First scan, each thread works with chunk of img.rows/nThreads rows
 +                //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows
 +                cv::parallel_for_(range, FirstScan4Connectivity(img, imgLabels, P, chunksSizeAndLabels), nThreads);
 +
 +                //merge labels of different chunks
 +                mergeLabels4Connectivity(imgLabels, P, chunksSizeAndLabels);
 +            }
 +
 +            for (int i = 0; i < h; i = chunksSizeAndLabels[i]){
 +                flattenL(P, (i * w + 1) / 2 + 1, chunksSizeAndLabels[i + 1], nLabels);
 +            }
 +
 +            //Array for statistics dataof threads
 +            StatsOp *sopArray = new StatsOp[h];
 +
 +            sop.init(nLabels);
 +            //Second scan
 +            cv::parallel_for_(range, SecondScan(imgLabels, P, sop, sopArray, nLabels), nThreads);
 +            StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);
 +            sop.finish();
 +
 +            delete[] sopArray;
 +            cv::fastFree(chunksSizeAndLabels);
 +            cv::fastFree(P);
 +            return nLabels;
 +        }
 +    };//End struct LabelingWuParallel
 +
++
 +    //Based on "Two Strategies to Speed up Connected Components Algorithms", the SAUF (Scan array union find) variant
 +    //using decision trees
 +    //Kesheng Wu, et al
      template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
 -    struct LabelingGrana{
 -    LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity,  StatsOp &sop){
 -        CV_Assert(img.rows == imgLabels.rows);
 -        CV_Assert(img.cols == imgLabels.cols);
 -        CV_Assert(connectivity == 8 || connectivity == 4);
 +    struct LabelingWu{
 +        LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
 +            CV_Assert(imgLabels.rows == img.rows);
 +            CV_Assert(imgLabels.cols == img.cols);
 +            CV_Assert(connectivity == 8 || connectivity == 4);
  
 -        const int h = img.rows;
 -        const int w = img.cols;
 -
 -        //A quick and dirty upper bound for the maximimum number of labels.
 -        const size_t Plength = img.rows*img.cols / 4;
 -        LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength);
 -        P[0] = 0;
 -        LabelT lunique = 1;
 -
 -        // First scan
 -        for (int r = 0; r<h; r += 2) {
 -            // Get rows pointer
 -            const PixelT* const img_row = img.ptr<PixelT>(r);
 -            const PixelT* const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
 -            const PixelT* const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]);
 -            const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
 -            LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
 -            LabelT* const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
 -            for (int c = 0; c < w; c += 2) {
 -
 -                // We work with 2x2 blocks
 -                // +-+-+-+
 -                // |P|Q|R|
 -                // +-+-+-+
 -                // |S|X|
 -                // +-+-+
 +            const int h = img.rows;
 +            const int w = img.cols;
  
 -                // The pixels are named as follows
 -                // +---+---+---+
 -                // |a b|c d|e f|
 -                // |g h|i j|k l|
 -                // +---+---+---+
 -                // |m n|o p|
 -                // |q r|s t|
 -                // +---+---+
 -
 -                // Pixels a, f, l, q are not needed, since we need to understand the
 -                // the connectivity between these blocks and those pixels only metter
 -                // when considering the outer connectivities
 -
 -                // A bunch of defines used to check if the pixels are foreground,
 -                // without going outside the image limits.
 -                #define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
 -                #define condition_c r-2>=0 && img_row_prev_prev[c]>0
 -                #define condition_d c+1<w && r-2>=0 && img_row_prev_prev[c+1]>0
 -                #define condition_e c+2<w && r-2>=0 && img_row_prev_prev[c+2]>0
 -
 -                #define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
 -                #define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
 -                #define condition_i r-1>=0 && img_row_prev[c]>0
 -                #define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
 -                #define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
 -
 -                #define condition_m c-2>=0 && img_row[c-2]>0
 -                #define condition_n c-1>=0 && img_row[c-1]>0
 -                #define condition_o img_row[c]>0
 -                #define condition_p c+1<w && img_row[c+1]>0
 -
 -                #define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
 -                #define condition_s r+1<h && img_row_fol[c]>0
 -                #define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
 -
 -                // This is a decision tree which allows to choose which action to
 -                // perform, checking as few conditions as possible.
 -                // Actions: the blocks label are provisionally stored in the top left
 -                // pixel of the block in the labels image
 -
 -                if (condition_o) {
 -                    if (condition_n) {
 -                        if (condition_j) {
 -                            if (condition_i) {
 -                                //Action_6: Assign label of block S
 -                                imgLabels_row[c] = imgLabels_row[c - 2];
 -                                continue;
 +            //A quick and dirty upper bound for the maximimum number of labels.
 +            //Following formula comes from the fact that a 2x2 block in 4-way connectivity
 +            //labeling can never have more than 2 new labels and 1 label for background.
 +            //Worst case image example pattern:
 +            //1 0 1 0 1...
 +            //0 1 0 1 0...
 +            //1 0 1 0 1...
 +            //............
 +            //Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling
 +            const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;
 +            //array P for equivalences resolution
 +            LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);
 +            //first label is for background pixels
 +            P[0] = 0;
 +            LabelT lunique = 1;
 +
 +            if (connectivity == 8){
 +                for (int r = 0; r < h; ++r){
 +                    // Get row pointers
 +                    PixelT const * const img_row = img.ptr<PixelT>(r);
 +                    PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
 +                    LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
 +                    LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
 +
 +                    for (int c = 0; c < w; ++c){
 +
 +#define condition_p c>0 && r>0 && img_row_prev[c - 1]>0
 +#define condition_q r>0 && img_row_prev[c]>0
 +#define condition_r c < w - 1 && r > 0 && img_row_prev[c + 1] > 0
 +#define condition_s c > 0 && img_row[c - 1] > 0
 +#define condition_x img_row[c] > 0
 +
 +                        if (condition_x){
 +                            if (condition_q){
 +                                //x <- q
 +                                imgLabels_row[c] = imgLabels_row_prev[c];
                              }
 -                            else {
 -                                if (condition_c) {
 -                                    if (condition_h) {
 -                                        //Action_6: Assign label of block S
 -                                        imgLabels_row[c] = imgLabels_row[c - 2];
 -                                        continue;
 +                            else{
 +                                // q = 0
 +                                if (condition_r){
 +                                    if (condition_p){
 +                                        // x <- merge(p,r)
 +                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev[c - 1], imgLabels_row_prev[c + 1]);
                                      }
 -                                    else {
 -                                        if (condition_g) {
 -                                            if (condition_b) {
 -                                                //Action_6: Assign label of block S
 -                                                imgLabels_row[c] = imgLabels_row[c - 2];
 -                                                continue;
 -                                            }
 -                                            else {
 -                                                //Action_11: Merge labels of block Q and S
 -                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 -                                                continue;
 -                                            }
 +                                    else{
 +                                        // p = q = 0
 +                                        if (condition_s){
 +                                            // x <- merge(s,r)
 +                                            imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c + 1]);
                                          }
 -                                        else {
 -                                            //Action_11: Merge labels of block Q and S
 -                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 -                                            continue;
 +                                        else{
 +                                            // p = q = s = 0
 +                                            // x <- r
 +                                            imgLabels_row[c] = imgLabels_row_prev[c + 1];
                                          }
                                      }
                                  }
 -                                else {
 -                                    //Action_11: Merge labels of block Q and S
 -                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 -                                    continue;
 -                                }
 -                            }
 -                        }
 -                        else {
 -                            if (condition_p) {
 -                                if (condition_k) {
 -                                    if (condition_d) {
 -                                        if (condition_i) {
 -                                            //Action_6: Assign label of block S
 -                                            imgLabels_row[c] = imgLabels_row[c - 2];
 -                                            continue;
 +                                else{
 +                                    // r = q = 0
 +                                    if (condition_p){
 +                                        // x <- p
 +                                        imgLabels_row[c] = imgLabels_row_prev[c - 1];
 +                                    }
 +                                    else{
 +                                        // r = q = p = 0
 +                                        if (condition_s){
 +                                            imgLabels_row[c] = imgLabels_row[c - 1];
                                          }
 -                                        else {
 -                                            if (condition_c) {
 -                                                if (condition_h) {
 -                                                    //Action_6: Assign label of block S
 -                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 -                                                    continue;
 -                                                }
 -                                                else {
 -                                                    if (condition_g) {
 -                                                        if (condition_b) {
 -                                                            //Action_6: Assign label of block S
 -                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 -                                                            continue;
 -                                                        }
 -                                                        else {
 -                                                            //Action_12: Merge labels of block R and S
 -                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                                            continue;
 -                                                        }
 -                                                    }
 -                                                    else {
 -                                                        //Action_12: Merge labels of block R and S
 -                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                                        continue;
 -                                                    }
 -                                                }
 -                                            }
 -                                            else {
 -                                                //Action_12: Merge labels of block R and S
 -                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                                continue;
 -                                            }
 +                                        else{
 +                                            //new label
 +                                            imgLabels_row[c] = lunique;
 +                                            P[lunique] = lunique;
 +                                            lunique = lunique + 1;
                                          }
                                      }
 -                                    else {
 -                                        //Action_12: Merge labels of block R and S
 -                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                        continue;
 -                                    }
 -                                }
 -                                else {
 -                                    //Action_6: Assign label of block S
 -                                    imgLabels_row[c] = imgLabels_row[c - 2];
 -                                    continue;
                                  }
                              }
 -                            else {
 -                                //Action_6: Assign label of block S
 -                                imgLabels_row[c] = imgLabels_row[c - 2];
 -                                continue;
 -                            }
                          }
 -                    }
 -                    else {
 -                        if (condition_r) {
 -                            if (condition_j) {
 -                                if (condition_m) {
 -                                    if (condition_h) {
 -                                        if (condition_i) {
 -                                            //Action_6: Assign label of block S
 -                                            imgLabels_row[c] = imgLabels_row[c - 2];
 -                                            continue;
 -                                        }
 -                                        else {
 -                                            if (condition_c) {
 +                        else{
 +                            //x is a background pixel
 +                            imgLabels_row[c] = 0;
 +                        }
 +                    }
 +                }
 +#undef condition_p
 +#undef condition_q
 +#undef condition_r
 +#undef condition_s
 +#undef condition_x
 +            }
 +            else{
 +                for (int r = 0; r < h; ++r){
 +                    PixelT const * const img_row = img.ptr<PixelT>(r);
 +                    PixelT const * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
 +                    LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
 +                    LabelT * const imgLabels_row_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0]);
 +                    for (int c = 0; c < w; ++c) {
 +
 +#define condition_q r > 0 && img_row_prev[c] > 0
 +#define condition_s c > 0 && img_row[c - 1] > 0
 +#define condition_x img_row[c] > 0
 +
 +                        if (condition_x){
 +                            if (condition_q){
 +                                if (condition_s){
 +                                    //Merge s->x->q
 +                                    imgLabels_row[c] = set_union(P, imgLabels_row[c - 1], imgLabels_row_prev[c]);
 +                                }
 +                                else{
 +                                    //copy q
 +                                    imgLabels_row[c] = imgLabels_row_prev[c];
 +                                }
 +                            }
 +                            else{
 +                                if (condition_s){
 +                                    // copy s
 +                                    imgLabels_row[c] = imgLabels_row[c - 1];
 +                                }
 +                                else{
 +                                    //new label
 +                                    imgLabels_row[c] = lunique;
 +                                    P[lunique] = lunique;
 +                                    lunique = lunique + 1;
 +                                }
 +                            }
 +                        }
 +                        else{
 +                            //x is a background pixel
 +                            imgLabels_row[c] = 0;
 +                        }
 +                    }
 +                }
 +#undef condition_q
 +#undef condition_s
 +#undef condition_x
 +            }
 +
 +            //analysis
 +            LabelT nLabels = flattenL(P, lunique);
 +            sop.init(nLabels);
 +
 +            for (int r = 0; r < h; ++r) {
 +                LabelT * img_row_start = imgLabels.ptr<LabelT>(r);
 +                LabelT * const img_row_end = img_row_start + w;
 +                for (int c = 0; img_row_start != img_row_end; ++img_row_start, ++c){
 +                    *img_row_start = P[*img_row_start];
 +                    sop(r, c, *img_row_start);
 +                }
 +            }
 +
 +            sop.finish();
 +            fastFree(P);
 +
 +            return nLabels;
 +        }//End function LabelingWu operator()
 +    };//End struct LabelingWu
 +
 +
-     // Based on \93Optimized  Block-based Connected Components Labeling with Decision Trees\94, Costantino Grana et al
++    // Based on "Optimized  Block-based Connected Components Labeling with Decision Trees", Costantino Grana et al
 +    // Only for 8-connectivity
 +    template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
 +    struct LabelingGranaParallel{
 +
 +        class FirstScan : public cv::ParallelLoopBody{
 +        private:
 +            const cv::Mat& img_;
 +            cv::Mat& imgLabels_;
 +            LabelT *P_;
 +            int *chunksSizeAndLabels_;
 +
 +        public:
 +            FirstScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels)
 +                : img_(img), imgLabels_(imgLabels), P_(P), chunksSizeAndLabels_(chunksSizeAndLabels){}
 +
 +            FirstScan&  operator=(const FirstScan&) { return *this; }
 +
 +            void operator()(const cv::Range& range) const{
 +
 +                int r = range.start;
 +                r += (r % 2);
 +
 +                chunksSizeAndLabels_[r] = range.end + (range.end % 2);
 +
 +                LabelT label = LabelT((r + 1) * (imgLabels_.cols + 1) / 4);
 +
 +                const LabelT firstLabel = label;
 +                const int h = img_.rows, w = img_.cols;
 +                const int limitLine = r + 1, startR = r;
 +
 +                for (; r < range.end; r += 2){
 +                    // Get rows pointer
 +                    const PixelT * const img_row = img_.ptr<uchar>(r);
 +                    const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img_.step.p[0]);
 +                    const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img_.step.p[0]);
 +                    const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                    LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                    LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels_.step.p[0] - imgLabels_.step.p[0]);
 +                    for (int c = 0; c < w; c += 2) {
 +
 +                        // We work with 2x2 blocks
 +                        // +-+-+-+
 +                        // |P|Q|R|
 +                        // +-+-+-+
 +                        // |S|X|
 +                        // +-+-+
 +
 +                        // The pixels are named as follows
 +                        // +---+---+---+
 +                        // |a b|c d|e f|
 +                        // |g h|i j|k l|
 +                        // +---+---+---+
 +                        // |m n|o p|
 +                        // |q r|s t|
 +                        // +---+---+
 +
 +                        // Pixels a, f, l, q are not needed, since we need to understand the
 +                        // the connectivity between these blocks and those pixels only metter
 +                        // when considering the outer connectivities
 +
 +                        // A bunch of defines used to check if the pixels are foreground,
 +                        // without going outside the image limits.
 +
 +#define condition_b c-1>=0 && r > limitLine && img_row_prev_prev[c-1]>0
 +#define condition_c r > limitLine && img_row_prev_prev[c]>0
 +#define condition_d c+1<w && r > limitLine && img_row_prev_prev[c+1]>0
 +#define condition_e c+2<w && r > limitLine && img_row_prev_prev[c+2]>0
 +
 +#define condition_g c-2>=0 && r > limitLine - 1 && img_row_prev[c-2]>0
 +#define condition_h c-1>=0 && r > limitLine - 1 && img_row_prev[c-1]>0
 +#define condition_i r > limitLine - 1 && img_row_prev[c]>0
 +#define condition_j c+1<w && r > limitLine - 1 && img_row_prev[c+1]>0
 +#define condition_k c+2<w && r > limitLine - 1 && img_row_prev[c+2]>0
 +
 +#define condition_m c-2>=0 && img_row[c-2]>0
 +#define condition_n c-1>=0 && img_row[c-1]>0
 +#define condition_o img_row[c]>0
 +#define condition_p c+1<w && img_row[c+1]>0
 +
 +#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
 +#define condition_s r+1<h && img_row_fol[c]>0
 +#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
 +
 +                        // This is a decision tree which allows to choose which action to
 +                        // perform, checking as few conditions as possible.
 +                        // Actions are available after the tree.
 +
 +                        if (condition_o) {
 +                            if (condition_n) {
 +                                if (condition_j) {
 +                                    if (condition_i) {
 +                                        //Action_6: Assign label of block S
 +                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                        continue;
 +                                    }
 +                                    else {
 +                                        if (condition_c) {
 +                                            if (condition_h) {
                                                  //Action_6: Assign label of block S
                                                  imgLabels_row[c] = imgLabels_row[c - 2];
                                                  continue;
                                                          }
                                                      }
                                                      else {
 -                                                        //Action_12: Merge labels of block R and S
 -                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                                        continue;
 -                                                    }
 -                                                }
 -                                                else {
 -                                                    if (condition_i) {
 -                                                        if (condition_g) {
 -                                                            if (condition_b) {
 -                                                                //Action_12: Merge labels of block R and S
 -                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 -                                                                continue;
 -                                                            }
 -                                                            else {
 -                                                                //Action_16: labels of block Q, R and S
 -                                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 -                                                                continue;
 -                                                            }
 -                                                        }
 -                                                        else {
 +                                                        if (condition_d) {
 +                                                            if (condition_g) {
 +                                                                if (condition_b) {
 +                                                                    if (condition_i) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        if (condition_c) {
 +                                                                            //Action_6: Assign label of block S
 +                                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                            continue;
 +                                                                        }
 +                                                                        else {
 +                                                                            //Action_12: Merge labels of block R and S
 +                                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                            continue;
 +                                                                        }
 +                                                                    }
 +                                                                }
 +                                                                else {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            if (condition_i) {
 +                                                                if (condition_g) {
 +                                                                    if (condition_b) {
 +                                                                        //Action_12: Merge labels of block R and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_16: labels of block Q, R and S
 +                                                                        imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                                else {
 +                                                                    //Action_16: labels of block Q, R and S
 +                                                                    imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_i) {
 +                                                        if (condition_d) {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                        else {
                                                              //Action_16: labels of block Q, R and S
 -                                                            imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                            imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        if (condition_h) {
 +                                                            if (condition_d) {
 +                                                                if (condition_c) {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    //Action_15: Merge labels of block P_, R and S
 +                                                                    imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_15: Merge labels of block P_, R and S
 +                                                                imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                            }
 +                                            else {
 +                                                if (condition_h) {
 +                                                    if (condition_m) {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        // ACTION_9 Merge labels of block P_ and S
 +                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_i) {
 +                                                        if (condition_m) {
 +                                                            if (condition_g) {
 +                                                                if (condition_b) {
 +                                                                    //Action_6: Assign label of block S
 +                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    //Action_11: Merge labels of block Q and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_11: Merge labels of block Q and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_h) {
 +                                                if (condition_m) {
 +                                                    //Action_6: Assign label of block S
 +                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    // ACTION_9 Merge labels of block P_ and S
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                if (condition_i) {
 +                                                    if (condition_m) {
 +                                                        if (condition_g) {
 +                                                            if (condition_b) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_11: Merge labels of block Q and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_11: Merge labels of block Q and S
 +                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_6: Assign label of block S
 +                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                    continue;
 +                                                }
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                                else {
 +                                    if (condition_j) {
 +                                        if (condition_i) {
 +                                            //Action_4: Assign label of block Q
 +                                            imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                            continue;
 +                                        }
 +                                        else {
 +                                            if (condition_h) {
 +                                                if (condition_c) {
 +                                                    //Action_4: Assign label of block Q
 +                                                    imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    //Action_7: Merge labels of block P_ and Q
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_4: Assign label of block Q
 +                                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        if (condition_p) {
 +                                            if (condition_k) {
 +                                                if (condition_i) {
 +                                                    if (condition_d) {
 +                                                        //Action_5: Assign label of block R
 +                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        // ACTION_10 Merge labels of block Q and R
 +                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_h) {
 +                                                        if (condition_d) {
 +                                                            if (condition_c) {
 +                                                                //Action_5: Assign label of block R
 +                                                                imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_8: Merge labels of block P_ and R
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_8: Merge labels of block P_ and R
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_5: Assign label of block R
 +                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                            }
 +                                            else {
 +                                                if (condition_i) {
 +                                                    //Action_4: Assign label of block Q
 +                                                    imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    if (condition_h) {
 +                                                        //Action_3: Assign label of block P_
 +                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                                        imgLabels_row[c] = label;
 +                                                        P_[label] = label;
 +                                                        label = label + 1;
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_i) {
 +                                                //Action_4: Assign label of block Q
 +                                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                if (condition_h) {
 +                                                    //Action_3: Assign label of block P_
 +                                                    imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                                    imgLabels_row[c] = label;
 +                                                    P_[label] = label;
 +                                                    label = label + 1;
 +                                                    continue;
 +                                                }
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }
 +                        else {
 +                            if (condition_s) {
 +                                if (condition_p) {
 +                                    if (condition_n) {
 +                                        if (condition_j) {
 +                                            if (condition_i) {
 +                                                //Action_6: Assign label of block S
 +                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                if (condition_c) {
 +                                                    if (condition_h) {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        if (condition_g) {
 +                                                            if (condition_b) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_11: Merge labels of block Q and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_k) {
 +                                                if (condition_d) {
 +                                                    if (condition_i) {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        if (condition_c) {
 +                                                            if (condition_h) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                if (condition_g) {
 +                                                                    if (condition_b) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_12: Merge labels of block R and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                                else {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_12: Merge labels of block R and S
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_6: Assign label of block S
 +                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        if (condition_r) {
 +                                            if (condition_j) {
 +                                                if (condition_m) {
 +                                                    if (condition_h) {
 +                                                        if (condition_i) {
 +                                                            //Action_6: Assign label of block S
 +                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                            continue;
 +                                                        }
 +                                                        else {
 +                                                            if (condition_c) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_11: Merge labels of block Q and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        if (condition_g) {
 +                                                            if (condition_b) {
 +                                                                if (condition_i) {
 +                                                                    //Action_6: Assign label of block S
 +                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    if (condition_c) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_11: Merge labels of block Q and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_11: Merge labels of block Q and S
 +                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                if (condition_k) {
 +                                                    if (condition_d) {
 +                                                        if (condition_m) {
 +                                                            if (condition_h) {
 +                                                                if (condition_i) {
 +                                                                    //Action_6: Assign label of block S
 +                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    if (condition_c) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_12: Merge labels of block R and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                if (condition_g) {
 +                                                                    if (condition_b) {
 +                                                                        if (condition_i) {
 +                                                                            //Action_6: Assign label of block S
 +                                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                            continue;
 +                                                                        }
 +                                                                        else {
 +                                                                            if (condition_c) {
 +                                                                                //Action_6: Assign label of block S
 +                                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                                continue;
 +                                                                            }
 +                                                                            else {
 +                                                                                //Action_12: Merge labels of block R and S
 +                                                                                imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                                continue;
 +                                                                            }
 +                                                                        }
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_12: Merge labels of block R and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                                else {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        if (condition_i) {
 +                                                            if (condition_m) {
 +                                                                if (condition_h) {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    if (condition_g) {
 +                                                                        if (condition_b) {
 +                                                                            //Action_12: Merge labels of block R and S
 +                                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                            continue;
 +                                                                        }
 +                                                                        else {
 +                                                                            //Action_16: labels of block Q, R and S
 +                                                                            imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                            continue;
 +                                                                        }
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_16: labels of block Q, R and S
 +                                                                        imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_16: labels of block Q, R and S
 +                                                                imgLabels_row[c] = set_union(P_, set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_i) {
 +                                                        if (condition_m) {
 +                                                            if (condition_h) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                if (condition_g) {
 +                                                                    if (condition_b) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_11: Merge labels of block Q and S
 +                                                                        imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                                else {
 +                                                                    //Action_11: Merge labels of block Q and S
 +                                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_j) {
 +                                                //Action_4: Assign label of block Q
 +                                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                if (condition_k) {
 +                                                    if (condition_i) {
 +                                                        if (condition_d) {
 +                                                            //Action_5: Assign label of block R
 +                                                            imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                            continue;
 +                                                        }
 +                                                        else {
 +                                                            // ACTION_10 Merge labels of block Q and R
 +                                                            imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_5: Assign label of block R
 +                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_i) {
 +                                                        //Action_4: Assign label of block Q
 +                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                                        imgLabels_row[c] = label;
 +                                                        P_[label] = label;
 +                                                        label = label + 1;
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                                else {
 +                                    if (condition_r) {
 +                                        //Action_6: Assign label of block S
 +                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                        continue;
 +                                    }
 +                                    else {
 +                                        if (condition_n) {
 +                                            //Action_6: Assign label of block S
 +                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                            continue;
 +                                        }
 +                                        else {
 +                                            //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                            imgLabels_row[c] = label;
 +                                            P_[label] = label;
 +                                            label = label + 1;
 +                                            continue;
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            else {
 +                                if (condition_p) {
 +                                    if (condition_j) {
 +                                        //Action_4: Assign label of block Q
 +                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                        continue;
 +                                    }
 +                                    else {
 +                                        if (condition_k) {
 +                                            if (condition_i) {
 +                                                if (condition_d) {
 +                                                    //Action_5: Assign label of block R
 +                                                    imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    // ACTION_10 Merge labels of block Q and R
 +                                                    imgLabels_row[c] = set_union(P_, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_5: Assign label of block R
 +                                                imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
 +                                                continue;
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_i) {
 +                                                //Action_4: Assign label of block Q
 +                                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                                imgLabels_row[c] = label;
 +                                                P_[label] = label;
 +                                                label = label + 1;
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                                else {
 +                                    if (condition_t) {
 +                                        //Action_2: New label (the block has foreground pixels and is not connected to anything else)
 +                                        imgLabels_row[c] = label;
 +                                        P_[label] = label;
 +                                        label = label + 1;
 +                                        continue;
 +                                    }
 +                                    else {
 +                                        // Action_1: No action (the block has no foreground pixels)
 +                                        imgLabels_row[c] = 0;
 +                                        continue;
 +                                    }
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +                //write in the follower memory location
 +                chunksSizeAndLabels_[startR + 1] = label - firstLabel;
 +            }
 +#undef condition_k
 +#undef condition_j
 +#undef condition_i
 +#undef condition_h
 +#undef condition_g
 +#undef condition_e
 +#undef condition_d
 +#undef condition_c
 +#undef condition_b
 +        };
 +
 +        class SecondScan : public cv::ParallelLoopBody{
 +        private:
 +            const cv::Mat& img_;
 +            cv::Mat& imgLabels_;
 +            LabelT *P_;
 +            StatsOp& sop_;
 +            StatsOp *sopArray_;
 +            LabelT& nLabels_;
 +
 +        public:
 +            SecondScan(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, StatsOp& sop, StatsOp *sopArray, LabelT& nLabels)
 +                : img_(img), imgLabels_(imgLabels), P_(P), sop_(sop), sopArray_(sopArray), nLabels_(nLabels){}
 +
 +            SecondScan&  operator=(const SecondScan& ) { return *this; }
 +
 +            void operator()(const cv::Range& range) const{
 +
 +                int r = range.start;
 +                r += (r % 2);
 +                const int rowBegin = r;
 +                const int rowEnd = range.end + range.end % 2;
 +
 +                if (rowBegin > 0){
 +                    sopArray_[rowBegin].initElement(nLabels_);
 +                    sopArray_[rowBegin].setNextLoc(rowEnd); //_nextLoc = rowEnd;
 +
 +                    if (imgLabels_.rows&  1){
 +                        if (imgLabels_.cols&  1){
 +                            //Case 1: both rows and cols odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sopArray_[rowBegin](r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sopArray_[rowBegin](r, c, 0);
 +                                        }
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            if (img_row[c + 1] > 0){
 +                                                imgLabels_row[c + 1] = iLabel;
 +                                                sopArray_[rowBegin](r, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row[c + 1] = 0;
 +                                                sopArray_[rowBegin](r, c + 1, 0);
 +                                            }
 +                                            if (r + 1 < imgLabels_.rows) {
 +                                                if (img_row_fol[c] > 0){
 +                                                    imgLabels_row_fol[c] = iLabel;
 +                                                    sopArray_[rowBegin](r + 1, c, iLabel);
 +                                                }
 +                                                else{
 +                                                    imgLabels_row_fol[c] = 0;
 +                                                    sopArray_[rowBegin](r + 1, c, 0);
 +                                                }
 +                                                if (img_row_fol[c + 1] > 0){
 +                                                    imgLabels_row_fol[c + 1] = iLabel;
 +                                                    sopArray_[rowBegin](r + 1, c + 1, iLabel);
 +                                                }
 +                                                else{
 +                                                    imgLabels_row_fol[c + 1] = 0;
 +                                                    sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                                }
 +                                            }
 +                                        }
 +                                        else if (r + 1 < imgLabels_.rows) {
 +                                            if (img_row_fol[c] > 0){
 +                                                imgLabels_row_fol[c] = iLabel;
 +                                                sopArray_[rowBegin](r + 1, c, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c] = 0;
 +                                                sopArray_[rowBegin](r + 1, c, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        sopArray_[rowBegin](r, c, 0);
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sopArray_[rowBegin](r, c + 1, 0);
 +                                            if (r + 1 < imgLabels_.rows) {
 +                                                imgLabels_row_fol[c] = 0;
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sopArray_[rowBegin](r + 1, c, 0);
 +                                                sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                        else if (r + 1 < imgLabels_.rows) {
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sopArray_[rowBegin](r + 1, c, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }//END Case 1
 +                        else{
 +                            //Case 2: only rows odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sopArray_[rowBegin](r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sopArray_[rowBegin](r, c, 0);
 +                                        }
 +                                        if (img_row[c + 1] > 0){
 +                                            imgLabels_row[c + 1] = iLabel;
 +                                            sopArray_[rowBegin](r, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sopArray_[rowBegin](r, c + 1, 0);
 +                                        }
 +                                        if (r + 1 < imgLabels_.rows) {
 +                                            if (img_row_fol[c] > 0){
 +                                                imgLabels_row_fol[c] = iLabel;
 +                                                sopArray_[rowBegin](r + 1, c, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c] = 0;
 +                                                sopArray_[rowBegin](r + 1, c, 0);
 +                                            }
 +                                            if (img_row_fol[c + 1] > 0){
 +                                                imgLabels_row_fol[c + 1] = iLabel;
 +                                                sopArray_[rowBegin](r + 1, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row[c + 1] = 0;
 +                                        sopArray_[rowBegin](r, c, 0);
 +                                        sopArray_[rowBegin](r, c + 1, 0);
 +                                        if (r + 1 < imgLabels_.rows) {
 +                                            imgLabels_row_fol[c] = 0;
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sopArray_[rowBegin](r + 1, c, 0);
 +                                            sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }// END Case 2
 +                    }
 +                    else{
 +                        if (imgLabels_.cols&  1){
 +                            //Case 3: only cols odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sopArray_[rowBegin](r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sopArray_[rowBegin](r, c, 0);
 +                                        }
 +                                        if (img_row_fol[c] > 0){
 +                                            imgLabels_row_fol[c] = iLabel;
 +                                            sopArray_[rowBegin](r + 1, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sopArray_[rowBegin](r + 1, c, 0);
 +                                        }
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            if (img_row[c + 1] > 0){
 +                                                imgLabels_row[c + 1] = iLabel;
 +                                                sopArray_[rowBegin](r, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row[c + 1] = 0;
 +                                                sopArray_[rowBegin](r, c + 1, 0);
 +                                            }
 +                                            if (img_row_fol[c + 1] > 0){
 +                                                imgLabels_row_fol[c + 1] = iLabel;
 +                                                sopArray_[rowBegin](r + 1, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else{
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row_fol[c] = 0;
 +                                        sopArray_[rowBegin](r, c, 0);
 +                                        sopArray_[rowBegin](r + 1, c, 0);
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            imgLabels_row[c + 1] = 0;
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sopArray_[rowBegin](r, c + 1, 0);
 +                                            sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }// END case 3
 +                        else{
 +                            //Case 4: nothing odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sopArray_[rowBegin](r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sopArray_[rowBegin](r, c, 0);
 +                                        }
 +                                        if (img_row[c + 1] > 0){
 +                                            imgLabels_row[c + 1] = iLabel;
 +                                            sopArray_[rowBegin](r, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sopArray_[rowBegin](r, c + 1, 0);
 +                                        }
 +                                        if (img_row_fol[c] > 0){
 +                                            imgLabels_row_fol[c] = iLabel;
 +                                            sopArray_[rowBegin](r + 1, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sopArray_[rowBegin](r + 1, c, 0);
 +                                        }
 +                                        if (img_row_fol[c + 1] > 0){
 +                                            imgLabels_row_fol[c + 1] = iLabel;
 +                                            sopArray_[rowBegin](r + 1, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row[c + 1] = 0;
 +                                        imgLabels_row_fol[c] = 0;
 +                                        imgLabels_row_fol[c + 1] = 0;
 +                                        sopArray_[rowBegin](r, c, 0);
 +                                        sopArray_[rowBegin](r, c + 1, 0);
 +                                        sopArray_[rowBegin](r + 1, c, 0);
 +                                        sopArray_[rowBegin](r + 1, c + 1, 0);
 +                                    }
 +                                }
 +                            }//END case 4
 +                        }
 +                    }
 +                }
 +                else{
 +                    //the first thread uses sop in order to make less merges
 +                    sop_.setNextLoc(rowEnd);
 +                    if (imgLabels_.rows&  1){
 +                        if (imgLabels_.cols&  1){
 +                            //Case 1: both rows and cols odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sop_(r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sop_(r, c, 0);
 +                                        }
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            if (img_row[c + 1] > 0){
 +                                                imgLabels_row[c + 1] = iLabel;
 +                                                sop_(r, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row[c + 1] = 0;
 +                                                sop_(r, c + 1, 0);
 +                                            }
 +                                            if (r + 1 < imgLabels_.rows) {
 +                                                if (img_row_fol[c] > 0){
 +                                                    imgLabels_row_fol[c] = iLabel;
 +                                                    sop_(r + 1, c, iLabel);
 +                                                }
 +                                                else{
 +                                                    imgLabels_row_fol[c] = 0;
 +                                                    sop_(r + 1, c, 0);
 +                                                }
 +                                                if (img_row_fol[c + 1] > 0){
 +                                                    imgLabels_row_fol[c + 1] = iLabel;
 +                                                    sop_(r + 1, c + 1, iLabel);
 +                                                }
 +                                                else{
 +                                                    imgLabels_row_fol[c + 1] = 0;
 +                                                    sop_(r + 1, c + 1, 0);
 +                                                }
 +                                            }
 +                                        }
 +                                        else if (r + 1 < imgLabels_.rows) {
 +                                            if (img_row_fol[c] > 0){
 +                                                imgLabels_row_fol[c] = iLabel;
 +                                                sop_(r + 1, c, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c] = 0;
 +                                                sop_(r + 1, c, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        sop_(r, c, 0);
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sop_(r, c + 1, 0);
 +                                            if (r + 1 < imgLabels_.rows) {
 +                                                imgLabels_row_fol[c] = 0;
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sop_(r + 1, c, 0);
 +                                                sop_(r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                        else if (r + 1 < imgLabels_.rows) {
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sop_(r + 1, c, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }//END Case 1
 +                        else{
 +                            //Case 2: only rows odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sop_(r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sop_(r, c, 0);
 +                                        }
 +                                        if (img_row[c + 1] > 0){
 +                                            imgLabels_row[c + 1] = iLabel;
 +                                            sop_(r, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sop_(r, c + 1, 0);
 +                                        }
 +                                        if (r + 1 < imgLabels_.rows) {
 +                                            if (img_row_fol[c] > 0){
 +                                                imgLabels_row_fol[c] = iLabel;
 +                                                sop_(r + 1, c, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c] = 0;
 +                                                sop_(r + 1, c, 0);
 +                                            }
 +                                            if (img_row_fol[c + 1] > 0){
 +                                                imgLabels_row_fol[c + 1] = iLabel;
 +                                                sop_(r + 1, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sop_(r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row[c + 1] = 0;
 +                                        sop_(r, c, 0);
 +                                        sop_(r, c + 1, 0);
 +                                        if (r + 1 < imgLabels_.rows) {
 +                                            imgLabels_row_fol[c] = 0;
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sop_(r + 1, c, 0);
 +                                            sop_(r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }// END Case 2
 +                    }
 +                    else{
 +                        if (imgLabels_.cols&  1){
 +                            //Case 3: only cols odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sop_(r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sop_(r, c, 0);
 +                                        }
 +                                        if (img_row_fol[c] > 0){
 +                                            imgLabels_row_fol[c] = iLabel;
 +                                            sop_(r + 1, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sop_(r + 1, c, 0);
 +                                        }
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            if (img_row[c + 1] > 0){
 +                                                imgLabels_row[c + 1] = iLabel;
 +                                                sop_(r, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row[c + 1] = 0;
 +                                                sop_(r, c + 1, 0);
 +                                            }
 +                                            if (img_row_fol[c + 1] > 0){
 +                                                imgLabels_row_fol[c + 1] = iLabel;
 +                                                sop_(r + 1, c + 1, iLabel);
 +                                            }
 +                                            else{
 +                                                imgLabels_row_fol[c + 1] = 0;
 +                                                sop_(r + 1, c + 1, 0);
 +                                            }
 +                                        }
 +                                    }
 +                                    else{
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row_fol[c] = 0;
 +                                        sop_(r, c, 0);
 +                                        sop_(r + 1, c, 0);
 +                                        if (c + 1 < imgLabels_.cols) {
 +                                            imgLabels_row[c + 1] = 0;
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sop_(r, c + 1, 0);
 +                                            sop_(r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        }// END case 3
 +                        else{
 +                            //Case 4: nothing odd
 +                            for (; r < rowEnd; r += 2){
 +                                // Get rows pointer
 +                                const PixelT * const img_row = img_.ptr<PixelT>(r);
 +                                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img_.step.p[0]);
 +                                LabelT * const imgLabels_row = imgLabels_.ptr<LabelT>(r);
 +                                LabelT * const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels_.step.p[0]);
 +                                // Get rows pointer
 +                                for (int c = 0; c < imgLabels_.cols; c += 2) {
 +                                    LabelT iLabel = imgLabels_row[c];
 +                                    if (iLabel > 0) {
 +                                        iLabel = P_[iLabel];
 +                                        if (img_row[c] > 0){
 +                                            imgLabels_row[c] = iLabel;
 +                                            sop_(r, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c] = 0;
 +                                            sop_(r, c, 0);
 +                                        }
 +                                        if (img_row[c + 1] > 0){
 +                                            imgLabels_row[c + 1] = iLabel;
 +                                            sop_(r, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row[c + 1] = 0;
 +                                            sop_(r, c + 1, 0);
 +                                        }
 +                                        if (img_row_fol[c] > 0){
 +                                            imgLabels_row_fol[c] = iLabel;
 +                                            sop_(r + 1, c, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c] = 0;
 +                                            sop_(r + 1, c, 0);
 +                                        }
 +                                        if (img_row_fol[c + 1] > 0){
 +                                            imgLabels_row_fol[c + 1] = iLabel;
 +                                            sop_(r + 1, c + 1, iLabel);
 +                                        }
 +                                        else{
 +                                            imgLabels_row_fol[c + 1] = 0;
 +                                            sop_(r + 1, c + 1, 0);
 +                                        }
 +                                    }
 +                                    else {
 +                                        imgLabels_row[c] = 0;
 +                                        imgLabels_row[c + 1] = 0;
 +                                        imgLabels_row_fol[c] = 0;
 +                                        imgLabels_row_fol[c + 1] = 0;
 +                                        sop_(r, c, 0);
 +                                        sop_(r, c + 1, 0);
 +                                        sop_(r + 1, c, 0);
 +                                        sop_(r + 1, c + 1, 0);
 +                                    }
 +                                }
 +                            }//END case 4
 +                        }
 +                    }
 +                }
 +            }
 +        };
 +
 +        inline static
 +        void mergeLabels(const cv::Mat& img, cv::Mat& imgLabels, LabelT *P, int *chunksSizeAndLabels){
 +
 +                // Merge Mask
 +                // +---+---+---+
 +                // |P -|Q -|R -|
 +                // |- -|- -|- -|
 +                // +---+---+---+
 +                //       |X -|
 +                //       |- -|
 +                //       +---+
 +                const int w = imgLabels.cols, h = imgLabels.rows;
 +
 +                for (int r = chunksSizeAndLabels[0]; r < h; r = chunksSizeAndLabels[r]){
 +
 +                    LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
 +                    LabelT * const  imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
 +                    const PixelT * const img_row = img.ptr<PixelT>(r);
 +                    const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
 +
 +                    for (int c = 0; c < w; c += 2){
 +
 +#define condition_x imgLabels_row[c] > 0
 +#define condition_pppr c > 1 && imgLabels_row_prev_prev[c - 2] > 0
 +#define condition_qppr imgLabels_row_prev_prev[c] > 0
 +#define condition_qppr1 c < w - 1
 +#define condition_qppr2 c < w
 +#define condition_rppr c < w - 2 && imgLabels_row_prev_prev[c + 2] > 0
 +
 +                        if (condition_x){
 +                            if (condition_pppr){
 +                                //check in img
 +                                if (img_row[c] > 0 && img_row_prev[c - 1] > 0)
 +                                    //assign the same label
 +                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c]);
 +                            }
 +                            if (condition_qppr){
 +                                if (condition_qppr1){
 +                                    if ((img_row[c] > 0 && img_row_prev[c] > 0) || (img_row[c + 1] > 0 && img_row_prev[c] > 0) ||
 +                                        (img_row[c] > 0 && img_row_prev[c + 1] > 0) || (img_row[c + 1] > 0 && img_row_prev[c + 1] > 0)){
 +                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);
 +                                    }
 +                                }
 +                                else /*if (condition_qppr2)*/{
 +                                    if (img_row[c] > 0 && img_row_prev[c] > 0)
 +                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c]);
 +                                }
 +                            }
 +                            if (condition_rppr){
 +                                if (img_row[c + 1] > 0 && img_row_prev[c + 2] > 0)
 +                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c]);
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +
 +        LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
 +            CV_Assert(img.rows == imgLabels.rows);
 +            CV_Assert(img.cols == imgLabels.cols);
 +            CV_Assert(connectivity == 8);
 +
 +            const int nThreads = cv::getNumberOfCPUs();
 +            cv::setNumThreads(nThreads);
 +
 +            const int h = img.rows;
 +            const int w = img.cols;
 +
 +            //A quick and dirty upper bound for the maximimum number of labels.
 +            //Following formula comes from the fact that a 2x2 block in 8-connectivity case
 +            //can never have more than 1 new label and 1 label for background.
 +            //Worst case image example pattern:
 +            //1 0 1 0 1...
 +            //0 0 0 0 0...
 +            //1 0 1 0 1...
 +            //............
 +            const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1;
 +
 +            //Array used to store info and labeled pixel by each thread.
 +            //Different threads affect different memory location of chunksSizeAndLabels
 +            int *chunksSizeAndLabels = (int *)cv::fastMalloc(h * sizeof(int));
 +
 +            //Tree of labels
 +            LabelT *P = (LabelT *)cv::fastMalloc(Plength * sizeof(LabelT));
 +            //First label is for background
 +            P[0] = 0;
 +
 +            cv::Range range(0, h);
 +
 +            //First scan, each thread works with chunk of img.rows/nThreads rows
 +            //e.g. 300 rows, 4 threads -> each chunks is composed of 75 rows
 +            cv::parallel_for_(range, FirstScan(img, imgLabels, P, chunksSizeAndLabels), nThreads);
 +
 +            //merge labels of different chunks
 +            mergeLabels(img, imgLabels, P, chunksSizeAndLabels);
 +
 +            LabelT nLabels = 1;
 +            for (int i = 0; i < h; i = chunksSizeAndLabels[i]){
 +                flattenL(P, (i + 1) * (w + 1) / 4, chunksSizeAndLabels[i + 1], nLabels);
 +            }
 +
 +            //Array for statistics data
 +            StatsOp *sopArray = new StatsOp[h];
 +            sop.init(nLabels);
 +
 +            //Second scan
 +            cv::parallel_for_(range, SecondScan(img, imgLabels, P, sop, sopArray, nLabels), nThreads);
 +
 +            StatsOp::mergeStats(imgLabels, sopArray, sop, nLabels);
 +            sop.finish();
 +
 +            delete[] sopArray;
 +            cv::fastFree(chunksSizeAndLabels);
 +            cv::fastFree(P);
 +            return nLabels;
 +        }
 +    };//End struct LabelingGranaParallel
 +
-     // Based on \93Optimized  Block-based Connected Components Labeling with Decision Trees\94, Costantino Grana et al
++    // Based on ï¿½Optimized  Block-based Connected Components Labeling with Decision Trees�, Costantino Grana et al
 +    // Only for 8-connectivity
 +    template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
 +    struct LabelingGrana{
 +        LabelT operator()(const cv::Mat& img, cv::Mat& imgLabels, int connectivity, StatsOp& sop){
 +            CV_Assert(img.rows == imgLabels.rows);
 +            CV_Assert(img.cols == imgLabels.cols);
 +            CV_Assert(connectivity == 8);
 +
 +            const int h = img.rows;
 +            const int w = img.cols;
 +
 +            //A quick and dirty upper bound for the maximimum number of labels.
 +            //Following formula comes from the fact that a 2x2 block in 8-connectivity case
 +            //can never have more than 1 new label and 1 label for background.
 +            //Worst case image example pattern:
 +            //1 0 1 0 1...
 +            //0 0 0 0 0...
 +            //1 0 1 0 1...
 +            //............
 +            const size_t Plength = ((size_t(h) + 1) * (size_t(w) + 1)) / 4 + 1;
 +
 +            LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT) *Plength);
 +            P[0] = 0;
 +            LabelT lunique = 1;
 +
 +            // First scan
 +            for (int r = 0; r < h; r += 2) {
 +                // Get rows pointer
 +                const PixelT * const img_row = img.ptr<PixelT>(r);
 +                const PixelT * const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
 +                const PixelT * const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]);
 +                const PixelT * const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
 +                LabelT * const imgLabels_row = imgLabels.ptr<LabelT>(r);
 +                LabelT * const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
 +                for (int c = 0; c < w; c += 2) {
 +
 +                    // We work with 2x2 blocks
 +                    // +-+-+-+
 +                    // |P|Q|R|
 +                    // +-+-+-+
 +                    // |S|X|
 +                    // +-+-+
 +
 +                    // The pixels are named as follows
 +                    // +---+---+---+
 +                    // |a b|c d|e f|
 +                    // |g h|i j|k l|
 +                    // +---+---+---+
 +                    // |m n|o p|
 +                    // |q r|s t|
 +                    // +---+---+
 +
 +                    // Pixels a, f, l, q are not needed, since we need to understand the
 +                    // the connectivity between these blocks and those pixels only metter
 +                    // when considering the outer connectivities
 +
 +                    // A bunch of defines used to check if the pixels are foreground,
 +                    // without going outside the image limits.
 +#define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
 +#define condition_c r-2>=0 && img_row_prev_prev[c]>0
 +#define condition_d c+1<w&& r-2>=0 && img_row_prev_prev[c+1]>0
 +#define condition_e c+2<w  && r-1>=0 && img_row_prev[c-1]>0
 +
 +#define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
 +#define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
 +#define condition_i r-1>=0 && img_row_prev[c]>0
 +#define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
 +#define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
 +
 +#define condition_m c-2>=0 && img_row[c-2]>0
 +#define condition_n c-1>=0 && img_row[c-1]>0
 +#define condition_o img_row[c]>0
 +#define condition_p c+1<w && img_row[c+1]>0
 +
 +#define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
 +#define condition_s r+1<h && img_row_fol[c]>0
 +#define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
 +
 +                    // This is a decision tree which allows to choose which action to
 +                    // perform, checking as few conditions as possible.
 +                    // Actions: the blocks label are provisionally stored in the top left
 +                    // pixel of the block in the labels image
 +
 +                    if (condition_o) {
 +                        if (condition_n) {
 +                            if (condition_j) {
 +                                if (condition_i) {
 +                                    //Action_6: Assign label of block S
 +                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                    continue;
 +                                }
 +                                else {
 +                                    if (condition_c) {
 +                                        if (condition_h) {
 +                                            //Action_6: Assign label of block S
 +                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                            continue;
 +                                        }
 +                                        else {
 +                                            if (condition_g) {
 +                                                if (condition_b) {
 +                                                    //Action_6: Assign label of block S
 +                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_11: Merge labels of block Q and S
 +                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        //Action_11: Merge labels of block Q and S
 +                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                        continue;
 +                                    }
 +                                }
 +                            }
 +                            else {
 +                                if (condition_p) {
 +                                    if (condition_k) {
 +                                        if (condition_d) {
 +                                            if (condition_i) {
 +                                                //Action_6: Assign label of block S
 +                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                if (condition_c) {
 +                                                    if (condition_h) {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        if (condition_g) {
 +                                                            if (condition_b) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_12: Merge labels of block R and S
 +                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            //Action_12: Merge labels of block R and S
 +                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                            continue;
 +                                        }
 +                                    }
 +                                    else {
 +                                        //Action_6: Assign label of block S
 +                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                        continue;
 +                                    }
 +                                }
 +                                else {
 +                                    //Action_6: Assign label of block S
 +                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                    continue;
 +                                }
 +                            }
 +                        }
 +                        else {
 +                            if (condition_r) {
 +                                if (condition_j) {
 +                                    if (condition_m) {
 +                                        if (condition_h) {
 +                                            if (condition_i) {
 +                                                //Action_6: Assign label of block S
 +                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                continue;
 +                                            }
 +                                            else {
 +                                                if (condition_c) {
 +                                                    //Action_6: Assign label of block S
 +                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                        }
 +                                        else {
 +                                            if (condition_g) {
 +                                                if (condition_b) {
 +                                                    if (condition_i) {
 +                                                        //Action_6: Assign label of block S
 +                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        if (condition_c) {
 +                                                            //Action_6: Assign label of block S
 +                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                            continue;
 +                                                        }
 +                                                        else {
 +                                                            //Action_11: Merge labels of block Q and S
 +                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_11: Merge labels of block Q and S
 +                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                    else {
 +                                        if (condition_i) {
 +                                            //Action_11: Merge labels of block Q and S
 +                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                            continue;
 +                                        }
 +                                        else {
 +                                            if (condition_h) {
 +                                                if (condition_c) {
 +                                                    //Action_11: Merge labels of block Q and S
 +                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                                else {
 +                                                    //Action_14: Merge labels of block P, Q and S
 +                                                    imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);
 +                                                    continue;
 +                                                }
 +                                            }
 +                                            else {
 +                                                //Action_11: Merge labels of block Q and S
 +                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
 +                                                continue;
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                                else {
 +                                    if (condition_p) {
 +                                        if (condition_k) {
 +                                            if (condition_m) {
 +                                                if (condition_h) {
 +                                                    if (condition_d) {
 +                                                        if (condition_i) {
 +                                                            //Action_6: Assign label of block S
 +                                                            imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                            continue;
 +                                                        }
 +                                                        else {
 +                                                            if (condition_c) {
 +                                                                //Action_6: Assign label of block S
 +                                                                imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        //Action_12: Merge labels of block R and S
 +                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_d) {
 +                                                        if (condition_g) {
 +                                                            if (condition_b) {
 +                                                                if (condition_i) {
 +                                                                    //Action_6: Assign label of block S
 +                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    if (condition_c) {
 +                                                                        //Action_6: Assign label of block S
 +                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
 +                                                                        continue;
 +                                                                    }
 +                                                                    else {
 +                                                                        //Action_12: Merge labels of block R and S
 +                                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                        continue;
 +                                                                    }
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                    else {
 +                                                        if (condition_i) {
 +                                                            if (condition_g) {
 +                                                                if (condition_b) {
 +                                                                    //Action_12: Merge labels of block R and S
 +                                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                                else {
 +                                                                    //Action_16: labels of block Q, R and S
 +                                                                    imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                    continue;
 +                                                                }
 +                                                            }
 +                                                            else {
 +                                                                //Action_16: labels of block Q, R and S
 +                                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_12: Merge labels of block R and S
 +                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                            continue;
 +                                                        }
 +                                                    }
 +                                                }
 +                                            }
 +                                            else {
 +                                                if (condition_i) {
 +                                                    if (condition_d) {
 +                                                        //Action_12: Merge labels of block R and S
 +                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                        continue;
 +                                                    }
 +                                                    else {
 +                                                        //Action_16: labels of block Q, R and S
 +                                                        imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                        continue;
 +                                                    }
 +                                                }
 +                                                else {
 +                                                    if (condition_h) {
 +                                                        if (condition_d) {
 +                                                            if (condition_c) {
 +                                                                //Action_12: Merge labels of block R and S
 +                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                            else {
 +                                                                //Action_15: Merge labels of block P, R and S
 +                                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
 +                                                                continue;
 +                                                            }
 +                                                        }
 +                                                        else {
 +                                                            //Action_15: Merge labels of block P, R and S
 +                                                            imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
                                                              continue;
                                                          }
                                                      }