| 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。 |
分水岭算法与漫水填充法相似,都是模拟水淹过山地的场景,区别是漫水填充法是从局部某个像素值进行分割,是一种局部分割算法,而分水岭法是从全局出发,需要对全局都进行分割。
分水岭算法会在多个局部最低点开始注水,随着注水量的增加,水位越来越高会淹没局部像素值较小的像素点,最后两个相邻的凹陷区域的水会汇集在一起,并在汇集处形成了分水岭。分水岭的计算过程是一个迭代标注的过程,经典的计算方式主要分为以下两个步骤:
- Step1:排序过程,首先对图像像素的灰度级进行排序,确定灰度值较小的像素点,该像素点即为开始注水点;
- Step2:淹没过程,对每个最低点开始不断注水,不断掩模周围的像素点,不同注水处的水汇集在一起,形成分割线。
OpenCV 4提供了用于实现分水岭法分割图像的watershed()函数,该函数的函数原型在代码清单8-19中给出。
代码清单8-19 watershed()函数原型
void cv::watershed(InputArray image,
InputOutputArray markers
)
- image:输入图像,数据类型为CV_8U的三通道图像。
- markers:输入/输出CV_32S的单通道图像的标记结果,与原图像具有相同的尺寸。
该函数根据期望标记结果实现图像分水岭分割。函数的第一个参数是需要进行分水岭分割的图像,该图像必须是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)
本文介绍了OpenCV 4中的分水岭算法,一种全局图像分割方法,通过模拟水淹过程进行图像分割。文章详细阐述了算法的两个步骤:排序过程和淹没过程,并提到了OpenCV的watershed()函数用于实现这一过程。同时,提供了使用Canny算子获取边缘,findContours()和drawContours()函数创建标记图像,以及最终调用watershed()进行分割的示例代码。实验结果显示了分水岭分割的效果和分割区域的原图像细节。
最低0.47元/天 解锁文章
200

被折叠的 条评论
为什么被折叠?



