OpenCV(python)一键入门--十七篇(二值图像分析补充)
本系列OpenCV博客旨在以最简单的方式分享OpenCV知识,欢迎大家交流和提出指导意见
凡是有本文未详细介绍的函数,都可以在以往的博客找到介绍及其使用方法
本期介绍函数:
cv.fitEllipse
cv.line
cv.fitLine
cv.pointPolygonTest
cv.convertScaleAbs
cv.getStructuringElement 获取结构元素
cv.convexHull 凸包检测
1:椭圆拟合
import cv2 as cv
import numpy as np
src = cv.imread("D:/cycle.png")
cv.imshow("input", src)
#Canny
t = 80
binary = cv.Canny(src, t, t * 2)
cv.imshow("canny_output", binary)
k = np.ones((3, 3), dtype=np.uint8)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k) #形态学膨胀
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
# 椭圆拟合
(cx, cy), (a, b), angle = cv.fitEllipse(contours[c])
# 绘制椭圆
cv.ellipse(src, (np.int32(cx), np.int32(cy)),
(np.int32(a/2), np.int32(b/2)), angle, 0, 360, (0, 0, 255), 2, 8, 0)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.fitEllipse 椭圆拟合函数
输入cv.findContours给出的轮廓,就可以使用 该椭圆拟合函数 获取绘制椭圆必须的参数
即获得:【(中心点坐标x,中心点坐标y),(长短轴长度2a,长短轴长度2b),旋转角】
椭圆绘制函数的demo在该篇博客有介绍,这里仅简单放个函数介绍供大家对照参考: OpenCV(python)——一键入门--第4篇
效果如下:
附上素材供大家调试使用:
2:直线拟合
import cv2 as cv
import numpy as np
#直线拟合
def canny_demo(image):
t = 80
canny_output = cv.Canny(image, t, t * 2)
return canny_output
src = cv.imread("d:/morph01.png")
cv.imshow("input", src)
k = np.ones((3, 3), dtype=np.uint8)
binary = canny_demo(src)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)
cv.imshow("binary", binary)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# 直线拟合与极值点寻找
for c in range(len(contours)):
x, y, w, h = cv.boundingRect(contours[c])
m = max(w, h)
if m < 30:
continue
vx, vy, x0, y0 = cv.fitLine(contours[c], cv.DIST_L1, 0, 0.01, 0.01)
#斜率截距的计算
k = vy/vx
b = y0 - k*x0
#初始化 赋初值
maxx = 0
maxy = 0
miny = 100000
minx = 0
#寻找轮廓极值点
for pt in contours[c]:
px, py = pt[0]
if maxy < py:
maxy = py
if miny > py:
miny = py
maxx = (maxy - b) / k
minx = (miny - b) / k
cv.line(src, (np.int32(maxx), np.int32(maxy)), (np.int32(minx), np.int32(miny)), (0, 0, 255), 2)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.fitLine
将线拟合到二维或者三维的点集上
函数可以简单看成:cv.fitLine(输入轮廓,拟合方法,param,半径精度(坐标原点和直线之间的距离),角度精度)
- 对于 半径精度 和 角度精度,0.01 将是一个很好的默认值
- param:某些类型距离的数值参数 ( C )。如果为 0,则选择最佳值
- 关于拟合方法,opencv支持如下六种方法
DIST_L1 = 1
DIST_L2 = 2
DIST_L12 = 4
DIST_FAIR = 5
DIST_WELSCH = 6
DIST_HUBER = 7
其中5~7的模式需要对应参数C
2):cv.line 绘制直线
可以看成:cv.line(图像,(起始坐标x,起始坐标y),(终点坐标x,终点坐标y),笔画粗细)
效果如下:
附上原素材:
3:点多边形测试
import cv2 as cv
import numpy as np
#灰度二值化
src = cv.imread("D:/cycle.png")
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("binary", binary)
image = np.zeros(src.shape, dtype=np.float32)
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
h, w = src.shape[:2]
for row in range(h):
for col in range(w):
dist = cv.pointPolygonTest(contours[0], (col, row), False)
if dist == 0:
image[row,col] = (255,255,255)
if dist > 0:
image[row,col] = (255,0,0)
if dist < 0:
image[row,col] = (0,255,0)
dst = cv.convertScaleAbs(image)
cv.imshow("analysis", dst)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.pointPolygonTest
可以看成是cv.pointPolygonTest(输入轮廓,针对轮廓测试的点,距离测量)
需要注意的是:距离测量的输入值是一个布尔值
如果输入为True,则会返回有符号距离
案例中为False,则返回+1,0,-1
+1表示点在轮廓内
0 表示点在轮廓上
-1表示点在轮廓外
2):cv.convertScaleAbs
作用:缩放、计算绝对值并将结果转换为 8 位。在输入数组的每个元素上,函数 convertScaleAbs 依次执行三个操作:缩放、取绝对值、转换为无符号 8 位类型:
函数原型为:dst=cv.convertScaleAbs(src[, dst[, alpha[, beta]]])
可以看成是:cv.convertScaleAbs(输入图像,【可选输出图像】,【可选比例因子】,【添加到缩放值的可选增量】)
效果如下:
4:凸包检测
import cv2 as cv
import numpy as np
#凸包检测
src = cv.imread("D:/hand_1.jpg")
cv.imshow("input", src)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
k = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))#得到结构元素
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, k)#形态学变换
cv.imshow("binary", binary)
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
ret = cv.isContourConvex(contours[c])
points = cv.convexHull(contours[c])#寻找凸包
total = len(points)
for i in range(len(points)):
x1, y1 = points[i%total][0]
x2, y2 = points[(i+1)%total][0]
cv.circle(src, (x1, y1), 4, (255, 0, 0), 2, 8, 0)
cv.line(src, (x1, y1), (x2, y2), (0, 0, 255), 2, 8, 0)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.getStructuringElement 获取结构元素
为形态学操作返回指定大小和形状的结构元素。
该函数构造并返回可以进一步传递给erode、dilate或morphologyEx的结构元素。但也可以自己构建任意二进制掩码并将其用作结构元素。
该函数可以看成:
cv.getStructuringElement(形状,大小,【锚,可选参数】)
形状:大致有以下
锚:元素内的锚点位置。默认值( − 1 , − 1 )意味着锚在中心。请注意,只有十字形元素的形状取决于锚点位置。在其他情况下,anchor 只是调节形态操作的结果移动了多少。
我们通过获取结构元素,然后将这个给morphologyEx,也就是形态学变换函数,在该博客2.1有详细介绍:https://bbs.huaweicloud.com/blogs/289130。
2):cv.convexHull 凸包检测
对二值图像进行轮廓分析之后,对获取到的每个轮廓数据,可以构建每个轮廓的凸包,构建完成之后会返回该凸包包含的点集。根据返回的凸包点集可以绘制该轮廓对应的凸包。函数使用 Sklansky 算法找到 2D 点集的凸包,该算法在当前实现中具有O(N logN)复杂度。
函数可以看成
cv.convexHull(轮廓点集,【凸包检测输出,可选】,【方向标志】,【是否返回点集】)
- 方向标志。如果为真,则输出凸包顺时针方向。否则,它是逆时针方向的。假设坐标系的 X 轴指向右侧,Y 轴指向上方。
- 是否返回点集:为操作标志。在矩阵的情况下,当标志为真时,函数返回凸包点。否则,它返回凸包点的索引。
整个凸包检测方式如下图:
效果如下:
- 点赞
- 收藏
- 关注作者
评论(0)