美文网首页
OpenCV自适应阀值二值化表格检测方法(python版)

OpenCV自适应阀值二值化表格检测方法(python版)

作者: 欧万翔 | 来源:发表于2020-07-12 22:55 被阅读0次

    OCR主要分为三个步骤:检测、分割、文字识别。其中文字识别无论是英文还是中文相对比较成熟。只要检测到位,标准的印刷体识别率还是非常高的。

    文书OCR检测主要有文字检测和表格检测。文本段落基于行的检测通过DBNet加人为后期纠正能够获得非常高的准确率(此部分以后再写),反而是表格的检测花费了很多时间,网上常规的方法:先对图像进行二值化,然后使用霍夫变换,检测出其中的直线,并在直线中,找到围成一个矩形的区域,将这块区域提取出来就好了。但是难点在于印刷或打印表格线条的过程中清晰度不高,线条粗细和清晰度不一,再次扫描后更加不清晰,同时有些表格里面的文字是多行的,情况非常复杂,必须一个个方框切割下来进行文字识别。例如下面整个图片,表格线条粗细不一,清晰度欠佳,采用霍夫变换直线检测准确率很低,经过多次实验,我把目前稳定性和准确率最高的方法记录下来。这个算法灵活运用了自适应阀值二值化、腐蚀和二次膨胀,让表格乖乖的现形了

    网上随便下载的一个原图

    (注意:此图有点斜,为了后面更高的检测和文字识别率,需要先摆正,此文不讲了)

    第一步,直接以灰度图读入图片

    img=cv2.imread("D:\\Python37\\code\\timg.jpg",0)

    第二步是关键,自适应阈值二值化处理

    binary = cv2.adaptiveThreshold(~img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,7, -2)

    自适应阈值:

          当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。

    cv2.adaptiveThreshold()参数说明,后面两个参数很重要。

    参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。~img表示黑白对调,变成黑底白字,这里也是注意点

    参数2:预设满足条件的最大值。指当像素值高于(有时是小于)阈值时应该被赋予的新的像素值

    参数3:指定自适应阈值算法。adaptive_method  指: CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C。(具体见下面的解释)。

    参数4:指定阈值类型。可选择CV_THRESH_BINARY,CV_THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。

    参数5:表示邻域块大小(一个正方形的领域),用来计算区域阈值,一般选择为3、5、7......等。因为我们是直线检测,相邻领域都很小,这样能够把大于这个像素的领域删除,例如本文设为7

    参数6:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。(具体见下面的解释)。

    对参数3与参数6内容的解释:

    自适应阈值化计算大概过程是为每一个象素点单独计算的阈值,即每个像素点的阈值都是不同的,就是将该像素点周围B*B区域内的像素加权平均,然后减去一个常数C,从而得到该点的阈值。B由参数5指定,常数C由参数6指定。

    参数4中:

    CV_ADAPTIVE_THRESH_MEAN_C ,为局部邻域块的平均值。该算法是先求出块中的均值,再减去常数C。

    CV_ADAPTIVE_THRESH_GAUSSIAN_C ,为局部邻域块的高斯加权和。该算法是在区域中(x,y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算, 再减去常数C。

    举个例子:如果使用平均值方法,平均值mean为190,差值delta(即常数C)为30。那么灰度小于160的像素为0,大于等于160的像素为255。

    第三步识别横线和竖线

    rows,cols=binary.shape

    scale = 20

    #识别横线

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(cols//scale,1))

    eroded = cv2.erode(binary,kernel,iterations = 1)

    #由于图像像素质量的原因,一次膨胀不够,往往有些线无法识别,我用二次膨胀。

    dilatedcol = cv2.dilate(eroded,kernel,iterations = 2)

    scale = 10

    #识别竖线

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(1,rows//scale))

    eroded = cv2.erode(binary,kernel,iterations = 1)

    #cv2.imshow("Eroded Image",eroded)

    dilatedrow = cv2.dilate(eroded,kernel,iterations =2)

    #标识交点

    bitwiseAnd = cv2.bitwise_and(dilatedcol,dilatedrow)

    #标识表格

    merge = cv2.add(dilatedcol,dilatedrow)

    #识别黑白图中的白色交叉点,将横纵坐标取出

    ys,xs = np.where(bitwiseAnd>0)

    mylisty=[] #纵坐标

    mylistx=[] #横坐标

    #通过排序,获取跳变的x和y的值,说明是交点,否则交点会有好多像素值值相近,我只取相近值的最后一点

    #这个10的跳变不是固定的,根据不同的图片会有微调,基本上为单元格表格的高度(y坐标跳变)和长度(x坐标跳变),对于多个点,我取x,y中间值mean

    i = 0

    myxs=np.sort(xs)

    tmpmy=[]

    for i in range(len(myxs)-1):

      if(myxs[i+1]-myxs[i]>10):

          tmpmy.append(myxs[i])

          mylistx.append(int(mean(tmpmy)))

          tmpmy=[]

      else:

          tmpmy.append(myxs[i])

          i=i+1

    mylistx.append(int(mean(tmpmy))) #要将最后一个点加入

    i = 0

    myys=np.sort(ys)

    tmpmy=[]

    for i in range(len(myys)-1):

      if(myys[i+1]-myys[i]>10):

          tmpmy.append(myys[i])

          mylisty.append(int(mean(tmpmy)))

          tmpmy = []

      else:

          tmpmy.append(myys[i])

          i = i + 1

    mylisty.append(int(mean(tmpmy))) #要将最后一个点加入

    cv2.imshow("bitwiseAnd", bitwiseAnd)

    cv2.imshow("merge", merge)

    cv2.waitKey(0)

    cv2.destroyAllWindows()

    识别出来的表格,基本已经有模有样了 准确率100%,注意一定要二次膨胀,同时要调整 scale

    第四步,根据交叉点分割出一个个小格用于文字识别

    #循环y坐标,x坐标分割表格,返回一个个子方框用于文字识别。真正使用过程中是需要知道每个框是第几行第几列的,我这里没有做处理。

        for i in range(len(mylisty)-1):

          for j in range(len(mylistx)-1):

                #在分割时,第一个参数为y坐标,第二个参数为x坐标

                ROI = image[mylisty[i]+3:mylisty[i+1]-3,mylistx[j]:mylistx[j+1]-3] #减去3的原因是由于我缩小ROI范围

                ROIList.append(ROI)

                j=j+1

            i=i+1

        return ROIList

    一个程序只能适应一个模板,大致思路差不多。我本来还想做一个自动膨胀次数检测,以自动达到检测目标、自动适应各种清晰度的程序,但是难度有点大,后续有需要再慢慢做了。

    最后:感谢深圳的孙老师带我OCR入门

    相关文章

      网友评论

          本文标题:OpenCV自适应阀值二值化表格检测方法(python版)

          本文链接:https://www.haomeiwen.com/subject/skdncktx.html