• item.name
    7
  • item.name
    3
  • item.name
    6
  • 分享
  • item.name
    举报

Python Opencv 图片识别表格:边框线检测

发表于 2021-12-12 04:15 1273 查看

图片识别表格的一个重要步骤是检测出图片中表格的边框线。

108-%E8%B4%A8%E9%87%8F%E8%BE%83%E5%B7%AE%E7%9A%84%E8%A1%A8%E6%A0%BC%E6%A0%B7%E6%9C%AC2.JPG

边框线检测最大的挑战是笔画中出现的横线和竖线。你可能认为可以通过线条的长短来区分,但如果是一张密集的表格,某个边框线只出现在一个单元格里,它也会很短。因此这种思路也会有兼容性问题。

网上有很多关于线段检测的算法,但是都只是在某种特定情况下是可行的,当我们要识别各种图片中的各种表格时,不得不考虑一种更健壮更全面的算法。

整体思路如下:

- 通过image_binary变为二值图像

- 确保图像为白底黑字,因为稍后的操作都是膨胀白色

- 通过dilate膨胀白色横块抹去文字和竖线。因为文字的笔画之间是有白色间隙的,通过白色横块膨胀,文字会被大部分抹去,除了极少的横线笔画。膨胀结果取反变成黑底白线得到A

- 通过dilate膨胀白色竖块抹去文字和横线。因为文字的笔画之间是有白色间隙的,通过白色竖块膨胀,文字会被大部分抹去,除了极少的竖线笔画。膨胀结果取反变成黑底白线得到B

- AB结果通过bitwise_or合并得到边框检测结果


#转换为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) #转为二值图 ret, binary = cv2.threshold(gray, black_thr, 255, cv2.THRESH_BINARY) # 膨胀算法的色块大小 h, w = binary.shape hors_k = int(math.sqrt(w)*1.2) vert_k = int(math.sqrt(h)*1.2) # 白底黑字,膨胀白色横向色块,抹去文字和竖线,保留横线 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (hors_k,1)) hors = ~cv2.dilate(binary, kernel, iterations = 1) # 迭代两次,尽量抹去文本横线,变反为黑底白线 # 白底黑字,膨胀白色竖向色块,抹去文字和横线,保留竖线 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,vert_k)) verts = ~cv2.dilate(binary, kernel, iterations = 1) # 迭代两次,尽量抹去文本竖线,变反为黑底白线 # 横线竖线检测结果合并 borders = cv2.bitwise_or(hors,verts)

该算法最讲究的就是dilate的kernel的大小,太大了会误删边框线,太小了会留下很多干扰线。网上看到的算法大部分是按照图片宽高进行一个比列的缩放,实际效果并不好。这里采用了图片宽高的平方根的办法,更好的解决了图片分辨率和线条之间的关系。

需要注意的是都是对dilate的结果取反得到黑底白线,便于后面通过bitwise_or叠加得到borders

实际效果如下:

黑白二值:

image.png

横线检测:

image.png

竖线检测:

image.png

边框合并

image.png

可以看到算法结束后,仍然存在一些干扰点,因此还需要进一步的算法进行过滤,将在后续文章中讲解。

学到了,还是学一下楼主的解决思路
1楼 回复于 2021-12-13 09:19
码住学习,将来没准会用到
2楼 回复于 2021-12-20 11:50
学一学,看着挺实用的
3楼 回复于 2021-12-27 08:14
LZ威武,受教匪浅,但是说一下缺点,虽然思路很有意思,但是仅针对直线检测,实际场景中很对并非这种正交拍摄的··需要借助透视变换还原后能部分达到这个效果,我利用透视变换,解决了部分横向线条,LZ有针对这种非常规直线表格的思路嘛
4楼 回复于 2022-03-17 06:43
学到了
5楼 回复于 2022-11-06 06:06 来自广东
学到了
6楼 回复于 2022-12-02 04:47 来自广东
显示 10
  • 1
  •