基于opencv的倾斜文本行的校正

这里主要记录下我在工作中对倾斜字体文本行的校正的方法探索,废话不多,一起说来看看吧。


目录

一、算法流程图

二、算法实现

2.1、预处理

2.2、水平模糊

2.3、垂直投影

2.4、短斜线倾斜角度的统计计算

2.5、倾斜校正

三、算法实现的最终结果


实现倾斜文本行字体的校正主要分为两部分,一部分为倾斜角度的检测,另一部分为倾斜校正。其中倾斜角度的检测极为重要,他关系到后续的校正。

一、算法流程图

二、算法实现

2.1、预处理

原始图片:

这里主要是灰度化、滤波以及二值化,结果如下:

2.2、水平模糊

水平模糊也叫做游程平滑。是将图像上长度小于某一域值的连续黑点转为白点的演算法则。图像经模糊算法处理后, 图像上距离相近的连通成份将会形成为一较大的连通区域。

def horizontal_blur(image):
    '''水平平滑'''
    dst=image

    #计算图像的字符宽度
    hor_vec=np.sum(dst,axis=0)

    width=hor_vec.shape[0]
    left=right=0
    for i in range(width):
        if hor_vec[i]!=0:
            left=i
            break

    for j in range(width-1,-1,-1):
        if hor_vec[j]!=0:
            right=j
            break

    char_width=right-left+1 if right-left+1>0 else 10

    # 计算游程平滑阈值
    thres=char_width//10

    h,w=dst.shape
    for r in range(h):
        c=0
        while c<w and dst[r,c]==0:
            c+=1

        max_w=0
        for i in range(w-1,-1,-1):
            if dst[r,i] !=0:
                max_w=i
                break

        start=0
        end=0
        flag=True
        for j in range(c,max_w):
            if flag and dst[r,j]==0:
                start=j
                flag=False
            if not flag and dst[r,j]!=0:
                end=j

                if end>start and end-start <= thres:
                    k=start
                    while k<end:
                        dst[r,k]=255
                        k+=1

                flag=True

    return dst

处理后的结果如下:

2.3、垂直投影

这个很好计算,这里不多介绍。直接看结果:

2.4、短斜线倾斜角度的统计计算

1、垂直投影测角原理

把斜体字进行抽象, 可以看成是一平行四边形。 一般地, 对于一个由黑象素组成的实心平行四边形图像 其垂直投影直方图是一梯形 。具体如下:

那么倾斜角度的计算公式为:

                             \small tan(A)=\frac{y_{1}}{x_{2}-x_{1}}

                            \small \angle A=arctan(\frac{y_{1}}{x_{2}-x_{1}})

也就是说我们可以通过上图第二个图来计算倾斜字体的角度,而第二张图就是我们的投影曲线了。所以我们计算投影曲线的角度也就是我们的倾斜角度。

但从2.3中的 投影图可知, 首先, 水平模糊后斜体字部分并非理想的平行四边形, 其次, 模糊图中存 在多个倾斜的边和倾斜角度信息, 但由于计算误差等原因, 可能存在一些错误的倾斜角度信息, 必须对所有倾斜角度信 息进行统计分析, 才可以获得更准确的测角信息。

需要注意的是:模糊区域边界部分投影曲线形状与字符 结构有较大关系, 例如字符边界不是竖直笔画 ( 英文字母 X)或边界笔画反而会干扰倾斜角度取得的字符 ( A, W等 ), 因此并非所有短斜线的斜率都是斜体字的斜率。 一般地, 正确的折线数量大于不正确的 。基于此, 本文在设计算法时采用 投票法来获取正确角度, 即对于得到的所有角度, 通过投票获知哪个角度出现的次数最多, 该角度就是要找的倾斜角度。

2、代码实现

这里代码不多详述,因为代码是公司的,所以能不能再贴了,有需要的小伙伴可以私底下聊,我会经量帮你解决。

2.5、倾斜校正

图像中倾斜字的校正实际上就是象素坐标的空间旋转 变换。 假设倾斜字符向右扭曲 , X 轴与水平轴重合 , Y 轴所 指方向为字符扭曲方向。如果将字符图像水平旋转使 Y 轴 所指方向与水平轴垂直, 则校正了图像的变形 现以一倾斜 字符“ 为例 , 推导空间变换公式如下:

旋转时 A 点以下的字符部分水平右移 , 以上部分水平左 移。 B 点为例 , 设旋转后的坐标值为 ( i, j), 易知水平右移 时纵坐标不变, 横坐标增加 BC, 则变换公式为 :
 
                                               
同理 , 左移部分变换公式为 :
 
                                               
然而图像中点的坐标值仍然为整数, 因此经过变换后所获得的结果必须进行取整操作, 这就存在误差 , 不可避免地造成图像失真。 本文采用双线性插值来降低取整带来的失真 , 并对校正后的二值图像进行平滑处理, 以消除插值带来的毛刺点。
 
具体实现如下:
def bilinear_interpolation(image,angle,center,y_min,y_max):
    '''对倾斜字体进行双线性插值'''
    center_x, center_y=center
    h,w=image.shape
    dst=np.zeros((h,w),dtype=np.uint8)

    for r in range(h):
        for c in range(w):
            #计算原图上的坐标
            i = r
            if r<center_y:
                j=c+(center_y-r)/math.tan(angle)
            elif r>center_y:
                j=c-(r-center_y)/math.tan(angle)
            else:
                j=c

            #计算源图上的四个近邻点
            x_0=max(int(np.floor(j)),0)
            y_0=max(int(np.floor(i)),0)
            x_1=min(x_0+1,w-1)
            y_1=min(y_0+1,h-1)

            #双线性插值
            if (x_0 >=x_1) or (y_0>=y_1):
                continue

            value0=((x_1-j)*image[y_0,x_0]+(j-x_0)*image[y_0,x_1])
            value1=((x_1-j)*image[y_1,x_0]+(j-x_0)*image[y_1,x_1])
            dst[r,c]=int(((y_1-i)*value0+(i-y_0)*value1))

    return dst


def correct_slanted_fonts(image,mask,angle):
    '''倾斜字体的矫正'''
    h,w=mask.shape

    # 计算倾斜字体的中心点
    center_x=0
    center_y=0
    num=0
    for r in range(h):
        for c in range(w):
            if mask[r,c]==255:
                center_x+=c
                center_y+=r
                num+=1

    center_x=center_x//num
    center_y=center_y//num

    #计算文本的上下边界
    ver_vec=np.sum(mask,axis=1)
    up=0
    down=0
    h=ver_vec.shape[0]
    for i in range(h):
        if ver_vec[i]!=0:
            up=i
            break
    for i in range(h-1,-1,-1):
        if ver_vec[i]!=0:
            down=i
            break

    #对图像进行双线性插值
    dst=bilinear_interpolation(image,angle,(center_x,center_y),up,down)

    # cv2.namedWindow("test1",0)
    # cv2.imshow("test1", dst)
    # cv2.waitKey(0)
    return dst

三、算法实现的最终结果

现在让我们来看看我们的需要校正的文本数据样例,部分具体样例图片如下:

 最终我们校正后的结果:

参考文献:

一种斜体印刷字倾斜角度检测算法

猜你喜欢

转载自blog.csdn.net/wxplol/article/details/105567497