使用 OpenCV Python 和 Hough 变换进行线检测
Line detection with OpenCV Python and Hough transform
我正在尝试检测 table 行并使用 Python OpenCV 和霍夫变换算法从图像中提取完整的 table。我需要每条线的所有坐标,目的是用相同的比例绘制相同的 table。我了解 Hough 变换的工作原理并尝试在没有 OpenCV 的情况下实现它,但它在大图像上非常慢。
这是来自 OpenCV 霍夫变换示例的代码
import cv2
import numpy as np
img = cv2.imread('image1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
cv2.imshow("image", edges)
cv2.waitKey(0)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, minLineLength, maxLineGap)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imwrite('houghlines5.jpg', img)
Canny 边缘检测返回图像 Resulf of Canny edge detectione
但是检测结果是Resulf of Housh Transform
我不知道为什么霍夫变换留下了table的一些行。你能推荐一些事情做吗?也许另一种从图像中提取 table 的方法?谢谢!
更新。
原图original table needed to detect
我在文档中找到了这个。
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
我不确定 lines
的确切结构,但我看到的示例只遍历了第一个 lines[0]
。也许您从 for line in lines
.
得到了一些意想不到的行为
我认为您必须在执行 HoughLinesP()
之前准备好图像,例如去掉文本、调整参数或者可能扩大边缘等。但是如果您想在不提取模板的情况下提取模板text 你可以让你的生活更轻松,只需从这个 table 中绘制所有文本(通过搜索小轮廓并在轮廓上制作一个白色覆盖边界框)。在示例代码中,我做了三个步骤:第一步是在没有 Hough 的情况下制作模板,第二步是使用 HoughLines()
,第三步是使用 HoughLinesP()
。希望能有所帮助。干杯!
示例:
import cv2
import numpy as np
### MAKING TEMPLATE WITHOUT HOUGH
# Read the image and make a copy then transform it to gray colorspace,
# threshold the image and search for contours.
img = cv2.imread('tablelines.png')
res = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
# Iterate through contours and draw a slightly bigger white rectangle
# over the contours that are not big enough (the text) on the copy of the image.
for i in contours:
cnt = cv2.contourArea(i)
if cnt < 500:
x,y,w,h = cv2.boundingRect(i)
cv2.rectangle(res,(x-1,y-1),(x+w+1,y+h+1),(255,255,255),-1)
# Display the result. Note that the image is allready the template!
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Optional count the rows and columns of the table
count = res.copy()
gray = cv2.cvtColor(count, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
check = []
for i in contours:
cnt = cv2.contourArea(i)
if 10000 > cnt > 10:
cv2.drawContours(count, [i], 0, (255,255,0), 2)
M = cv2.moments(i)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
check.append([cx, cy])
check.sort(key = lambda xy: xy[1])
columns = 1
for i in range(0, len(check)-1):
if check[i+1][1] + 5 >= check[i][1] >= check[i+1][1] - 5:
columns += 1
else:
break
print(columns)
check.sort(key = lambda tup: tup[0])
rows = 1
for i in range(0, len(check)-1):
if check[i+1][0] + 5 >= check[i][0] >= check[i+1][0] - 5:
rows += 1
else:
break
print('Columns: ',columns)
print('Roiws : ',rows)
cv2.imshow('res', count)
cv2.waitKey(0)
cv2.destroyAllWindows()
### LINES WITH HOUGHLINES()
# Convert the resulting image from previous step (no text) to gray colorspace.
res2 = img.copy()
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
# You can either use threshold or Canny edge for HoughLines().
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# Perform HoughLines tranform.
lines = cv2.HoughLines(thresh,1,np.pi/180,200)
for line in lines:
for rho,theta in line:
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(res2,(x1,y1),(x2,y2),(0,0,255),2)
#Display the result.
cv2.imshow('res', res)
cv2.imshow('res2', res2)
cv2.waitKey(0)
cv2.destroyAllWindows()
### LINES WITH HOUGHLINESP()
# Convert the resulting image from first step (no text) to gray colorspace.
res3 = img.copy()
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
# Use Canny edge detection and dilate the edges for better result.
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
kernel = np.ones((4,4),np.uint8)
dilation = cv2.dilate(edges,kernel,iterations = 1)
# Perform HoughLinesP tranform.
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(dilation, 1, np.pi / 180, 50, minLineLength, maxLineGap)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(res3, (x1, y1), (x2, y2), (0, 255, 0), 2)
#Display the result.
cv2.imwrite('h_res1.png', res)
cv2.imwrite('h_res2.png', res2)
cv2.imwrite('h_res3.png', res3)
cv2.imshow('res', res)
cv2.imshow('res2', res2)
cv2.imshow('res3', res3)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
列数:7
行数:21
我正在尝试检测 table 行并使用 Python OpenCV 和霍夫变换算法从图像中提取完整的 table。我需要每条线的所有坐标,目的是用相同的比例绘制相同的 table。我了解 Hough 变换的工作原理并尝试在没有 OpenCV 的情况下实现它,但它在大图像上非常慢。
这是来自 OpenCV 霍夫变换示例的代码
import cv2
import numpy as np
img = cv2.imread('image1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
cv2.imshow("image", edges)
cv2.waitKey(0)
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, minLineLength, maxLineGap)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imwrite('houghlines5.jpg', img)
Canny 边缘检测返回图像 Resulf of Canny edge detectione
但是检测结果是Resulf of Housh Transform
我不知道为什么霍夫变换留下了table的一些行。你能推荐一些事情做吗?也许另一种从图像中提取 table 的方法?谢谢!
更新。 原图original table needed to detect
我在文档中找到了这个。
for x1,y1,x2,y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
我不确定 lines
的确切结构,但我看到的示例只遍历了第一个 lines[0]
。也许您从 for line in lines
.
我认为您必须在执行 HoughLinesP()
之前准备好图像,例如去掉文本、调整参数或者可能扩大边缘等。但是如果您想在不提取模板的情况下提取模板text 你可以让你的生活更轻松,只需从这个 table 中绘制所有文本(通过搜索小轮廓并在轮廓上制作一个白色覆盖边界框)。在示例代码中,我做了三个步骤:第一步是在没有 Hough 的情况下制作模板,第二步是使用 HoughLines()
,第三步是使用 HoughLinesP()
。希望能有所帮助。干杯!
示例:
import cv2
import numpy as np
### MAKING TEMPLATE WITHOUT HOUGH
# Read the image and make a copy then transform it to gray colorspace,
# threshold the image and search for contours.
img = cv2.imread('tablelines.png')
res = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
# Iterate through contours and draw a slightly bigger white rectangle
# over the contours that are not big enough (the text) on the copy of the image.
for i in contours:
cnt = cv2.contourArea(i)
if cnt < 500:
x,y,w,h = cv2.boundingRect(i)
cv2.rectangle(res,(x-1,y-1),(x+w+1,y+h+1),(255,255,255),-1)
# Display the result. Note that the image is allready the template!
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Optional count the rows and columns of the table
count = res.copy()
gray = cv2.cvtColor(count, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
check = []
for i in contours:
cnt = cv2.contourArea(i)
if 10000 > cnt > 10:
cv2.drawContours(count, [i], 0, (255,255,0), 2)
M = cv2.moments(i)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
check.append([cx, cy])
check.sort(key = lambda xy: xy[1])
columns = 1
for i in range(0, len(check)-1):
if check[i+1][1] + 5 >= check[i][1] >= check[i+1][1] - 5:
columns += 1
else:
break
print(columns)
check.sort(key = lambda tup: tup[0])
rows = 1
for i in range(0, len(check)-1):
if check[i+1][0] + 5 >= check[i][0] >= check[i+1][0] - 5:
rows += 1
else:
break
print('Columns: ',columns)
print('Roiws : ',rows)
cv2.imshow('res', count)
cv2.waitKey(0)
cv2.destroyAllWindows()
### LINES WITH HOUGHLINES()
# Convert the resulting image from previous step (no text) to gray colorspace.
res2 = img.copy()
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
# You can either use threshold or Canny edge for HoughLines().
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# Perform HoughLines tranform.
lines = cv2.HoughLines(thresh,1,np.pi/180,200)
for line in lines:
for rho,theta in line:
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(res2,(x1,y1),(x2,y2),(0,0,255),2)
#Display the result.
cv2.imshow('res', res)
cv2.imshow('res2', res2)
cv2.waitKey(0)
cv2.destroyAllWindows()
### LINES WITH HOUGHLINESP()
# Convert the resulting image from first step (no text) to gray colorspace.
res3 = img.copy()
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
# Use Canny edge detection and dilate the edges for better result.
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
kernel = np.ones((4,4),np.uint8)
dilation = cv2.dilate(edges,kernel,iterations = 1)
# Perform HoughLinesP tranform.
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(dilation, 1, np.pi / 180, 50, minLineLength, maxLineGap)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(res3, (x1, y1), (x2, y2), (0, 255, 0), 2)
#Display the result.
cv2.imwrite('h_res1.png', res)
cv2.imwrite('h_res2.png', res2)
cv2.imwrite('h_res3.png', res3)
cv2.imshow('res', res)
cv2.imshow('res2', res2)
cv2.imshow('res3', res3)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
列数:7
行数:21