经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。 |
分水岭算法与漫水填充法相似,都是模拟水淹过山地的场景,区别是漫水填充法是从局部某个像素值进行分割,是一种局部分割算法,而分水岭法是从全局出发,需要对全局都进行分割。
分水岭算法会在多个局部最低点开始注水,随着注水量的增加,水位越来越高会淹没局部像素值较小的像素点,最后两个相邻的凹陷区域的水会汇集在一起,并在汇集处形成了分水岭。分水岭的计算过程是一个迭代标注的过程,经典的计算方式主要分为以下两个步骤:
OpenCV 4提供了用于实现分水岭法分割图像的watershed()函数,该函数的函数原型在代码清单8-19中给出。
代码清单8-19 watershed()函数原型
void cv::watershed(InputArray image,
InputOutputArray markers
)
该函数根据期望标记结果实现图像分水岭分割。函数的第一个参数是需要进行分水岭分割的图像,该图像必须是CU_8U的三通道彩色图像。函数第二个参数用于输入期望分割的区域,在将图像传递给函数之前,必须使用大于0的整数索引粗略的勾画图像期望分割的区域。因此,每个标记的区域被表示为具有像素值1、2、3等的一个或多个连通分量。标记图像的尺寸与输入图像相同且数据类型为CV_32S,可以使用findContours()函数和drawContours()函数从二值掩码中得到此类标记图像,标记图像中所有没有被标记的像素值都为0。在函数输出时,两个区域之间的分割线用-1表示。
为了了解该函数的用法,在代码清单8-20中给出了利用watershed()函数对图像进行分割的示例程序。程序中通过图像的边缘区域对图像进行标记,首先利用Canny()函数计算图像的边缘,之后利用findContours()函数计算图像中的连通域,并通过drawContours()函数绘制连通域得到符合格式要求的标记图像,最后利用watershed()函数对图像进行分割。为了增加分割后不同区域之间的对比度,随机对不同区域进行上色,结果如图8-12所示,同时提取原图像中每个被分割的区域,部分结果在图8-13给出。
代码清单8-20 myWatershed.cpp分水岭法分割图像
1. #include <opencv2\opencv.hpp>
2. #include <iostream>
3.
4. using namespace std;
5. using namespace cv;
6.
7. int main()
8. {
9. Mat img, imgGray, imgMask;
10. Mat maskWaterShed; // watershed()函数的参数
11. img = imread("HoughLines.jpg"); //原图像
12. if (img.empty())
13. {
14. cout << "请确认图像文件名称是否正确" << endl;
15. return -1;
16. }
17. cvtColor(img, imgGray, COLOR_BGR2GRAY);
18. //GaussianBlur(imgGray, imgGray, Size(5, 5), 10, 20); //模糊用于减少边缘数目
19.
20. //提取边缘并进行闭运算
21. Canny(imgGray, imgMask, 150, 300);
22. //Mat k = getStructuringElement(0, Size(3, 3));
23. //morphologyEx(imgMask, imgMask, MORPH_CLOSE, k);
24.
25. imshow("边缘图像", imgMask);
26. imshow("原图像", img);
27.
28. //计算连通域数目
29. vector<vector<Point>> contours;
30. vector<Vec4i> hierarchy;
31. findContours(imgMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
32.
33. //在maskWaterShed上绘制轮廓,用于输入分水岭算法
34. maskWaterShed = Mat::zeros(imgMask.size(), CV_32S);
35. for (int index = 0; index < contours.size(); index++)
36. {
37. drawContours(maskWaterShed, contours, index, Scalar::all(index + 1),
38. -1, 8, hierarchy, INT_MAX);
39. }
40. //分水岭算法 需要对原图像进行处理
41. watershed(img, maskWaterShed);
42.
43. vector<Vec3b> colors; // 随机生成几种颜色
44. for (int i = 0; i < contours.size(); i++)
45. {
46. int b = theRNG().uniform(0, 255);
47. int g = theRNG().uniform(0, 255);
48. int r = theRNG().uniform(0, 255);
49. colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
50. }
51.
52. Mat resultImg = Mat(img.size(), CV_8UC3); //显示图像
53. for (int i = 0; i < imgMask.rows; i++)
54. {
55. for (int j = 0; j < imgMask.cols; j++)
56. {
57. // 绘制每个区域的颜色
58. int index = maskWaterShed.at<int>(i, j);
59. if (index == -1) // 区域间的值被置为-1(边界)
60. {
61. resultImg.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
62. }
63. else if (index <= 0 || index > contours.size()) // 没有标记清楚的区域被置为0
64. {
65. resultImg.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
66. }
67. else // 其他每个区域的值保持不变:1,2,…,contours.size()
68. {
69. resultImg.at<Vec3b>(i, j) = colors[index - 1]; // 把些区域绘制成不同颜色
70. }
71. }
72. }
73.
74. resultImg = resultImg * 0.6 + img * 0.4;
75. imshow("分水岭结果", resultImg);
76.
77. //绘制每个区域的图像
78. for (int n = 1; n <= contours.size(); n++)
79. {
80. Mat resImage1 = Mat(img.size(), CV_8UC3); // 声明一个最后要显示的图像
81. for (int i = 0; i < imgMask.rows; i++)
82. {
83. for (int j = 0; j < imgMask.cols; j++)
84. {
85. int index = maskWaterShed.at<int>(i, j);
86. if (index == n)
87. resImage1.at<Vec3b>(i, j) = img.at<Vec3b>(i, j);
88. else
89. resImage1.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
90. }
91. }
92. //显示图像
93. imshow(to_string(n), resImage1);
94. }
95.
96. waitKey(0);
97. return 0;
98. }
OpenCV 4开发详解 |
往期推荐 |
---|
【OpenCV 4开发详解】图像模板匹配 |
【OpenCV 4开发详解】图像卷积 |
【OpenCV 4开发详解】图像噪声的种类与生成 |
【OpenCV 4开发详解】均值滤波 |
【OpenCV 4开发详解】方框滤波 |
【OpenCV 4开发详解】高斯滤波 |
【OpenCV 4开发详解】可分离滤波 |
【OpenCV 4开发详解】中值滤波 |
【OpenCV 4开发详解】边缘检测原理 |
【OpenCV 4开发详解】Scharr算子 |
【OpenCV 4开发详解】Laplacian算子 |
【OpenCV 4开发详解】Canny算法 |
【OpenCV 4开发详解】图像距离变换 |
【OpenCV 4开发详解】图像连通域分析 |
【OpenCV 4开发详解】图像腐蚀 |
【OpenCV 4开发详解】图像膨胀 |
【OpenCV 4开发详解】形态学应用 |
【OpenCV 4开发详解】检测直线 |
【OpenCV 4开发详解】直线拟合 |
【OpenCV 4开发详解】直线检测 |
【OpenCV 4开发详解】轮廓发现与绘制 |
【OpenCV 4开发详解】轮廓面积与长度 |
【OpenCV 4开发详解】图像矩的计算与应用 |
【OpenCV 4开发详解】点集拟合 |
【OpenCV 4开发详解】QR二维码检测 |
【OpenCV 4开发详解】分割图像——漫水填充法 |
经过几个月的努力,市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》将春节后由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持! |
关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。 |