1.点多边形测试
(1)概念介绍
测试一个点是否在给定的多边形内部,边缘或者外部
(2)API介绍(cv::pointPolygonTest)
pointPolygonTest(inputarray contour,//输入的轮廓
Point2f pt,//测试点
Bool measureDist//是否返回距离值,如果是false,1表示在内面,0表示在边界上,-1表示在外部,true返回实际距离)
返回数据是double型
(3)实现步骤:
- 构建一张400*400大小的图片,Mat::Zero(400,400,CV_8UC1)
- 画上一个六边形的闭合区域line
- 发现轮廓
- 对图像中所有像素点做多边形测试,得到距离,归一化后显示
2.基于距离变换与分水岭的图像分割
(1)什么是图像分割
图像分割的目标是将图像中像素根据一定的规则分为若干个cluster集合,每个集合包含一类像素
根据算法分为监督学习方法和无监督学习方法,图像分割的算法多数都是无监督学习方法——kMeans
(2)距离变换与分水岭介绍
距离变换常见算法有俩种:1、不断膨胀/腐蚀得到,2、基于倒角距离
分水岭变换常见的算法:基于浸泡理论实现
(3)相关API
Cv::distanceTransform(inputarray src,
Outputarray dst,
Outputarray labels,
Int distanceType,
Int maskSize,
Int labelType=DIST_LABEL_CCOMP)
distanceType=DIST_L1/DIST_L2,
maskSize=3*3,最新的支持5*5,推荐3*3
labels离散维诺图输出
dst输出8位或者32位的浮点数,单一通道,大小与输入图像一致
参数四可选类型:
参数六可选类型:
cv::watershed(inputarray image,inputoutputarray markers)
分水岭算法步骤:
第一步:找到图像的局部最低点,可以用一个内核去找,也可以一个一个比较,实现起来不难。
第二步:从最低点开始注水,水开始网上满(图像的说法就是梯度法),其中那些最低点已经被标记,不会被淹没,那些中间点是被淹没的。
第三步:找到局部最高点,就是图中3位置对应的两个点。
第四步:这样基于局部最小值,和找到的局部最大值,就可以分割图像了。
然而基于梯度图像的直接分水岭算法容易导致图像的过分割,产生这一现象的原因主要是由于输入的图像存在过多的极小区域而产生许多小的集水盆地,从而导致分割后的图像不能将图像中有意义的区域表示出来。所以必须对分割结果的相似区域进行合并。 opencv对其改进就是使用了人工标记的方法,我们标记一些点,基于这些点去引导分水岭算法的进行,效果很好!
比如我们对上面的图像标记了两个三角形,第一步我们找到三个局部最小点,第二步淹没的时候三个点都被淹没了,然而中间那个没被标记,那就淹死了,其余两个点保留,这样就可以达到我们的想要的结果了。
(4)处理流程:
- 讲白色背景变成黑色——目的是为后面的变换做准备
- 使用filter2D与拉普拉斯算子实现图像对比度提高,sharp
- 转为二值图像通过threshold
- 距离变换
- 对距离变换结果进行归一化到[0~1]之间
- 使用阈值,再次二值化,得到标记
- 腐蚀得到每个Peak-erode
- 发现轮廓-findContours
- 绘制轮廓-drawContours
- 分水岭变换watershed
- 对每个分割区域着色输出结果