霍夫变换绝对是要走的路。事实上,网格检测是介绍此技术时最流行的示例之一(参见here 和here)。
我建议以下步骤:
- 下采样
- 模糊
- 应用 Canny(您应该很好地猜测从使用的角度来看,网格线的最小/最大可能长度是多少)
- 扩张边缘图像(canny 在网格中发现分隔符的两个边界为不同的边缘,扩张将使这些再次合并)
- 侵蚀(现在我们的边框太粗了,虽然会发现太多线条)
- 应用霍夫线
- 合并相似的行
在最后一步,您有许多可能的方法,这在很大程度上取决于您想对之后的结果做什么。例如,您可以使用找到的图像创建一个新的边缘图像并再次应用侵蚀和霍夫,您可以使用基于傅里叶的东西,或者您可以简单地通过一些任意阈值过滤线条(仅举几例)。我实现了最后一个(因为从概念上讲这是最容易做到的),这就是我所做的(尽管我完全不确定这是否是最好的方法):
- 为 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
# how many lines are similar to a given one
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)
# ordering the INDECES of the lines by how many are similar to them
indices = [i for i in range(len(lines))]
indices.sort(key=lambda x : len(similar_lines[x]))
# line flags is the base for the filtering
line_flags = len(lines)*[True]
for i in range(len(lines) - 1):
if not line_flags[indices[i]]: # if we already disregarded the ith element in the ordered list then we don't care (we will not delete anything based on it and we will never reconsider using this line again)
continue
for j in range(i + 1, len(lines)): # we are only considering those elements that had less similar line
if not line_flags[indices[j]]: # and only if we have not disregarded them already
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 # if it is similar and have not been disregarded yet then drop it now
print('number of Hough lines:', len(lines))
filtered_lines = []
if filter:
for i in range(len(lines)): # filtering
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)