C++ OpenCV基于距离变换与分水岭的图像分割

Posted 微卡智享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ OpenCV基于距离变换与分水岭的图像分割相关的知识,希望对你有一定的参考价值。

图像分割

图像分割,英文名image segmentation,就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:

  • 基于阈值的分割方法

  • 基于区域的分割方法

  • 基于边缘的分割方法以及基于特定理论的分割方法

从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像索赋予相同的编号。

  • 图像分割的目标是将图像中像素根据一定的规则分为若干个(N)个cluster集合,I每个集合包含一类像素。

  • 根据算法分为监督学习算法和无监督学习算法,图像分割的算法多数都是无监督学习算法。---KMeans


距离变换与分水岭介绍

距离变换

C++ OpenCV基于距离变换与分水岭的图像分割

距离变换常见算法有两种

  • 不断膨胀/ 腐蚀得到

  • 基于倒角距离


分水岭变换

C++ OpenCV基于距离变换与分水岭的图像分割

分水岭变换常见的算法

基于浸泡理论实现


相关API

        cv::distanceTransform(

                InputArray  src, 

                OutputArray dst,  

                OutputArray  labels,  

                int  distanceType,  

                int maskSize,  

                int labelType = DIST_LABEL_CCOMP

        )

distanceType = DIST_L1/DIST_L2,

maskSize = 3x3,最新的支持5x5,推荐3x3、

labels离散维诺图输出,

dst输出8位或者32位的浮点数,单一通道,大小与输入图像一致


        cv::watershed(

                InputArray image, 

                InputOutputArray  markers

        )


操作步骤

  1. 将白色背景变成黑色-目的是为后面的变换做准备

  2. 使用filter2D与拉普拉斯算子实现图像对比度提高,sharp

  3. 转为二值图像通过threshold

  4. 距离变换

  5. 对距离变换结果进行归一化到[0~1]之间

  6. 使用阈值,再次二值化,得到标记

  7. 腐蚀得到每个Peak - erode

  8. 发现轮廓 – findContours

  9. 绘制轮廓- drawContours

  10. 分水岭变换 watershed

  11. 对每个分割区域着色输出结果


代码演示

新建一个项目opencv-0027,配置属性(),然后在源文件写入#include和main方法

这次我们用opencv里面自带的一张图像来实个这个方法

C++ OpenCV基于距离变换与分水岭的图像分割

运行显示的图像为

C++ OpenCV基于距离变换与分水岭的图像分割


1.将白色背景变成黑色

C++ OpenCV基于距离变换与分水岭的图像分割

我们运行看一下

C++ OpenCV基于距离变换与分水岭的图像分割

可以看到右边的已经把背景都换为黑色了。


2.使用filter2D与拉普拉斯算子实现图像对比度提高,sharp

C++ OpenCV基于距离变换与分水岭的图像分割

我们再运行看一下,左边的就是生成的结果图,可以看出左边的清晰度更高了一些

C++ OpenCV基于距离变换与分水岭的图像分割


3.转为二值图像通过threshold

C++ OpenCV基于距离变换与分水岭的图像分割

我们再运行看一下,左边的图像已经让我们转换为二值图像了,也比较清晰

C++ OpenCV基于距离变换与分水岭的图像分割


4.距离变换

5.对距离变换结果进行归一化到[0~1]之间

因为距离变换看不出任何效果,所以我们把4和5两步放在一起显示

C++ OpenCV基于距离变换与分水岭的图像分割

我们再运行一下看看执行结果

C++ OpenCV基于距离变换与分水岭的图像分割


6.使用阈值,再次二值化,得到标记

C++ OpenCV基于距离变换与分水岭的图像分割

显示效果为

C++ OpenCV基于距离变换与分水岭的图像分割


7.腐蚀得到每个Peak

效果不太好看,我们需要再进行二值的腐蚀,把上面的代码再修改一下

C++ OpenCV基于距离变换与分水岭的图像分割

我们再看一下运行效果,可以看出来比刚才的效果好很多了

C++ OpenCV基于距离变换与分水岭的图像分割


8.标记并且开始查找轮廓

C++ OpenCV基于距离变换与分水岭的图像分割

这一步只是查找轮廓,我们接下来绘制查找的轮廓再一起显示出来


9.绘制轮廓

C++ OpenCV基于距离变换与分水岭的图像分割

上面drawContours和circle最后一个参数都是用了-1,代表着画的轮廓里面进行颜色填充

我们再显示一下看看效果

C++ OpenCV基于距离变换与分水岭的图像分割

看到好像什么也没有,这是因为我们画的轮廓太小了, 我们改一下显示效果

C++ OpenCV基于距离变换与分水岭的图像分割

把最后显示cv::imshow(imgdst,makers*5000)再乘5000,重新看一下显示效果

C++ OpenCV基于距离变换与分水岭的图像分割

这会儿就可以看到绘制的轮廓出来了


10.分水岭变换

C++ OpenCV基于距离变换与分水岭的图像分割

我们看看显示的效果

C++ OpenCV基于距离变换与分水岭的图像分割

可以看出,每个轮廓都有明显的区分开了。


11.对每个分割区域着色输出结果

C++ OpenCV基于距离变换与分水岭的图像分割

C++ OpenCV基于距离变换与分水岭的图像分割

然后我们再运行看到最后结果




-END-




以上是关于C++ OpenCV基于距离变换与分水岭的图像分割的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV + CPP 系列(三十)基于距离变换与分水岭的图像分割

OpenCV(26)图像分割 -- 距离变换与分水岭算法(硬币检测扑克牌检测车道检测)

基于标记的分水岭分割算法

OpenCV实战——基于分水岭算法的图像分割

OpenCV中的图像处理 —— 霍夫线 / 圈变换 + 图像分割(分水岭算法) + 交互式前景提取(GrabCut算法)

OpenCV 中的鲁棒图像分割