版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第七章手写票据的光学字符识别背景新闻片段《“智慧税务”贴心又省心》发票申领越来越方便的背后,是发票电子化改革的逐步深入。2021年,国家税务总局建成了全国统一的电子发票服务平台,并于当年12月1日在试点地区成功推出全面数字化的电子发票,24小时在线免费为纳税人提供发票开具、交付、查验等服务,实现发票全领域、全环节、全要素电子化,为推动税收征管数字化转型提供有利条件。2022年9月,国务院办公厅发布的《关于进一步优化营商环境降低市场主体制度性交易成本的意见》提出,2022年底前,实现电子发票无纸化报销、入账、归档、存储等。手写票据识别的意义目前,企业重要的历史生产经营资料被以手写票据的形式保存。在需要纸质件签字、盖章、留作凭证的场景里,在潮湿、高温或低温等不宜使用电子设备的场景,例如工厂生产车间,企业还在不断产生新的手写票据。会计信息化、无纸化是审计发展的社会趋势,而其中重要的一个步骤就是手写票据的电子化。只有手写票据电子化,才能将更多、时间更早的、形式更丰富的生产经营信息录入到数字化审计大系统里,所以识别手写票据内容是大数据审计的必要预处理步骤。在企业实现审计电子化的过程中,识别手写票据的主要技术是光学字符识别。手写票据的光学字符识别是一项自动化审计的基础工具,是建立智能审计应用的基础。凭证文本信息录入的特例(1)POS机接入银行系统,为了金融安全,企业开发的审计应用通常不允许接入POS机获取数据,也不允许从网上银行直接调取账单,所以录入这些交易记录的唯一途径是,用POS机打印卷式机打小票和平推式机打小票,再通过光学字符识别录入其上信息。(2)在大部分地区,车船由当地公路铁路或航运公司运营,只承担当地短途交通的作用,并未接入全国路网也并未接入全国票务系统。在报销侧,业务人员的行程是不确定的,所以与全国的这些小型交通公司桥接数据是不现实的,而通过光学字符识别录入业务人员取回的票据更容易一些。在这些场景中,手写字符的光学字符识别比机打字符更难;并且,凭证文本信息录入是智能化的核心步骤,也是验真、验重、与数据库核对的基础。本章聚焦手写票据的文本信息录入,即从原始凭证的影印文件开始,到按字段录入票据上的全部信息结束。无论电子化进程如何,光学字符识别都有意义。案例场景本章所用的案例,介绍批量录入同种手写表格型票据的通用方法,具体要求如下:1、批量录入:同时处理一批同种票据,而不是每次运行时只处理一张票据,票据识别的数量每次可以超过50张。2、同种:票据使用同种模板,意义相同的字段处于不同票据的大致相同的相对位置。3、表格型:票据的主要内容被包含在一个表格中,有明显的外框线。特别强调,当需要识别不同种类的票据时,可以使用清分机,先分离票据的种类,再依次识别同种票据。手写票据识别的流程编程环境安装编程环境本章案例使用Linux类型的操作系统,Anaconda3管理的
Python3.10编程环境,使用到的第三方函数库保存在requirements.txt中。在已经安装好Python3.10并激活该环境的情况下,在终端中输入以下命令,可以安装同样的编程环境。pipinstall-rrequirements.txt在Linux操作系统中,直接输入以下命令,然后按提示安装Anaconda软件。wget/anaconda/archive/Anaconda3-2021.05-Linux-x86_64.sh
sh./Anaconda3-2021.05-Linux-x86_64.sh其中随着版本更新,Anaconda3-2021.05-Linux-x86_64.sh可能会变成不同的名称,请访问/anaconda/archive/
并从文件列表中找到最新版本。操作Anaconda进入编程环境操作conda环境的命令列出如下:创建新环境condacreate-n$environment_namepython=3.10激活环境condaactivteocr退出虚拟环境condadeactivate删除环境condaremove-nocr–all如上所述,可以创建多个虚拟环境,编写不同的程序。数据源在实际业务中,整理手写票据前通常使用高清扫描仪将图像信息录入计算机,本案例模拟这个过程,从单色PDF影印文件开始分析。扫描仪扫描仪通常会将扫描结果保存为高清PDF文件。如果可以直接连接扫描仪硬件,即可直接定义扫描参数。扫描后的图片与纸质件不同的是,图片的颜色空间是离散的,像素也是离散的,其中有两个重要参数:PPI和颜色空间。如果得到的是扫描仪输出的高清PDF文件,而无法直接控制扫描仪的参数,则要将PDF对应的PPI和颜色空间转换成文字识别所需要的。这里不需要考虑PDF文件中复杂的属性,只需要将PDF页面上显示的内容,即扫描的内容保存成图片即可。每页PDF保存成1张图片。数据源
表格和单元格定位模块流程表格和单元格定位是使用计算机视觉算法,从手写票据的影印文件开始,得到票据中所含表格的每个单元格的位置和尺寸。这个模块有4个重要步骤:解析PDF文件:本步骤的重点是内存管理,即随着处理的图片数量增加,程序占用的内存不应有明显增加。将表格作为一个整体,定位表格的位置。自动旋转表格至水平方向。定位每个单元格的位置,形成单元格位置列表,包含单元格的相对位置和尺寸。创建第一个文件创建tickets/table_layout.py文件,文件开头使用以下程序,引入第三方函数库。importpypdfium2aspdfium
importcv2
importnumpyasnp
importpandasaspdpypdfium函数库的主要作用是解析PDF格式的文件,cv2是opencv-python计算机视觉算法库,可以对图片作旋转、裁切、改变颜色、绘画等操作,numpy是用于处理数据的科学计算函数库,pandas函数库操作数据表。解析PDF文件解析PDF文件这个步骤的目的是将一个PDF文件解析成一批图片,需要设计一个函数:接受的输入是PDF文件路径,输出是一个列表,列表中的每个元素是一个图片。在tickets/table_layout.py创建函数。defpdf_to_image(path):
pages=[]#以后替换为功能片段
returnpages这将引入一个问题:存储图片所需的空间随图片数量线性增加。如果一个分析批次中有400张图片,占用的内存空间是处理100张图片的4倍。解析PDF文件这样做有必要吗?事实上是没有的。在大部分步骤中,不同图片是独立进行分析的,分析一个图片不要使用来自其他图片的信息。需要综合所有图片的统计步骤只在单元格配准模块出现,而单元格配准只需要单元格的位置,而不需要具体的图片内容。所以,这个函数的返回值应该是一个生成器,可以被遍历,但每次只处理一张图片,分析完毕后就被从内存空间中释放,然后再处理下一张图片。解析PDF文件在项目文件夹中创建文件1_bulk_recognition.py,该文件控制分析的总流程,以如下形式调用这个函数。fromtickets.table_layoutimportpdf_to_image
importpickle
filename='data/style1.pdf'
pages_generator=pdf_to_image(filename)
withopen(f'raw/style1_tables.pkl','wb')asf:
forpage,channelinpages_generator:
table=page#以后替换为分析片段
pickle.dump(table,f)解析PDF文件此时函数pdf_to_image创建了一个生成器。在下一行,创建了一个缓存文件,每次从生成器读取一张图片到page变量。处理完毕的图片被追加写入缓存,page变量被赋值为下一张图片。此时,上一张图片的内容实际已被覆盖,page对应的内存空间被反复使用,所以随着图片的增多,内存没有明显增加。具体到函数中的功能片段,查阅pypdfium2函数库的文档,可知pdfium.PdfDocument.render_to函数可以完成生成器的功能。解析PDF文件可以使用cv2.imwrite函数保存一张图片,检验本步骤结果的正确性。fromtickets.table_layoutimportpdf_to_image
importcv2
filename='data/style1.pdf'
pages_generator=pdf_to_image(filename)
page,channel=next(pages_generator)
cv2.imwrite('results/style1_page0.jpg',page)解析PDF文件表格定位表格定位为了解决这个问题,定位表格的位置是一个重要的步骤。除了作为定位单元格的基础,定位表格还有其他作用:案例目标是识别表格中的内容,而表格以外的其他文字都不重要,例如“收据”、“单位名称”、“单位(盖章有效)”、“开票人”。定位表格的同时,这些区域将被丢弃。避免扫描时受光影影响形成的不规则图案,被误认为文字,例如途中表格左侧空白区域的黑色噪点。表格定位
表格定位
表格定位表格的外框线(图7-4蓝色轮廓)多个相邻单元格的框线(图7-4红色轮廓)一个单元格的框线(图7-4绿色轮廓)有封闭图案的文字(图7-4橙色轮廓)表格定位在定位表格时,只需要图7-4中的蓝色轮廓。所以第2个参数选择cv2.RETR_EXTERNAL,找到所有的轮廓并选择面积最大的,就是表格区域。在函数locate_table中继续写入以下片段。size=[cv2.contourArea(x)forxincontours]
largest_outer_contour=contours[np.argmax(size)]轮廓是图片中非零数值的位置,所以是不规则形状;寻找表格时,需要取最大轮廓的包络矩形。x,y,w,h=cv2.boundingRect(largest_outer_contour)表格定位最终函数返回包络矩形区域,就是表格区域,完整的函数如下所示。deflocate_table(img):
img=cv2.bitwise_not(img)
contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
size=[cv2.contourArea(x)forxincontours]
largest_outer_contour=contours[np.argmax(size)]
x,y,w,h=cv2.boundingRect(largest_outer_contour)
returnimg[y:y+h,x:x+w]表格定位此时,流程控制文件1_bulk_recognition.py的内容如下。fromtickets.table_layoutimportpdf_to_image,locate_table
importpickle
filename='data/style1.pdf'
pages_generator=pdf_to_image(filename)
withopen(f'raw/style1_tables.pkl','wb')asf:
forpage,channelinpages_generator:
table=locate_table(page[:,:,0])
pickle.dump(table,f)其中locate_table的输入参数是page[:,:,0],因为数组page的维度axis=2表示颜色通道,又由于是单色图片,颜色通道的数量是1。我们只关心图片的横纵坐标,所以取消axis=2维度。表格旋转有时表格是倾斜的,而无论是裁剪表格或单元格,都会保留一个平直的矩形区域。如果单元格是倾斜的,则单元格的外边框和部分相邻单元格的内容都会进入视野,这会降低识别结果的准确性。所以,需要将表格自动旋转到水平方向。表格旋转在旋转表格时,当表格向左倾斜(左侧低于右侧)或向右倾斜(左侧高于右侧)时,应向不同方向和角度旋转,所以应区别讨论。
表格旋转在tickets/table_layout.py中创建函数locate_table_rotate并复制locate_table的内容,对得到了最大轮廓后的部分作修改。deflocate_table_rotate(img):
img=cv2.bitwise_not(img)
contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
size=[cv2.contourArea(x)forxincontours]
largest_outer_contour=contours[np.argmax(size)]
#表格旋转部分
returnimg表格旋转首先,函数cv2.boundingRect返回包络轮廓的平直矩形(StraightBoundingRectangle),而函数cv2.minAreaRect返回包络轮廓的面积最小的矩形,可以是倾斜的(RotatedRectangle)。box=cv2.minAreaRect(largest_outer_contour)取得矩形的尺寸和顶点。w,h=box[1]
source_points=cv2.boxPoints(box)对返回角度分类讨论,根据理论公式,将倾斜的矩形拉伸为合适大小的平直矩形。表格旋转完整的函数locate_table_rotate是:deflocate_table_rotate(img):
img=cv2.bitwise_not(img)
contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
size=[cv2.contourArea(x)forxincontours]
largest_outer_contour=contours[np.argmax(size)]
ifbox[2]>45:#左侧低,右侧高
destination_points=np.array([[0,0],[h,0],[h,w],[0,w]])
transformation=
cv2.getPerspectiveTransform(source_points.astype('float32'),
destination_points.astype('float32'))
rotated_table=cv2.warpPerspective(img,transformation,(int(h),int(w)))表格旋转
else:#左侧高,右侧低
destination_points=np.array([[0,h],[0,0],[w,0],[w,h]])
transformation=cv2.getPerspectiveTransform(source_points.astype('float32'),
destination_points.astype('float32'))
rotated_table=cv2.warpPerspective(img,transformation,(int(w),int(h)))
returnrotated_table单元格定位一个机器学习模型必须在准确性(Precision)和召回率(Recall)中作平衡。在本案例中,准确性指模型判定为单元格(例如图7-4绿色轮廓)的轮廓有多少概率确实是一个单元格;召回率指表格中的每个单元格有多少概率被模型判定为单元格。随着召回率提高,也就是有越来越多的单元格被模型识别到,算法返回的结果中也一定会有越来越多的“杂质”,即并非是单元格的轮廓。票据识别的目的,是尽可能多地录入票据中的信息。模型设计者此时有两种选择:设计一个高准确性、低召回率的模型。此时算法返回的结果几乎不需要整理,代价是遗漏了许多票据中的信息。设计一个高召回率、低准确性的模型。此时几乎所有票据中的信息被录入,但算法返回了许多冗余的字段和没有意义的字段。单元格定位对第二种选择,只要在最终的表格中删除不需要的列即可,在这个场景下是更优的选择。首先,提取所有单元格轮廓。contours,hierarchy=cv2.findContours(img,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)其中cv2.findContours的第2个参数代表以列表形式返回轮廓,不计算轮廓之间的层级关系。不过,这并不意味着模型设计者不需要考虑准确性;在保证召回率的情况下,最好仍然尽量提高准确性。可能的方法有:根据单元格可能的大小,过滤面积太大或太小的轮廓;面积太大的轮廓一定是由许多单元格共同组成的,包括表格外框线本身。至少有一种方法可以去除表格外框线本身。图7-4橙色轮廓由封闭笔画构成,而每张票据中的文字不同,所以在其他票据的同一相对位置,不一定有相同的轮廓。所以可以通过单元格配准过滤部分轮廓,事实上这类轮廓的比例不低。单元格定位
单元格定位最后,函数返回单元格配准部分需要的信息。完整的cells_position函数是:defcells_position(img,table_id):
contours,hierarchy=cv2.findContours(img,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
h,w=img.shape
sq_lb,sq_ub=max(784,h*w*6e-4),h*w*0.9
positions=np.array([cv2.boundingRect(x)forxincontours
ifsq_lb<cv2.contourArea(x)<sq_ub])
positions=positions[positions[:,2]*positions[:,3]<sq_ub,:]
positions_df=pd.DataFrame(columns=['x','y','w','h'],data=positions)
positions_df['table_id']=table_id
positions_df['table_w']=w
positions_df['table_h']=h
returnpositions_df单元格配准创建第一个文件本节使用DBSCAN聚类算法,识别来自不同票据的轮廓,有哪些属于同一个单元格。在上一节中提到,非单元格的轮廓在每张票据中有不同的相对位置,而表示单元格的轮廓在大部分票据中有相同的相对位置。所以在不同票据中,将相对位置相近的轮廓聚为一类,统计每个类出现在多少票据中,即可判断哪些类对应的轮廓(包络矩形)表示单元格。引入第三方函数库:importcv2
importnumpyasnp
importpandasaspd
fromsklearn.clusterimportDBSCAN其中sklearn函数库操作聚类算法。DBSCAN聚类聚类算法的输入和输出都是上一节得到的单元格位置信息表,聚类标签被添加到信息表中,作为增补的一列。输入的单元格位置信息表的格式如表所示。列名意义table_id票据编号table_w表格区域(表格定位的结果)宽度table_h表格区域(表格定位的结果)高度x单元格左上顶点横坐标y单元格左上顶点纵坐标w单元格宽度h单元格高度DBSCAN聚类考虑到每张票据的表格区域有不同的大小,所以这里用相对位置作为聚类的数据,即单元格的坐标或尺寸占表格尺寸的比例。positions=pd.DataFrame({
'relative_x':cells_df['x']/cells_df['table_w'],
'relative_y':cells_df['y']/cells_df['table_h']
})在表格中,每一行代表一个候选为单元格的矩形区域,记录了左上顶点的相对坐标。定性地,单元格的坐标更集中,其他区域的坐标更稀疏。DBSCAN聚类
DBSCAN聚类
DBSCAN聚类使用DBSCAN聚类算法拟合并赋予类别标签。dbscan=DBSCAN(eps=eps,min_samples=min_pts,n_jobs=-1)
cells_df['labels']=dbscan.fit_predict(positions)去除离群点。cells_df=cells_df.loc[cells_df['labels']!=-1,:]在同一张票据中,被标记为同一个类的单元格只保留一个。cells_df.drop_duplicates(subset=['table_id','labels'])每个类别都代表一个固定意义的单元格,例如“品名和类别的第一项”或“合计金额的百位数”之类,每张票据里具有相同类别编号的单元格代表相同的意义,所以票据编号、单元格编号、单元格坐标和尺寸,已经建立了对应关系。DBSCAN聚类完整的聚类函数:defget_cluster_labels(cells_df):
positions=pd.DataFrame({
'relative_x':cells_df['x']/cells_df['table_w'],
'relative_y':cells_df['y']/cells_df['table_h']
})
n_tables=cells_df['table_id'].max()+1
min_pts=int(n_tables*0.4)
relative_w=cells_df['w']/cells_df['table_w']
relative_h=cells_df['h']/cells_df['table_h']
eps=np.sqrt(relative_w.min()**2+relative_h.min()**2)*1.22475
dbscan=DBSCAN(eps=eps,min_samples=min_pts,n_jobs=-1)
cells_df['labels']=dbscan.fit_predict(positions)
cells_df=cells_df.loc[cells_df['labels']!=-1,:]
cells_df.drop_duplicates(subset=['table_id','labels'])
returncells_df描述性统计单元格配准的任务是否就这样完成了呢?没有,因为虽然这批识别出的单元格都拥有了类别编号,但是以后有新的同类票据,仍然无法知道单元格的位置在哪里。实际上,聚类算法的结果应该可以被复用,即:同种票据第一次出现时,通过聚类得到一个模板,上面标定了表格的哪些相对位置有哪些单元格。相同种类的票据再次出现时,只需要做表格定位和表格旋转,算得相对位置后套用模板,直接找到单元格位置,然后识别图片中的文字。在聚类模型的基础上,计算每个编号的单元格的平均位置,可以解决这个问题。这个步骤用文件tickets/cell_correspondence.py中的函数group_cells实现。其中,输入参数cells_df是上一个步骤的输出值,即一个包含了表格编号、单元格类别编号、单元格尺寸和位置、表格区域的尺寸的信息表。defgroup_cells(cells_df):
return描述性统计在group_cells函数中,计算每个编号的单元格的平均相对位置。defgroup_cells(cells_df):
n_tables=cells_df['table_id'].max()+1
cells_subtotals=[]
for(label,cells_subset)incells_df.groupby('labels'):
cells_subtotals.append({
'label':label+1,
'frequency':cells_subset.shape[0]/n_tables,
'avg_relative_x':(cells_subset['x']/cells_subset['table_w']).mean(),
'avg_relative_y':(cells_subset['y']/cells_subset['table_h']).mean(),
'avg_relative_w':(cells_subset['w']/cells_subset['table_w']).mean(),
'avg_relative_h':(cells_subset['h']/cells_subset['table_h']).mean(),
})
returnpd.DataFrame(cells_subtotals)描述性统计最终,函数输出一个信息表,其中label代表单元格的编号,frequency代表在已有的、用于制作聚类模型的这些票据(称为训练集)中,该单元格被识别到的比例。以avg_relative_开头的4列,表示单元格相对的宽、高、横纵坐标位置。其中,相对位置代表占表格区域的比例,即一张票据的表格区域的宽度是table_w,所以avg_relative_x*table_w是单元格左上顶点在这张票据的表格区域的坐标。即使不同票据的表格区域的位置和尺寸有差别,单元格在表格区域的相对位置和相对尺寸是不变的。模板可视化在函数中,读取一张图片的表格区域。这张图片可以是训练集中的任意一张图片的表格区域。img=cv2.bitwise_not(img)因为预处理时,对图片经过反色了。在可视化时,要再反色一次,使得图片恢复白底黑字。img=cv2.cvtColor(img[:,:,np.newaxis],cv2.COLOR_GRAY2RGB)然后获得图片的尺寸。h,w,_=img.shape在可视化部分,用红色矩形绘制单元格的相对位置。border_width=int(max(min(h/540,w/540),2))
for_,anchorinanchors.iterrows():
x1=int(anchor['avg_relative_x']*w)
y1=int(anchor['avg_relative_y']*h)
x2=x1+int(anchor['avg_relative_w']*w)
y2=y1+int(anchor['avg_relative_h']*h)
cv2.rectangle(img,(x1,y1),(x2,y2),(0,0,255),border_width)#BGR模板可视化
模板可视化利用这个函数,还可以显示更多的信息。例如,在上述函数的“文字标签”注释处,可以为单元格标注编号和被识别到的比例。cv2.putText(img,f"[{int(anchor['label'])}]{int(anchor['frequency']*100)}",
org=(x1,y2),fontFace=cv2.FONT_HERSHEY_SIMPLEX,fontScale=0.6,color=(0,0,255),thickness=border_width)该函数的效果是,例如一个单元格被标注为[90]96,代表这个单元格的编号是90,在训练集中有96%的票据上有这个单元格。这个比例可以作为一种置信度,在描述性统计部分,可以依据置信度,过滤掉置信度低于阈值的单元格。模板可视化识别结果有一些冗余信息和遗漏信息。例如,第90号单元格已经包括了固定表头“品名及规格”,但是第78、79、82、83、84号分别将这5个字当作了单独的单元格;固定表头“十万”、“角”、“分”的信息则遗漏了。由于实际填写的(每张票据都不同的)部分没有任何遗漏,这种结果在实际应用中是可以接受的。单元格内容识别基本框架上一节得到了单元格的相对位置。在本节中,对于每张图片(票据的表格区域),先套用单元格的相对位置,结合图片大小,得到每个单元格在票据中的实际位置。根据实际位置裁切单元格图片,就能够开始识别单元格的内容了。这个步骤可以用以下片段表示。其中,输入参数img代表一张图片,anchors_是函数group_cells的输出结果。本案例使用的文字识别模型LSTM-RNN-CTC是在白底黑字的图片上训练的,所以img=cv2.bitwise_not(img)一行对“表格和单元格定位”部分缓存的黑底白字的票据的表格区域再次使用反色。变量cell即为单元格区域。基本框架deftable_to_text(img,anchors_):
tb_h,tb_w=img.shape
x=np.round(anchors_['avg_relative_x'].values*tb_w).astype(int)
y=np.round(anchors_['avg_relative_y'].values*tb_h).astype(int)
w=np.round(anchors_['avg_relative_w'].values*tb_w).astype(int)
h=np.round(anchors_['avg_relative_h'].values*tb_h).astype(int)
img=cv2.bitwise_not(img)
foriinrange(anchors_.shape[0]):
cell=img[y[i]:y[i]+h[i],x[i]:x[i]+w[i]]
#图片预处理和文字识别
return基本框架导入需要用到的第三方函数库。importcv2
importnumpyasnp
fromopenvino.inference_engineimportIECore
fromlstm_rnn_ctc.ctccodecimportCtcCodec其中openvino是解析神经网络模型的引擎,文件夹lstm_rnn_ctc是从Intel的开源仓库中下载并修改的解析LSTM-RNN-CTC模型的方法。图片预处理
图片预处理对2种不同的情况分别处理:单元格的宽度小于2000像素,则向右填充白色,直至宽度等于2000像素。单元格的宽度大于2000像素,横向压缩图片,使得宽度等于2000像素。这种预处理方式有一个局限:只能识别单元格中的单行文字。这对票据识别来说足够了,但是如果表格有备注栏等可写多行文字的单元格,则无法正确识别。ifadjusted_cell_w<=net_w_:
processed_img=np.full((net_h_,net_w_),255)
processed_img[:,:adjusted_cell_w]=cv2.resize(img,(adjusted_cell_w,net_h_),interpolation=cv2.INTER_AREA)
else:
processed_img=cv2.resize(img,(net_w_,net_h_),interpolation=cv2.INTER_AREA)图片预处理神经网络接受一批图片,而这里只有一张,所以要增加一个维度代表存放图片的列表,并且要增加颜色通道的维度。所以返回值是processed_img[np.newaxis,np.newaxis,:,:].完整的preprocess_input函数是:defpreprocess_input(img,net_h_,net_w_):
cell_h,cell_w=img.shape
adjusted_cell_w=int(cell_w/cell_h*net_h_)
ifadjusted_cell_w<=net_w_:
processed_img=np.full((net_h_,net_w_),255)
processed_img[:,:adjusted_cell_w]=cv2.resize(img,(adjusted_cell_w,net_h_),interpolation=cv2.INTER_AREA)
else:
processed_img=cv2.resize(img,(net_w_,net_h_),interpolation=cv2.INTER_AREA)
returnprocessed_img[np.newaxis,np.newaxis,:,:]LSTM-RNN-CTC模型
LSTM-RNN-CTC模型在联结时间分类器获得字符位置后,神经网络将对应切片的图像传递给单字分类器,通常是一个卷积神经网络。卷积神经网络将使用包含约6000个常用中文文字及一些特殊符号的字典,以分类器的形式断定该图像中包含了哪个单字,从而完成文字识别。在实践中,我们通常没有足够的计算能力,也没有必要自己训练LSTM-RNN-CTC模型,而可以使用其他公司训练过并开源的模型。其他公司可能使用TensorFlow,PyTorch,Caffe等不同的深度学习函数库,输出的模型也可能有不同的格式,不方便我们使用。但是,OpenVino提供了一个神经网络模型编译器,将不同的深度学习函数库的神经网络模型格式,转化成统一的OpenVino格式,并附有配置文件。我们只需安装OpenVino,并下载预训练模型的配置文件和二进制模型本体,即可给OpenVino解析的模型传递数据,然后获得结果。LSTM-RNN-CTC模型如果项目文件夹的位置是~/Handwriting-Tickets-OCR,在终端中运行以下命令,下载OpenVino发行的LSTM-RNN-CTC模型。此时应检查系统设置和网络设置,确保能连接Intel的服务器下载模型。cd~/Handwriting-Tickets-OCR
pipinstallopenvino-dev
omz_downloader--namehandwritten-simplified-chinese-recognition-0001从Anaconda环境下复制文件至OpenVino文件夹。cp~/.conda/envs/ocr/lib/libpython3.9.so.1.0~/.conda/envs/ocr/lib/python3.9/site-packages/openvino/libsLSTM-RNN-CTC模型在文件tickets/table_ocr.py中初始化模型。首先,写入字符集。chars_list_file='lstm_rnn_ctc/scut_ept.txt'
withopen(chars_list_file,'r')asf:
model_characters=f.read()初始化CTC编码器。codec=CtcCodec(model_characters)初始化OpenVino解析器。ie=IECore()使用解析器解析模型的配置文件和模型本体。model_xml='intel/handwritten-simplified-chinese-recognition-0001/FP16-INT8/'\
'handw
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 23《童年的发现》教学设计
- 山东方亚新材料有限公司新型高端铝复合材料生产项目水土保持方案报告表
- 人工智能通识导论(理论篇)课件 第7章-身体与智能:具身智能新前沿
- 2026扶贫案例面试题及答案
- 2026年AR物流调度的车辆分配交互
- 2026安卓经典面试题及答案
- 附着式、平板式振动器操作安全技术交底
- 近五年高考英语真题词:753个阅读核心词+185个写作提分词
- 第12课 大画家王冕教学设计小学地方、校本课程浙教版人·自然·社会
- 2025-2026学年阅读课教学设计英语初中
- 办公楼及停车场物业服务项目方案投标文件(技术方案)
- 云南省临沧市临翔区第一中学2025届数学七下期末达标检测试题含解析
- DB14-T 2819-2023 煤炭洗选企业信息化建设规范
- 办公楼消防安全知识培训
- 个人抵押借款简易合同示例
- 拇外翻课件完整版本
- 排水沟盖板施工方案
- 铜绿假单胞菌实验活动风险评估报
- 2024年春巴中市七年级语文期末考试卷(附答案解析)
- DB31T 1497-2024 无人机喷洒防治林业有害生物技术规程
- 大数据在客户关系管理中的应用手册
评论
0/150
提交评论