• oepncv c++ 连通组件扫描


    1、概念

            连通组件指在图像上通过四邻域八邻域法,连接起来的像素值大于某一阈值的区域(这些像素点被称为前景像素),而小于阈值的区域被称为背景。如下图的4个连通组件。

             四邻域、八邻域:

     

    2、常用算法

    a)基于像素的扫描方法                                      b)基于块的扫描方法

     说明:与卷积类似,利用上述模板在图像上平移扫描前景像素,则扫描区域内其余的前景像素与当前像素连通。

     c)两步法扫描

            1、同样采用像素模板对图像进行扫描,给予其标记,并获得等价队列(连通的不同标记队列)。

            

             2、将一个等价队列中的标记全部置为最小标记值,如上{1,3,5}队列全置为1。

            

    d)opencv中的连通组件扫描算法——BBDT

    c_{1}true判定:

            将上图左边的块模板分为右边所示的大块分区P、Q、R、S、X。要获取块X与块P连通的结论(c_{1}),则需满足,小像素点h和o均为前景像素。

    3、代码示例:

    3.1、 API:

    1. int cv::connectedComponents ( InputArray image,
    2. OutputArray labels,
    3. int connectivity,
    4. int ltype,
    5. int ccltype
    6. )
    1. int cv::connectedComponentsWithStats( InputArray image,
    2. OutputArray labels,
    3. OutputArray stats,
    4. OutputArray centroids,
    5. int connectivity,
    6. int ltype,
    7. int ccltype
    8. )

    labels——带标记的与输入图像同大小类型的图像。 

    stats——每个连通组件的(包括背景)的外接矩形信息,具体如下:

     centroids——每个连通组件的(包括背景)的中心坐标信息,数据类型为CV_64F

    connectivity——邻域连通方法,4/8邻域。

    ltype——输出label图像类型,目前仅有CV_32S 和CV_16U类型可选用。

    ccltype ——连通组件扫描方法,可选用如下方法:

     connectedComponents 示例:

    1. void QuickDemo::scan_neighbor(Mat& image)
    2. {
    3. //高斯模糊
    4. GaussianBlur(image, image, Size(3, 3), 0);
    5. Mat gray;
    6. cvtColor(image, gray, COLOR_BGR2GRAY);
    7. Mat binary;
    8. threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    9. namedWindow("adaptiveThreshold", WINDOW_FREERATIO);
    10. imshow("adaptiveThreshold", binary);
    11. Mat labels = Mat::zeros(binary.size(), binary.type());
    12. int num_label = connectedComponents(binary, labels, 8, CV_32S, CCL_DEFAULT);
    13. //显示labels
    14. //1、生成颜色数组
    15. RNG rng(12345);
    16. vector colorTable(num_label);//定义一个num_label维度的空数组
    17. colorTable[0] = Vec3b(0, 0, 0);//将背景颜色置为黑色
    18. for (int i = 1; i < num_label; ++i) {
    19. //对其余标签赋予颜色数据
    20. colorTable[i] = Vec3b(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    21. }
    22. Mat result = Mat::zeros(image.size(), image.type());
    23. //2、通过循环对不同的标签填入随机生成的颜色
    24. int h = image.rows, w = image.cols;
    25. for (int row = 0; row < h; ++row) {
    26. for (int col= 0; col < w; ++col) {
    27. int label = labels.at<int>(row, col);//将labels图像上对应像素坐标上的标记值取出
    28. result.at(row, col) = colorTable[label];//将result图像上对应像素坐标赋予颜色
    29. }
    30. }
    31. //在图像上显示有多少个字体
    32. putText(result, format("number of %d", num_label - 1), Point(50, 50), FONT_HERSHEY_PLAIN, 3, Scalar(0, 50, 70), 1);
    33. namedWindow("labels", WINDOW_FREERATIO);
    34. imshow("labels", result);
    35. }

    connectedComponentsWithStats示例:

    1. void QuickDemo::scan_neighbor(Mat& image)
    2. {
    3. //高斯模糊
    4. GaussianBlur(image, image, Size(3, 3), 0);
    5. Mat gray;
    6. cvtColor(image, gray, COLOR_BGR2GRAY);
    7. Mat binary;
    8. threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    9. namedWindow("adaptiveThreshold", WINDOW_FREERATIO);
    10. imshow("adaptiveThreshold", binary);
    11. Mat labels = Mat::zeros(binary.size(), binary.type());
    12. Mat stats, centroids;
    13. int num_label = connectedComponentsWithStats(binary, labels,stats,centroids, 8, CV_32S, CCL_DEFAULT);
    14. //显示labels
    15. //1、生成颜色数组
    16. RNG rng(12345);
    17. vector colorTable(num_label);//定义一个num_label维度的空数组
    18. colorTable[0] = Vec3b(0, 0, 0);//将背景颜色置为黑色
    19. for (int i = 1; i < num_label; ++i) {
    20. //对其余标签赋予颜色数据
    21. colorTable[i] = Vec3b(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    22. }
    23. Mat result = Mat::zeros(image.size(), image.type());
    24. //2、通过循环对不同的标签填入随机生成的颜色
    25. int h = image.rows, w = image.cols;
    26. for (int row = 0; row < h; ++row) {
    27. for (int col = 0; col < w; ++col) {
    28. int label = labels.at<int>(row, col);//将labels图像上对应像素坐标上的标记值取出
    29. result.at(row, col) = colorTable[label];//将result图像上对应像素坐标赋予颜色
    30. }
    31. }
    32. //绘制外接矩形和中心点圆
    33. for (int i = 1; i < num_label; ++i) {
    34. //先获取连接组件的中心坐标
    35. int cx = centroids.at<double>(i, 0);
    36. int cy = centroids.at<double>(i, 1);
    37. int x = stats.at<int>(i, CC_STAT_LEFT);//矩形左边界与整个图像左边的距离
    38. int y = stats.at<int>(i, CC_STAT_TOP);//矩形上边界与整个图像上边的距离
    39. int width = stats.at<int>(i, CC_STAT_WIDTH);//矩形宽度
    40. int height = stats.at<int>(i, CC_STAT_HEIGHT);//矩形高度
    41. int area = stats.at<int>(i, CC_STAT_AREA);//矩形面积
    42. //绘制
    43. circle(result, Point(cx, cy), 3, Scalar(0, 0, 255), 2, 8);
    44. // 外接矩形
    45. Rect box(x, y, width, height);
    46. rectangle(result, box, Scalar(0, 255, 0), 2, 8);
    47. putText(result, format("%d", area), Point(x, y), FONT_HERSHEY_PLAIN, 3, Scalar(0, 50, 70), 1);
    48. }
    49. namedWindow("labels", WINDOW_FREERATIO);
    50. imshow("labels", result);
    51. }

     

     

  • 相关阅读:
    雾锁王国服务器一键部署教程
    岩土工程安全监测中振弦采集仪连接振弦传感器时注意事项
    Lua语法结构
    【C++】缺省参数 函数重载 内联函数
    java计算机毕业设计物流管理系统源代码+数据库+系统+lw文档
    【图像处理】德里奇( Deriche)边缘检测器
    记录 ubuntu 硬盘分区跟格式化(fdisk命令)
    阿里云CentOS环境之docker安装,启动,加速器,docker-compose(十四)
    [CISCN 2019 初赛]Love Math
    数据结构之AVL树
  • 原文地址:https://blog.csdn.net/lucust/article/details/128151523