霍夫变换绝对是可行的方法。实际上,当引入这种技术时,网格检测是最受欢迎的示例之一(请参见
此处和
此处)。
我建议按照以下步骤进行:
- 下采样
- 模糊处理
- 应用Canny算法(您应该对使用视角的网格线的最小/最大可能长度有一个很好的猜测)
- 膨胀边缘图像(Canny找到网格分隔符的两个边框作为不同的边缘,膨胀将使这些边缘再次合并)
- 侵蚀(现在我们有了太厚的边框,霍夫会找到太多的线)
- 应用HoughLines算法
- 合并相似的线条
在最后一步中,您有许多可能的方法,并且它强烈取决于之后您想要做什么。例如,您可以使用找到的图像创建一个新的边缘图像,并再次应用侵蚀和Hough,您可以使用基于傅里叶变换的方法,或者您可以通过某些任意阈值过滤线条(仅举几个例子)。我实现了最后一个(因为从概念上讲这是最容易做到的),以下是我的做法(尽管我完全不确定这是否是最佳方法):
- 定义rho和theta值的任意阈值
- 检查另一个边缘在这些阈值中出现的次数
- 从最相似的开始,我开始删除与它相似的线条(这样我们将保留在某种意义上是类似组中“中间”一条线)
- 剩余的线条是最终候选人
请参见代码,玩得开心:
import cv2
import numpy as np
filter = False
file_path = ''
img = cv2.imread(file_path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,90,150,apertureSize = 3)
kernel = np.ones((3,3),np.uint8)
edges = cv2.dilate(edges,kernel,iterations = 1)
kernel = np.ones((5,5),np.uint8)
edges = cv2.erode(edges,kernel,iterations = 1)
cv2.imwrite('canny.jpg',edges)
lines = cv2.HoughLines(edges,1,np.pi/180,150)
if not lines.any():
print('No lines were found')
exit()
if filter:
rho_threshold = 15
theta_threshold = 0.1
similar_lines = {i : [] for i in range(len(lines))}
for i in range(len(lines)):
for j in range(len(lines)):
if i == j:
continue
rho_i,theta_i = lines[i][0]
rho_j,theta_j = lines[j][0]
if abs(rho_i - rho_j) < rho_threshold and abs(theta_i - theta_j) < theta_threshold:
similar_lines[i].append(j)
indices = [i for i in range(len(lines))]
indices.sort(key=lambda x : len(similar_lines[x]))
line_flags = len(lines)*[True]
for i in range(len(lines) - 1):
if not line_flags[indices[i]]:
continue
for j in range(i + 1, len(lines)):
if not line_flags[indices[j]]:
continue
rho_i,theta_i = lines[indices[i]][0]
rho_j,theta_j = lines[indices[j]][0]
if abs(rho_i - rho_j) < rho_threshold and abs(theta_i - theta_j) < theta_threshold:
line_flags[indices[j]] = False
print('number of Hough lines:', len(lines))
filtered_lines = []
if filter:
for i in range(len(lines)):
if line_flags[i]:
filtered_lines.append(lines[i])
print('Number of filtered lines:', len(filtered_lines))
else:
filtered_lines = lines
for line in filtered_lines:
rho,theta = line[0]
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))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imwrite('hough.jpg',img)
![Result](https://istack.dev59.com/CetRB.webp)