如何找到已扫描表单图像的轮廓?

3
我希望在这个扫描件中检测到表格的轮廓。理想情况下,我想要找到用红色标出的表格角落。我的最终目标是检测整个文档是否被扫描,并且四个角都在扫描边界内。我使用了Python的OpenCV库,但它无法找到大容器的轮廓。有什么想法吗?

1
你能分享一下你尝试过的代码吗? - Yunus Temurlenk
当然,我尝试了这个轮廓检测的解决方案:https://github.com/Breta01/handwriting-ocr/blob/master/notebooks/page_detection.ipynb,也在这里有描述:https://bretahajek.com/2017/01/scanning-documents-photos-opencv/。我还尝试了一些用于查找轮廓的脚本,这里有描述:https://medium.com/analytics-vidhya/how-to-detect-tables-in-images-using-opencv-and-python-6a0f15e560c3。运行第一个解决方案时,它返回图片的轮廓(我猜是因为扫描页面和背景之间没有对比度)。至于第二个解决方案,我找不到最大的多边形。 - Corovei Andrei
看起来你正在尝试通过轮廓来检测表格。请查看我在这里的答案:https://dev59.com/b7Xna4cB1Zd3GeqPI1Os#57664735 - Dmytro
2个回答

2

针对表格网格可以用于识别表格形式这一观察,以下是一个简单的方法:

  1. 获取二值图像。加载图像,将其转换为灰度图像,进行高斯模糊,然后使用Otsu阈值处理得到二值图像。

  2. 查找水平线段。我们创建一个水平形状的卷积核,查找水平表格线并绘制到蒙版上。

  3. 查找垂直线段。我们创建一个垂直形状的卷积核,查找垂直表格线并绘制到蒙版上。

  4. 填充正文和形态学开运算。我们执行形态学操作来闭合表格,然后查找轮廓并填充掩模以得到形状的轮廓。此步骤满足您的需求,因为您可以在掩模上找到轮廓,但我们可以进一步提取只需要的部分。

  5. 执行四点透视变换。我们查找轮廓,按最大轮廓排序,使用轮廓逼近进行排序,然后执行四点透视变换以获得图像的俯视图。


这是结果:

输入图像

检测到要提取的轮廓,用绿色突出显示。

4点透视变换后的输出

代码

import cv2
import numpy as np
from imutils.perspective import four_point_transform

# Load image, create mask, grayscale, and Otsu's threshold
image = cv2.imread('1.jpg')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,3)

# Find horizontal sections and draw on mask 
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (80,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, (255,255,255), -1)

# Find vertical sections and draw on mask 
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, (255,255,255), -1)

# Fill text document body
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, close_kernel, iterations=3)
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(mask, [c], -1, 255, -1)

# Perform morph operations to remove noise
# Find contours and sort for largest contour
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, close_kernel, iterations=5)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
displayCnt = None

for c in cnts:
    # Perform contour approximation
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    if len(approx) == 4:
        displayCnt = approx
        break

# Obtain birds' eye view of image
warped = four_point_transform(image, displayCnt.reshape(4, 2))

cv2.imwrite('mask.png', mask)
cv2.imwrite('thresh.png', thresh)
cv2.imwrite('warped.png', warped)
cv2.imwrite('opening.png', opening)

0
用窄的方向范围使用霍夫变换,来搜索垂直和水平线条怎么样?如果你幸运的话,那些你需要的线条可能会是最长的,在选择它们之后,你可以重建矩形。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接