【opencv学习】【Hough直线检测】_计算机视觉


【opencv学习】【Hough直线检测】_学习_02

import cv2
import numpy as np


# 展示图像,封装成函数
def cv_show_image(name, img):
cv2.imshow(name, img)
cv2.waitKey(0) # 等待时间,单位是毫秒,0代表任意键终止
cv2.destroyAllWindows()


# 总流程
# 1.获取灰度图像,转成二值图像
# 2.canny边缘检测,获取图像边缘信息。减少计算量
# 3.获取霍夫直线信息,可以使用HoughLines 或者 HoughLinesP函数
# 4.算出直线位置,根据不同的使用函数,获取相应的值,画出每条直线

# 第一步:读取图像
img = cv2.imread("images/build.jpeg")
height = img.shape[0] # 高度
width = img.shape[1] # 宽度

# 第二步:转成灰度图和二值图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, gray = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show_image('gray_img', gray)

# 第三步:使用canny边缘检测,检测出所有的边缘信息
edges = cv2.Canny(gray, threshold1=20, threshold2=100, apertureSize=3) # apertureSize 是sobel算子的大小
cv_show_image('canny_img', edges)

# 第四步:使用直线检测,并画出直线。
# 第四步第一种方法:使用HoughLines
# dst: 输出图像. 它应该是个灰度图 (但事实上是个二值化图)
# lines: 返回值:储存着检测到的直线的参数对 (x_{start}, y_{start}, x_{end}, y_{end}) 的容器,结构如[[[x1,y1,x2,y2]],[[...]]]
# rho : 参数极半径 r 以像素值为单位的分辨率. 我们使用 1 像素为步长.
# theta: 参数极角 theta 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)为步长.
# threshold: 控制检测出线段的条件。设置阈值: 一条直线所需最少的的曲线在一点相交,超过设定阈值才被检测出线段,值越大,
# 基本上意味着检出的线段越长,检出的线段个数越少。因为阈值越大,超过阈值的点越少,即xy平面的直线越少,但是因为阈值越大,说明检测出在同一条直线上的点越多,即直线越长。这个参数是针对参数空间而言的,在参数空间中一条曲线就代表在xy平面上的一个点
# minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃,其实这个参数的意义跟上一个很类似,只是这个参数是针对xy平面而言的,即当组成直线的点达到一点数量的时候才被检测出为线段,否则过滤掉
# maxLineGap: 控制检测出直线长短,在同一条直线上的点,能够被连接的最大距离,越大得到的线越长,如下图,点在直线上,若此时距离maxlineGap小于设定的值,则连接,否则就不连接
lines = cv2.HoughLines(image=edges, rho=1, theta=np.pi / 180, threshold=100) # #函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
print(lines.shape)

result = img.copy()
for line in lines:
# print(type(line)) #多维数组
rho, theta = line[0] # 获取极值ρ长度和θ角度
a = np.cos(theta) # 获取角度cos值
b = np.sin(theta) # 获取角度sin值
x0 = a * rho # 获取x轴值
y0 = b * rho # 获取y轴值  x0和y0是直线的中点
x1 = int(x0 + 1000 * (-b)) # 获取这条直线最大值点x1
y1 = int(y0 + 1000 * (a)) # 获取这条直线最大值点y1
x2 = int(x0 - 1000 * (-b)) # 获取这条直线最小值点x2  
y2 = int(y0 - 1000 * (a)) # 获取这条直线最小值点y2  其中*1000是内部规则
cv2.line(result, (x1, y1), (x2, y2), (0, 0, 255), 2) # 开始划线
cv_show_image('HoughLines_result_img', result)

# 第四步方法二:使用HoughLinesP
# HoughLinesP概率霍夫变换(是加强版)使用简单,效果更好,检测图像中分段的直线(而不是贯穿整个图像的直线)
minLineLength = 30 # height/32
maxLineGap = 10 # height/40
lines = cv2.HoughLinesP(image=edges, rho=1, theta=np.pi / 180, threshold=80,
minLineLength=minLineLength, maxLineGap=maxLineGap)
print(lines.shape)

result = img.copy()
for line in lines:
# print(type(line)) # 多维数组
x1,y1,x2,y2 = line[0]
cv2.line(result, (x1, y1), (x2, y2), (0, 0, 255), 2) # 开始划线
cv_show_image('HoughLinesP_result_img', result)

效果展示

二值图像:

【opencv学习】【Hough直线检测】_计算机视觉_03


canny边缘检测

【opencv学习】【Hough直线检测】_计算机视觉_04


使用 HoughLines 函数得到的结果,发现这个直线会穿过整个图像

【opencv学习】【Hough直线检测】_学习_05


使用 HoughLinesP 函数得到的结果,发现这个直线就是图像中的直线长度

【opencv学习】【Hough直线检测】_边缘检测_06


最后是参考的资料地址

参考:

​霍夫(Hough)变换之直线检测​

​​OpenCV—直线检测​​

​霍夫线变换​