图像连通域分析(Two-Pass & DFS )

参考博客:http://blog.csdn.net/icvpr/article/details/10259577#reply
two-pass法原文中的代码有错误,添加了并查集数据结构后得以解决。
DFS方法无误。
本文代码的作用是,寻找图片中的所以连通域,并保留面积最大的连通域,其他区域删除。

#include <iostream>  
#include <opencv2\highgui\highgui.hpp>  
#include <opencv2\core\core.hpp>  
#include <opencv2\imgproc\imgproc.hpp>  
#include <map>  
#include <stack>
#include <string>  
#include <list>    
#include <stdio.h>
#include <time.h>


using namespace std;
using namespace cv; 

void myFillSeedFill(const Mat& _binImg, Mat& _labelImg) {
    if(_binImg.empty() || _binImg.type() != CV_8UC1) {
        return;
    }

    _labelImg.release();
    _binImg.convertTo(_labelImg, CV_32SC1);

    int label = 1;
    int rows = _binImg.rows;
    int cols = _binImg.cols;

    vector<pair<int, int>> area;
    int maxLabel = 0;
    int maxLabelNum = 0;

    for(int i = 0; i < rows; ++i) {
        int * p = _labelImg.ptr<int>(i);
        for(int j = 0; j < cols; ++j) {
            if(p[j] == 1) {
                stack<pair<int, int>> s;
                s.push(pair<int, int>(i, j));
                ++label;
                int curLabelNum = 0;
                while(!s.empty()) {
                    pair<int, int> curPix = s.top();
                    int curX = curPix.first;
                    int curY = curPix.second;

                    int * curxptr = _labelImg.ptr<int>(curX);
                    curxptr[curY] = label;

                    //_labelImg.at<int>(curX, curY) = label;
                    ++curLabelNum;
                    s.pop();


                    if(curX-1 >= 0) {
                        int * prexptr = _labelImg.ptr<int>(curX-1);
                        if(prexptr[curY] == 1) {
                            s.push(pair<int, int>(curX-1, curY));
                        }
                    }
                    if(curY-1 >= 0) {
                        //int * prexptr = _labelImg.ptr<int>(curX-1);
                        if(curxptr[curY-1] == 1) {
                            s.push(pair<int, int>(curX, curY-1));
                        }
                    }
                    if(curX+1 < rows) {
                        int * latexptr = _labelImg.ptr<int>(curX+1);
                        if(latexptr[curY] == 1) {
                            s.push(pair<int, int>(curX+1, curY));
                        }
                    }
                    if(curY+1 < cols) {
                        //int * prexptr = _labelImg.ptr<int>(curX-1);
                        if(curxptr[curY+1] == 1) {
                            s.push(pair<int, int>(curX, curY+1));
                        }
                    }
                }
                if(curLabelNum > maxLabelNum) {
                    maxLabelNum = curLabelNum;
                    maxLabel = label;
                }
            }
        }
    }

    for(int i = 0; i < rows; ++i) {
        int * p = _labelImg.ptr<int>(i);
        for(int j = 0; j < cols; ++j) {
            if(p[j] == maxLabel) {
                p[j] = 255;
            }
            else {
                p[j] = 0;
            }
        }
    }

    //总耗时: 0.5秒
}


int father[100000];
vector<int> labelCnt(1000, 0);

void make() {
    for(int i = 0; i < 100000; ++i) {
        father[i] = i;
    }
}

int Find_Set(int x) {
    if(x != father[x]) {
        father[x] = Find_Set(father[x]);
    }
    return father[x];
}

void Union(int x, int y) {
    int fx = Find_Set(x);
    int fy = Find_Set(y);
    if(fx == fy) {
        return;
    }
    father[fy] = fx;
}

void icvprCcaByTwoPass(const cv::Mat& _binImg, cv::Mat& _lableImg)  
{  
    // connected component analysis (4-component)  
    // use two-pass algorithm  
    // 1. first pass: label each foreground pixel with a label  
    // 2. second pass: visit each labeled pixel and merge neighbor labels  
    //   
    // foreground pixel: _binImg(x,y) = 1  
    // background pixel: _binImg(x,y) = 0  


    if (_binImg.empty() ||  
        _binImg.type() != CV_8UC1)  
    {  
        return ;  
    }  

    // 1. first pass  

    _lableImg.release() ;  
    _binImg.convertTo(_lableImg, CV_32SC1) ;  

    int label = 1 ;  // start by 2  
    std::vector<int> labelSet;  
    labelSet.push_back(0) ;   // background: 0  
    labelSet.push_back(1) ;   // foreground: 1  

    int rows = _binImg.rows;  
    int cols = _binImg.cols;
    int* data_firstRows = _lableImg.ptr<int>(0);
    if(data_firstRows[0] == 1) {
        data_firstRows[0] = ++label;
        labelSet.push_back(label);
    }
    for (int j = 1; j < cols; ++j) {  //第一行初始化label
        if(data_firstRows[j] == 1) {
            if(data_firstRows[j-1] > 0) {
                data_firstRows[j] == data_firstRows[j-1];
            } else {
                data_firstRows[j] = ++label;
                labelSet.push_back(label);
            }
        }
    }
    for(int j = 1; j < rows; ++j) {   //第一列初始化label
        if(_lableImg.at<int>(j, 0) == 1) {
            if(_lableImg.at<int>(j-1, 0) > 0) {
                _lableImg.at<int>(j, 0) = _lableImg.at<int>(j-1, 0);
            } else {
                _lableImg.at<int>(j, 0) = ++label;
                labelSet.push_back(label);
            }
        }
    }
    //label = 1;
    make();
    for (int i = 1; i < rows; i++)  
    {  
        int* data_preRow = _lableImg.ptr<int>(i-1) ;  
        int* data_curRow = _lableImg.ptr<int>(i) ;  
        for (int j = 1; j < cols; j++)  
        {  
            if (data_curRow[j] == 1)  
            {  
                std::vector<int> neighborLabels;  
                neighborLabels.reserve(2);  
                int leftPixel = data_curRow[j-1];  
                int upPixel = data_preRow[j];  
                if ( leftPixel > 1)  
                {  
                    neighborLabels.push_back(leftPixel) ;  
                }  
                if (upPixel > 1)  
                {  
                    neighborLabels.push_back(upPixel) ;  
                }  

                if (neighborLabels.empty())  
                {  
                    labelSet.push_back(++label) ;  // assign to a new label  
                    data_curRow[j] = label ;  
                    labelSet[label] = label ;  
                }  
                else  
                {  
                    std::sort(neighborLabels.begin(), neighborLabels.end());  
                    int smallestLabel = neighborLabels[0];    
                    data_curRow[j] = smallestLabel;  

                    for(size_t k = 1; k < neighborLabels.size(); k++) {
                        int tmpLabel = neighborLabels[k];

                        Union(tmpLabel, smallestLabel);
                        Union(smallestLabel, tmpLabel);
                    }

                }                 
            }  
        }  
    }  


    // 2. second pass  
    for (int i = 0; i < rows; i++)  
    {  
        int* data = _lableImg.ptr<int>(i) ;  
        for (int j = 0; j < cols; j++)  
        {  
            data[j] = Find_Set(data[j]);
            if(data[j] != 0) {
                labelCnt[data[j]]++;
            }
        }  
    }
    vector<int>::iterator maxLabel = max_element(labelCnt.begin(), labelCnt.end());
    cout << *maxLabel << endl;
    int maxL = distance(labelCnt.begin(), maxLabel);
    cout << maxL << endl;

    for (int i = 0; i < rows; i++) {  
        int* data = _lableImg.ptr<int>(i) ;  
        for (int j = 0; j < cols; j++) {
            if(data[j] == maxL) {
                data[j] = 255;
            } else {
                data[j] = 0;
            }
        }
    }

}


cv::Scalar icvprGetRandomColor()  
{  
    uchar r = 255 * (rand()/(1.0 + RAND_MAX));  
    uchar g = 255 * (rand()/(1.0 + RAND_MAX));  
    uchar b = 255 * (rand()/(1.0 + RAND_MAX));  
    return cv::Scalar(b,g,r) ;  
}  


void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg)   
{  
    if (_labelImg.empty() ||  
        _labelImg.type() != CV_32SC1)  
    {  
        return ;  
    }  

    std::map<int, cv::Scalar> colors ;  

    int rows = _labelImg.rows ;  
    int cols = _labelImg.cols ;  

    _colorLabelImg.release() ;  
    _colorLabelImg.create(rows, cols, CV_8UC3) ;  
    _colorLabelImg = cv::Scalar::all(0) ;  

    for (int i = 0; i < rows; i++)  
    {  
        const int* data_src = (int*)_labelImg.ptr<int>(i) ;  
        uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ;  
        for (int j = 0; j < cols; j++)  
        {  
            int pixelValue = data_src[j] ;  
            if (pixelValue > 1)  
            {  
                if (colors.count(pixelValue) <= 0)  
                {  
                    colors[pixelValue] = icvprGetRandomColor() ;  
                }  
                cv::Scalar color = colors[pixelValue] ;  
                *data_dst++   = color[0] ;  
                *data_dst++ = color[1] ;  
                *data_dst++ = color[2] ;  
            }  
            else  
            {  
                data_dst++ ;  
                data_dst++ ;  
                data_dst++ ;  
            }  
        }  
    }  
}  

int main()  
{  
    time_t t_start, t_end;
   /* Mat img, res;  */
    Mat binImage = imread("segmentationMask_bad.jpg",0);    //将读入的彩色图像直接以灰度图像读入
    //Mat binImage = imread("liantongyu.jpg",0);   //小图,在递归调用中可用,图太大则只能使用TwoPass方法
    //Mat binImage = imread("connect2.jpg",0);  
    Mat showimg;


    showimg.release() ;  
    binImage.convertTo(showimg, CV_8UC1) ;  
    for(int i = 0; i < showimg.rows; ++i) {
        uchar * p = showimg.ptr<uchar>(i);
        for(int j = 0; j < showimg.cols; ++j) {
            if(p[j] > 50)
                p[j] = 225;
            else
                p[j] = 0;
        }
    }

    cv::imshow("showing", showimg);

    //cv::Mat binImage = cv::imread("../icvpr.com.jpg", 0) ;  
    //cv::threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV) ;  
    for(int i = 0; i < binImage.rows; ++i) {
        uchar * p = binImage.ptr<uchar>(i);
        for(int j = 0; j < binImage.cols; ++j) {
            if(p[j] > 50)
                p[j] = 1;
            else
                p[j] = 0;
        }
    }


    // connected component labeling  
    cv::Mat labelImg ;  

    t_start = clock();
    //icvprCcaByTwoPass(binImage, labelImg) ;         // cost 0.184s
    myFillSeedFill(binImage, labelImg);             // cost 0.526s


    t_end = clock();
    double duration = (double)(t_end - t_start) / CLOCKS_PER_SEC;
    cout << "cost " << duration << " s" << endl;



    // show result  
    cv::Mat grayImg ;  
    //labelImg *= 10 ;  
    labelImg.convertTo(grayImg, CV_8UC1) ;  
    cv::imshow("labelImg", grayImg) ;  

    cv::Mat colorLabelImg ;  
    icvprLabelColor(labelImg, colorLabelImg) ;  
    cv::imshow("colorImg", colorLabelImg) ;  
    cv::waitKey(0) ;  

    return 0 ;  
}

猜你喜欢

转载自blog.csdn.net/nichchen/article/details/78690772
dfs