最近在matlab平台和opencv上都尝试了以下霍夫变换直线识别。
发现matlab中可以通过设置相近直线距离和最小长度,去除一些角度相近、距离相近的直线;
而opencv的houghline函数没有类似的功能,houghlinesP又不能直接返回rho、theta,总之无法自动剔除相近的直线(当然也很可能是我没用对),于是自己写了下面的函数:
功能大概是检测houghlines返回的参数列表,将theta和rho差值均小于一定范围的直线合并。但目前也有不足,即由于houghlines不返回检测到的直线模量,因此实际上保留的是几条相似直线中第一个被遍历到的直线。
具体代码如下:
import cv2 as cv
import numpy as np
def rho_theta_draw(src: np.ndarray, rho, theta):
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv.line(src, (x1, y1), (x2, y2), (0, 0, 255), 2) # 画直线,对象、起点、终点、颜色、线宽
def hough_draw(lines: np.ndarray, src: np.ndarray, min_rho=10, min_theta=np.pi/90):
'''
函数根据HoughLine函数返回参数进行作图,且自动剔除相近直线
函数将把theta差值小于一定范围,并且在此基础上,rho差值小于一定范围的直线剔除
'''
drew_list = [] # 创建空列表用于存储已经作图的theta
i = 0
j = 0
draw_flag = 1
# 检查lines是否为空,否则作出第一条线
if len(lines) != 0:
rho, theta = lines[0, 0] # 读取第一条直线数据
rho_theta_draw(src, rho, theta)
i += 1
drew_list.append({'theta': theta, 'rho': rho}) # 在drew_list中存入第一个直线数据
for rho, theta in lines[1:, 0]: # lines是一个三维深度的数组,此处遍历每个[rho, theta]元素
for past_line in drew_list:
theta_error = abs(past_line['theta'] - theta)
rho_error = abs(past_line['rho'] - rho)
if theta_error <= min_theta: # 若两条直线的theta差值小于阈值
if rho_error <= min_rho: # 若两条直线距离rho小于阈值,则视作一条直线
j += 1
draw_flag = 0
break # 跳出遍历
else: # 若函数正常完成遍历,说明是一条新直线
drew_list.append({'theta': theta, 'rho': rho}) # 存入drew_list
# 画图
if draw_flag == 1:
rho_theta_draw(src, rho, theta)
i += 1
else:
draw_flag = 1 # 不作图,但恢复标志位
pre_rho = rho # 保存参数
pre_theta = theta
print(f'输入{i+j}条直线,共作{i}条直线,{j}条被合并')
print(drew_list)
return src
起到剔除作用的主要是hough_draw这个函数,rho_theta_draw只是一个用于简化代码用的小函数。
hough_draw要求输入houghlines返回的lines,走图对象src,最小距离rho(默认为10)和最小theta(单位为rad,默认为pi/90,即2°)。
运行效果如下:
不做剔除时,总共画了五条直线
设置min_rho=40,min_theta=pi/180,即1°时:
最底下的时进行作图的直线参数。
修改min_theta=pi/90,即2°时:
最后还是得承认,目前作为opencv新手,各种函数用的还是很垃圾,如果库内自带函数有上述函数的功能,那只能说是很尴尬了。
函数还有提升空间,如果换成基于houghlinesP去编程,应该能将直线模量进一步考虑进去,不过直线检测只是当前毕设里面一个弄着玩的功能,估计是不会继续深入了。