简单描述
- 获取需要分割的图片
- 转化为灰度图
- 转化为二值图
- 转化为距离图
- 分离距离图,转化为二值图
- 查找距离二值图的轮廓
- 给二值图轮廓中的每个点进行颜色标记,从
1
开始标记 - 将标记的图转化为固定类型的标记图(CV_32S类型)
- 在标记图中将二值图黑色的区域对应的位置设置标记为轮廓的数量加
1
。(非常重要,后面介绍) - 使用分水岭算法将标记的图和原图关联起来。
- 给标记图中每块标记区域上色
话不多说,先贴代码
Python实现
1 |
import cv2 as cv |
C++ 实现
1 |
|
最终显示结果
这里仅仅使用 Python 版代码的截图,C++版运行结果是一样的。
思路分析
在分水岭算法中,我们要找到分割次数,就是要找到标记点,即Markers
。
在本例中使用距离变换算法统计出硬币的个数,即24个,使用距离变换后的二值图,可以很好的打出24个标记,标记每一个硬币。但是我们还需要将背景屏蔽掉,即将不是硬币的地方打一个标记,不然使用分水岭算法的时候水会漫出去导致未找到正确的边界。
思路分析清晰,最后剩下的就是怎么打标记的问题了?
两种解决办法:
- 查找轮廓
- 使用系统的
connectedComponents
的函数
用轮廓查找来打标记
仅使用 Python 代码来分析逻辑,C++ 同理
再贴一遍代码
1 |
# 6. 查找距离二值图的轮廓 |
- 因为图片已经是距离变换后的二值化的图了,所以能查找到准确的轮廓。
- 查找到轮廓后,给每个轮廓填充不一样的颜色即可(本质就是标记,好让分水岭算法去计算边界)
- 背景也要打上一个标记(这步很重要,不然会粘连起来)
使用connectedComponents
来打标记
1 |
connectedComponents(image, markers) |
image
:要标记的8位单通道的图markers
:输出的标记图
该方法在C++
中有一个返回值,返回值的代表了标记的个数N
该方法在Python
中有两个返回值,第一个代表标记的个数N
和输出的标记图Markers
该方法要注意的是:标签总数为[0, N-1],0表示背景标签,即
image
为0的那部分。后面还需做特定的处理。