这里主要记录下我在工作中对倾斜字体文本行的校正的方法探索,废话不多,一起说来看看吧。
目录
实现倾斜文本行字体的校正主要分为两部分,一部分为倾斜角度的检测,另一部分为倾斜校正。其中倾斜角度的检测极为重要,他关系到后续的校正。
一、算法流程图
二、算法实现
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、垂直投影测角原理
把斜体字进行抽象,
可以看成是一平行四边形。
一般地,
对于一个由黑象素组成的实心平行四边形图像
,
其垂直投影直方图是一梯形 。具体如下:
那么倾斜角度的计算公式为:
也就是说我们可以通过上图第二个图来计算倾斜字体的角度,而第二张图就是我们的投影曲线了。所以我们计算投影曲线的角度也就是我们的倾斜角度。
但从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
三、算法实现的最终结果
现在让我们来看看我们的需要校正的文本数据样例,部分具体样例图片如下:
最终我们校正后的结果:
参考文献: