您的位置:首页 > 运维架构

OpenCV 扫描标记法求连通区域面积

2017-08-25 20:04 204 查看
扫描标记的时候 没有选择用Two-Pass(两遍扫描法),而是用Seed-Filling(种子填充法)。

扫描标记中最需要注意点:

1.首先说明我的图片是黑色底,白色目标物。

2.icvprCcaBySeedFill函数扫描全图一遍以后,不同的连通区域就已经分配了一个唯一且不同的标记号。

3.接下来icvprLabelColor函数也是把全图扫描一遍,然后依次判断每一个像素点的值,并都赋给pixelValue
,如果这个值为1,就说明是1号连通区,为2,就说明是2号连通区。

4.为了求面积,在判断像素点的值的时候,加入了count变量,作为计数器。发现一个1号连通区的像素点,count值就加1,以此得出1号连通区的像素点数,其他连通区以此类推。

5.如果你的图片是白色底,黑色的目标物,那么在(data[j]
== 0), if (_lableImg.at<int>(curX, curY-1) == 0)  和下面3个4连通的判断中,一定要把0改成1,而且还要把threshold(binImage,
binImage, 50,255, CV_THRESH_BINARY_INV) ; 中的255改成1,不然调不出来。

6.代码是照抄其他博客的,不知道这算不算原创。不过count++这个是我自己想的
哈哈。亲测可用。

#include <iostream>  

#include <string>  

#include <list>  

#include <vector>  

#include <map>  

#include <stack>

#include <opencv2/imgproc/imgproc.hpp>  

#include <opencv2/highgui/highgui.hpp>  

#include<opencv2/opencv.hpp>

using namespace cv;

using namespace std;

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 Scalar(b,g,r) ;  

}  

  

  

void icvprLabelColor(Mat& _labelImg, Mat& _colorLabelImg)   

{  
int count=0;

    if (_labelImg.empty() ||  

        _labelImg.type() != CV_32SC1)  

    {  

        return ;  

    }  

  

    map<int, Scalar> colors ;  

  

    int rows = _labelImg.rows ;  

    int cols = _labelImg.cols ;  

  

    _colorLabelImg.release() ;  

    _colorLabelImg.create(rows, cols, CV_8UC3) ;  

    _colorLabelImg = 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 == 3)  //pixelValue是标记号

            {  
count++;//数像素点

                if (colors.count(pixelValue) <= 0)  

                {  

                    colors[pixelValue] = icvprGetRandomColor() ;  

                }  

                Scalar color = colors[pixelValue] ;  

                *data_dst++ = color[0] ;  

                *data_dst++ = color[1] ;  

                *data_dst++ = color[2] ;  

            }  

            else  

            {  

                data_dst++ ;  

                data_dst++ ;  

                data_dst++ ;  

            }  

        } 

    }
printf("%d",count);

}

void icvprCcaBySeedFill(Mat& _binImg,Mat& _lableImg)  

{  

    // connected component analysis (4-component)  

    // use seed filling algorithm  

    // 1. begin with a foreground pixel and push its foreground neighbors into a stack;  

    // 2. pop the top pixel on the stack and label it with the same label until the stack is empty  

    //   

    // foreground pixel: _binImg(x,y) = 1  

    // background pixel: _binImg(x,y) = 0  

  

  

    if (_binImg.empty() ||  

        _binImg.type() != CV_8UC1)  

    {  

        return ;  

    }  

  

    _lableImg.release() ;  

    _binImg.convertTo(_lableImg, CV_32SC1) ;  

  

    int label = 1 ;  // start by 2  

  

    int rows = _binImg.rows - 1 ;  

    int cols = _binImg.cols - 1 ;  

    for (int i = 1; i < rows-1; i++)  

    {  

        int* data= _lableImg.ptr<int>(i) ;  

        for (int j = 1; j < cols-1; j++)  

        {  

            if (data[j] == 0)

            {  

                stack<pair<int,int>> neighborPixels ;     

                neighborPixels.push(pair<int,int>(i,j)) ;     // pixel position: <i,j>  

                ++label ;  // begin with a new label  

                while (!neighborPixels.empty())  

                {  

                    // get the top pixel on the stack and label it with the same label  

                    pair<int,int> curPixel = neighborPixels.top() ;  

                    int curX = curPixel.first ;  

                    int curY = curPixel.second ;  

                    _lableImg.at<int>(curX, curY) = label ;  

  

                    // pop the top pixel  

                    neighborPixels.pop() ;  

  

                    // push the 4-neighbors (foreground pixels)  

                    if (_lableImg.at<int>(curX, curY-1) == 0)  

                    {// left pixel  

                        neighborPixels.push(pair<int,int>(curX, curY-1)) ;  

                    }  

                    if (_lableImg.at<int>(curX, curY+1) == 0)  

                    {// right pixel  

                        neighborPixels.push(pair<int,int>(curX, curY+1)) ;  

                    }  

                    if (_lableImg.at<int>(curX-1, curY) == 0)  

                    {// up pixel  

                        neighborPixels.push(pair<int,int>(curX-1, curY)) ;  

                    }  

                    if (_lableImg.at<int>(curX+1, curY) == 0)  

                    {// down pixel  

                        neighborPixels.push(pair<int,int>(curX+1, curY)) ;  

                    }  

                }         

            }  

        }  

    }  

}

int main(int argc, char** argv)  

{  

    Mat binImage = imread("D:\\VS2012\\Work\\test7\\test7\\9.jpg", 0) ;  //你自己改地址
imshow("原图", binImage) ;  

    threshold(binImage, binImage, 50,255, CV_THRESH_BINARY_INV) ;  

    Mat labelImg ;  

    icvprCcaBySeedFill(binImage, labelImg) ;  

    Mat colorLabelImg ;  

    icvprLabelColor(labelImg, colorLabelImg) ;  

    imshow("区域标记", colorLabelImg) ;  

    waitKey(0) ;  

  

    return 0 ;  
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: