在手写汉字的处理中对于不同的文本采用不同的分割处理方法:
对于文本块的处理应先进性腐蚀操作在进行连通域判断即可在一张仅有文本区域的内容中。
利用连通区域腐蚀的方法也可以进行目标的检测。
在对比较贵整的文本内容,例如表格等内文本的检测可以利用投影法进行初步的划分,之后再利用汉字统计结构(长宽比等)对划分的区域进行进一步的处理。
在文本发生不规则的倾斜的文本中利用连通区域检测的算法,可以更好的检测出文本出现的区域,之后再利用汉字统计结构的变化对初步划分的结果进行改进。
一种改进的投影法进行文本区域的划分利用小波变换把波峰和波谷变得更加明晰,便于划分。
对于表格中文本的处理应先按照表格边框的倾斜程度进行倾斜矫正,从而更好的利用投影法对文本进行分割。
在利用连通域对文本进行分割时可以先进性膨胀之后在进行腐蚀操作,腐蚀采用内聚膨胀,进行腐蚀进行边缘腐蚀,这种做法可以扩大去除汉字之间的部分间隙,同时也可以去除汉字内部的间隙。
膨胀核矩阵
0 0 1 0 0
0 0 1 0 0
1 1 1 1 1
0 0 1 0 0
0 0 1 0 0
腐蚀核矩阵
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
在本次汉字的分割中采取闭运算,先进行文字间的膨胀运算,之后在进行腐蚀运算,之后运用连通算法进行文本的分割。
图1 手写汉字初步分割无表格
在对识别之后得汉字进行编号并将无法识别的文字空出,并交给神经网络进行处理。类似于训练一个阅读理解的神经网络进行填词。
在核的大小设置中5*5的较为合适,若选用3*3的则会太小,会损失字符本身的清晰度,若选用7*7的则会在腐蚀时不易使得字之间的间隙隔开分割效果不理想。
在文本的使用中运用闭运算只能在初步对文本的分割起到较好的效果但还有部分分割字无法分割开,此时可根据字形结构对文本分割进行判断,若宽度超过一定比例责任为是粘连的3个字或者是2个字,在根据手写者写字的统计特征进行进一步分割。
在基于连通域的手写汉字的初步分割中可以不采用文本行分割的算法。
下面将采用基于图像作者书写文本的大小进行进一步分割,分割结果图如下图:
图2 利用取出极限后的平均数对文本进行划分可以取出部分的粘连字符
取出分割出的小的文本框,则设置一定的宽度或所选区域面积阈值当小于某一阈值时则不画出该文本框。
图3 设定阈值去除多余的文本框
在文本选择中可选择多种分割方式进行组合,如果选择初步的分割无法识别某些字符可在该字符出进行调整。选取合适的区域选出字符进行识别。在文本送入神经网络进行识别的过程中,应统计字符的个数,并对字符进行编号。随后便于识别出的字符的输出。
在采用闭运算时会将原本有空隙的一部分的空隙变得消失因此应将闭运算之后得图像与原图像分割的文本框对比结合着进行分割。
图4 未经过闭运算直接的运算
不经过闭运算回在内部生成许多小框块,各部分都会生成小框。如果小于因此必须将小框进行合并。
在文本的行分割中可以采取,膨胀,之后进行连通运算进行文本行的分割。在此处可以采用7*7的膨胀运算,进行文本行的分割。
实验记录:
在预处理中运用中值滤波能去除部分噪声但也会使得图像中文本变得更加模糊,因此在取出噪声时应选取另外一种方法进行预处理。
怎样进行文本的倾斜矫正:
图5 原表格文本
在处理较大的图片时,应先将较大的图片进行适当的缩小之后再进行处理效果较好,例如一张扫描的图片0.8M,通过截图使其变成100kb大小左右的图片更有利于对图中文本的处理。
在膨胀腐蚀运算中对于间隔较小的文字不太理想。也不可用腐蚀后膨胀的运算,腐蚀很容易去掉文字的大体结构,因此在腐蚀后进行膨胀的开运算很难恢复原文字的大致轮廓。
在表格中的文字运用腐蚀膨胀运算处理效果并不理想。因此在表格中的文字应选择用投影法对表格进行字符的分割,在处理中应选择细分方法,对文字做进一步的划分。
在对图像的处理中设置一部分的框大小阈值可以过滤去除一部分的框。
先进性灰度化、中值滤波之后进行
倾斜矫正步骤:
- 检测出图中的文本范围
- 计算出文本被旋转的角度
- 将图像旋转特定的角度
矫正对比图如下:
图6 经过倾斜矫正后的文本与原文本的对比图
对经过倾斜矫正后的表格进行按间隙的分割方法进行处理。即按峰值的方法进行处理。在此处可以用到小波变换。
在表格文字的处理中应去除表格的水平线避免影响其分割的效果。去除表格线并进行倾斜矫正后的水平分割效果图如下图:
图4 去除表格边框后的水平切分图
添加水平直线效果图:
图5 粗切分最终效果图
在粗切分之后应对表格进一步进行细化切分。运用宽度的统计分析设计1.4倍的平均宽度值判断其为两个字符还是一个字符。以及三个字符的判断,并以1/2的总宽度进行再次的分割。其结果图如下。
图5 只对部分的分割汉字有效
在细分个后效果也不太好。仅能改善部分的分割效果图。1.4倍的平均宽度值判断其为两个字符。
图6 改善后的分割效果
单纯的运用基于字形统计的方法进行文本的进一步细分还会分错部分字符,因此应该结合字符粘连之间的像素特征对汉字进行分割。利用笔画之间的连接特征进行字符的分割。
在对字符进行细化之后在进行分割。在分割中如果分割线处的字符总的像素值大于一定的值则不进行分割选择下一处作为分割线在平均值左右寻找粘连最少即像素值最低的区域作为分割区域。
代码如下:
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
#base_dir = "/root/workspace/deep_ocr"
#path_test_image = "test_data.png"
def pepper(img, n):
for k in range(n):
i = int(np.random.random() * img.shape[1])
j = int(np.random.random() * img.shape[0])
if img.ndim == 2:
img[j, i] == 0
elif img.ndim == 3:
img[j,i,0]= 0
img[j,i,1]= 0
img[j,i,2]= 0
return img
path_test_image = "test_data.png"
image_color = cv2.imread(path_test_image)
print(image_color.shape)
new_shape = (image_color.shape[1] * 2, image_color.shape[0] * 2)
image_color = cv2.resize(image_color, new_shape)
#image_color = cv2.resize(image_color, (284,216))
image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
#image=np.rot90(image)
#erzhihua
adaptive_threshold = cv2.adaptiveThreshold(
image,
255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY_INV, 11, 2)
adaptive_threshold = pepper(adaptive_threshold, 500)
adaptive_threshold1=cv2.medianBlur(adaptive_threshold,3)
adaptive_threshold2=cv2.medianBlur(adaptive_threshold,5)
#adaptive_threshold3=cv2.medianBlur(adaptive_threshold,7)
adaptive_threshold3=adaptive_threshold
cv2.imshow('yuan1', adaptive_threshold3)
#
#cv2.imshow('Media3', adaptive_threshold1)
#cv2.imshow('media5', adaptive_threshold2)
#cv2.imshow('media7', adaptive_threshold3)
#
#
#cv2.waitKey(0)
horizontal_sum = np.sum(adaptive_threshold3, axis=1)
#plt.plot(horizontal_sum, range(horizontal_sum.shape[0]))
#plt.gca().invert_yaxis()
#plt.show()
print(horizontal_sum)
print(horizontal_sum[1])
def extract_peek_ranges_from_array(array_vals, minimun_val=230, minimun_range=2):
start_i = None
end_i = None
peek_ranges = []
for i, val in enumerate(array_vals):
# print("val")
# print(val)
# print("***************************i*****************************8")
# print(i)
if val > minimun_val and start_i is None:
start_i = i
elif val > minimun_val and start_i is not None:
pass
elif val < minimun_val and start_i is not None:
end_i = i
if end_i - start_i >= minimun_range:
peek_ranges.append((start_i, end_i))
start_i = None
end_i = None
elif val < minimun_val and start_i is None:
pass
else:
raise ValueError("cannot parse this case...")
return peek_ranges
peek_ranges = extract_peek_ranges_from_array(horizontal_sum)
line_seg_adaptive_threshold = np.copy(adaptive_threshold3)
for i, peek_range in enumerate(peek_ranges):
x = 0
y = peek_range[0]
w = line_seg_adaptive_threshold.shape[1]
h = peek_range[1] - y
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(line_seg_adaptive_threshold, pt1, pt2, 255) #huaxianhanshu(cv2.rectangle)
cv2.imshow('line image2', line_seg_adaptive_threshold)
#cv2.waitKey(0)
vertical_peek_ranges2d = []
for peek_range in peek_ranges:
start_y = peek_range[0]
end_y = peek_range[1]
line_img = adaptive_threshold[start_y:end_y, :]
vertical_sum = np.sum(line_img, axis=0)
vertical_peek_ranges = extract_peek_ranges_from_array(
vertical_sum,
minimun_val=40,
minimun_range=1)
vertical_peek_ranges2d.append(vertical_peek_ranges)
## Draw
color = (0, 0, 255)
for i, peek_range in enumerate(peek_ranges):
for vertical_range in vertical_peek_ranges2d[i]:
x = vertical_range[0]
y = peek_range[0]
w = vertical_range[1] - x
h = peek_range[1] - y
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(image_color, pt1, pt2, color)
cv2.imshow('char image3', image_color)
#cv2.waitKey(0)
def median_split_ranges(peek_ranges):
new_peek_ranges = []
widthes = []
for peek_range in peek_ranges:
w = peek_range[1] - peek_range[0] + 1
widthes.append(w)
widthes = np.asarray(widthes)
median_w = np.median(widthes)
for i, peek_range in enumerate(peek_ranges):
num_char = int(round(widthes[i]/median_w, 0))
if num_char > 1:
char_w = float(widthes[i] / num_char)
for i in range(num_char):
start_point = peek_range[0] + int(i * char_w)
end_point = peek_range[0] + int((i + 1) * char_w)
new_peek_ranges.append((start_point, end_point))
else:
new_peek_ranges.append(peek_range)
return new_peek_ranges
vertical_peek_ranges2d = []
for peek_range in peek_ranges:
start_y = peek_range[0]
end_y = peek_range[1]
line_img = adaptive_threshold[start_y:end_y, :]
vertical_sum = np.sum(line_img, axis=0)
vertical_peek_ranges = extract_peek_ranges_from_array(
vertical_sum,
minimun_val=40,
minimun_range=1)
vertical_peek_ranges = median_split_ranges(vertical_peek_ranges)
vertical_peek_ranges2d.append(vertical_peek_ranges)
## Draw
color = (0, 0, 255)
for i, peek_range in enumerate(peek_ranges):
for vertical_range in vertical_peek_ranges2d[i]:
x = vertical_range[0]
y = peek_range[0]
w = vertical_range[1] - x
h = peek_range[1] - y
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(image_color, pt1, pt2, color)
cv2.imshow('splited char image4', image_color)
cv2.waitKey(0)