当前位置: 首页 > 知识库问答 >
问题:

使用OpenCV Python和Hough变换进行线检测

万俟招
2023-03-14

我正在尝试使用Python OpenCV和Hough变换算法检测表线并从图像中提取完整的表。我需要有每条线的所有坐标,目的是绘制相同比例的相同表格。我了解Hough变换的工作原理,并尝试在没有OpenCV的情况下实现它,但在大图像上速度非常慢。

这是来自示例OpenCV Hough Transfrom的代码

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边缘检测返回图像Canny边缘检测结果

但是检测的结果是豪斯变换的结果

我不知道Hough变换为什么会在表中留下一些行。你能推荐一些事情做吗?也许是从图像中提取表的另一种方法?非常感谢。

UPD。需要检测的原始图像原始表

共有2个答案

司空玮
2023-03-14

我在留档找到这个。

for x1,y1,x2,y2 in lines[0]:
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)

我不确定行的确切结构,但我看到的示例只遍历了第一行。也许您从“行中的行”中得到了一些意外行为。

查飞星
2023-03-14

我认为您必须在执行HoughLinesP()之前准备好图像,例如去掉文本,使用参数或可能扩展边缘等。但是,如果您想提取没有文本的模板,只需从该表中绘制所有文本(通过搜索小轮廓并在轮廓上创建白色重叠边界框),就可以让您的生活更轻松。在示例代码中,我完成了三个步骤:一个步骤是不使用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

 类似资料:
  • 我需要一个我一直在工作的算法的帮助。我试图检测阈值图像中的所有线条,检测所有线条,然后只输出那些平行的线条。阈值图像输出我感兴趣的对象,然后我通过canny边缘检测器过滤该图像。然后,该边缘图像通过概率Hough变换。现在,我希望该算法能够检测任何图像中的平行线。我想通过检测所有直线的坐标并计算它们的斜率(然后是角度)来实现这一点。平行线必须具有相同或几乎相同的角度,这样我只能输出具有相同角度的线

  • 我尝试过各种演示代码,如“opencv查找:轮廓”,模板匹配(效果不好,因为它无法检测到顶盖的旋转) 我发现最好的方法是将Canny边缘检测和Hough变换圆相结合,这样Canny边缘检测的输出结果可以是Hough变换圆的输入图像,结果如下。 不幸的是,并非所有圆圈都被检测到,如果我更改

  • 我在网上阅读,发现可以根据使用边缘检测器检测到的线数,然后应用Hough变换来判断图像是否像素化<我试过那种方法,但霍夫变换似乎无法正确检测线条,我不明白为什么它不能正常工作 以下是一些可供参考的结果图像:canny边缘检测结果 以及霍夫变换的结果 如何改进测线检测 我使用的代码基于一些在线教程:

  • 我试图使用霍夫变换找到图像的旋转角度。首先,我使用精明的边缘检测器检测边缘,然后我应用霍夫变换。之后,对于每个θ,我对θ上的线条长度进行求和,并找到theta.then的直方图,我将其“旋转”并找到匹配项。例如,如果我需要移动5次,原始图像和旋转图像相差5度。问题是,例如,这种方法在180和0之间没有差异。然而,这是合乎逻辑的,因为霍夫给出的θ仅在-90和90之间。现在我如何识别旋转角度是0还是1

  • 我正在尝试使用opencv 4 android sdk检测矩形文档。首先,我试图通过查找轮廓来检测它,但它不适用于多色文档。您可以查看此链接以获得更好的想法:使用OpenCV4Android检测多色文档 我做了很多研究,发现可以用houghline变换来完成。所以我按照以下方法检测文档: 原始图像- 我对hough线变换所做的是: 从上面的水平线和垂直线列表中,我找到了以下交叉点: 从这四个交点我

  • 我觉得应该有一种有效的方法使用和使用来修改新列,但不能使其工作。 我知道在中使用“有点试验性”(就像在本文中一样),但如果有任何建议,我将不胜感激。 不起作用: