图片识别表格的一个重要步骤是检测出图片中表格的边框线。
边框线检测最大的挑战是笔画中出现的横线和竖线。你可能认为可以通过线条的长短来区分,但如果是一张密集的表格,某个边框线只出现在一个单元格里,它也会很短。因此这种思路也会有兼容性问题。
网上有很多关于线段检测的算法,但是都只是在某种特定情况下是可行的,当我们要识别各种图片中的各种表格时,不得不考虑一种更健壮更全面的算法。
整体思路如下:
- 通过image_binary变为二值图像 确保图像为白底黑字,因为稍后的 *** 作都是膨胀白色
- 通过dilate膨胀白色横块抹去文字和竖线。因为文字的笔画之间是有白色间隙的,通过白色横块膨胀,文字会被大部分抹去,除了极少的横线笔画。膨胀结果取反变成黑底白线得到A
- 通过dilate膨胀白色竖块抹去文字和横线。因为文字的笔画之间是有白色间隙的,通过白色竖块膨胀,文字会被大部分抹去,除了极少的竖线笔画。膨胀结果取反变成黑底白线得到B
- AB结果通过bitwise_or合并得到边框检测结果
采用dilate算法时最重要的是kernel的设计,kernel最重要的是size,网上看到的算法大部分是按照图片宽高进行一个比列的缩放得到size,实际效果并不好。我们这个算法采用了图片宽高的平方根进行一定的调整后形成size,实测效果非常好,很好的解决了图片分辨率和线条之间的关系。
完整代码如下:
#转换为灰度图 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的结果取反得到黑底白线,便于后面通过bitwise_or叠加得到borders
实际效果如下:
黑白二值:
横线检测:
竖线检测:
边框合并
可以看到算法结束后,仍然存在一些干扰点,因此还需要进一步的算法进行过滤,将在后续文章中讲解。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)