openCV检测连通域

Posted on 2016-06-18

這一段时间在做研读的论文的实现工作,期间一下用了很多opencv的知识,希望后续会有时间把所学的写成一个系列。

opencv作为一个图像处理库在图像分割,特征提取,人脸识别,计算机视觉领域中应用广泛,今天写一个关于采用opencv对图像连通域检测的demo

前期也是翻阅了很多资料,常见的有two-pass,Seed-Filling等算法。

相关资料贴一下: Connected Component Analysis/Labeling

以及這篇: 几种联通区域标记的算法介绍

手动编写的那篇的代码有bug,检测结果不很正确,后来查阅opencv的官方文档,在3.x的版本中,這些都被封装起来了。

第一种:

CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels,
                                 int connectivity = 8, int ltype = CV_32S);
  • image– 需要被标记的图像
  • labels–标记后的目标图像
  • connectivity–采用四邻域还是八邻域检测
  • ltype = CV_32S–支持的Mat图像的类型

第二种:

CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labels,
                                          OutputArray stats, OutputArray centroids,
                                          int connectivity = 8, int ltype = CV_32S);

其中多两个参数:

  • stats–获取关于label区域的其它信息,比如极端(最左最右出的像素坐标)
  • centroids–每一个label区域的中心,也包括背景label.返回一个(x,y)坐标

代码奉上:    

include <opencv2/opencv.hpp>
include <opencv_lib.hpp>
include <iostream>
include <vector>

using namespace cv;
using namespace std;

int main()
{
    //载入图像
    Mat img = imread("labeling_img.jpg");

    //判断是否为空
    if (img.empty())
    {
        cout << "Could not read input image file" << endl;
        return -1;
    }

    //声明Mat对象,作二值化用
    Mat gray, bin;

    //灰度变换
    cvtColor(img, gray, CV_BGR2GRAY);

    //2値化
    threshold(gray, bin, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    //申明对象,存储结果图像
    Mat labelImage(img.size(), CV_32S);

    //记录联通区域的数目,8为8领域
    int nLabels = connectedComponents(bin, labelImage, 8);

    //声明vector,类型为opencv 中的vec3b类型,存放不同联通区域的着色
    vector<Vec3b> colors(nLabels);

    //背景黑色
    colors[0] = Vec3b(0, 0, 0);

    //对于由不同lable标记的联通区域,进行随机上色
    for (int label = 1; label < nLabels; label++)
    {
        colors[label] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255));
    }

    //dst存储最终上色的标记图像
    Mat dst(img.size(), CV_8UC3);


    for (int r = 0; r < dst.rows; r++)
    {
        for (int c = 0; c < dst.cols; c++)
        {
            int label = labelImage.at<int>(r, c);
            Vec3b &pixel = dst.at<Vec3b>(r, c);
            pixel = colors[label];
        }
    }

    //显示原图
    imshow("img", img);

    //結果图像表示
    imshow("Connected Components", dst);

    
    waitKey();

    return 0;
    
}

(因为截图什么的大小不一致,原则上两幅图像是一致的 )

web_spider(2)input.png

web_spider(2)output.png

如果需要知道更多信息,可以将上个demo中的代码段,换成第二种函数

for (int label = 1; label < nLabels; ++label){
		colors[label] = cv::Vec3b((std::rand() & 255), (std::rand() & 255), (std::rand() & 255));
		std::cout << "Component " << label << std::endl;
		std::cout << "CC_STAT_LEFT   = " << stats.at<int>(label, cv::CC_STAT_LEFT) << std::endl;
		std::cout << "CC_STAT_TOP    = " << stats.at<int>(label, cv::CC_STAT_TOP) << std::endl;
		std::cout << "CC_STAT_WIDTH  = " << stats.at<int>(label, cv::CC_STAT_WIDTH) << std::endl;
		std::cout << "CC_STAT_HEIGHT = " << stats.at<int>(label, cv::CC_STAT_HEIGHT) << std::endl;
		std::cout << "CC_STAT_AREA   = " << stats.at<int>(label, cv::CC_STAT_AREA) << std::endl;
		std::cout << "CENTER   = (" << centroids.at<double>(label, 0) << "," << centroids.at<double>(label, 1) << ")" << std::endl << std::endl;
	}

蚊子再小也是肉~
本站总访问量 本站访客数