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("../images/twolines.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)
binary = canny_demo(src)
k = np.ones((3, 3), dtype=np.uint8)
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, 8, 0)
# 显示
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
对轮廓进行分析,除了可以对轮廓进行椭圆或者圆的拟合之外,还可以对轮廓点集进行直线拟合,直线拟合的算法有很多,最常见的就是最小二乘法,对于多约束线性方程,最小二乘可以找好直线方程的两个参数、实现直线拟合,OpenCV中直线拟合正是基于最小二乘法实现的。OpenCV实现直线拟合的API如下:
line = cv.fitLine(points, distType, param, reps, aeps[, line])
points
表示待拟合的输入点集合distType
表示在拟合时候使用距离计算公式是哪一种,OpenCV支持如下六种方式:
DIST_L1
= 1DIST_L2
= 2DIST_L12
= 4DIST_FAIR
= 5DIST_WELSCH
= 6DIST_HUBER
= 7param
对模型拟合距离计算公式需要参数C,5~7distType
需要参数Creps
与aeps
是指对拟合结果的精度要求line
在二维拟合时候输出的是vec4f类型的数据,在三维拟合的时候输出是vec6f的vector所有内容均来源于贾志刚老师的知识星球——OpenCV研习社,本文为个人整理学习,已获得贾老师授权,有兴趣、有能力的可以加入贾老师的知识星球进行深入学习。