【Unity萌新学习记录】百度OCR文字识别引入Unity实现Unity手写文字识别功能

0.写在前面
第一次写教程,如有疏漏或者错误的地方,还请指正
本教程将介绍如何使用Unity实现手写文字识别
本教程使用的Unity编辑器版本: 2020.3.30f1c1
编译器: Visual Studio 2019 Community
测试设备:LEGION y9000p 2021H i7-11800H@2.30GHz
测试环境:Windows 10 20H2 家庭中文版
项目概述
在Unity中实现在Canvas上实现用鼠标手写
在手写功能完成后,成功接入百度的手写文字OCR识别API
最后实现的基本效果是:用户可以在Canvas上写字,写完字后按下空格键即可调用百度的手写文字OCR识别,识别成功后将在Unity控制台生成Debug信息返回识别结果,支持清空画布字迹重新书写。
后续会进一步优化,实现识别结果在屏幕上显示识别文本结果等功能
1. Unity在Canvas上手写文字的实现
1.1准备工作
打开Unity Hub 新建一个2D项目,根据喜好给项目命名,最好是英文命名。(防止Unity出一些奇怪的问题)
本教程命名为"Handwritten character recognition",并关闭版本管理。

1.2画布的基本设置
建立一个Canvas

选中Canvas,在Inspector面板中
将Canvas的渲染模式改成Screen Space-Camera。

然后选中Main Camera,将其拖到Canvas组件中的Render Mode中去,如下图。

点击Game视图,然后点击“display1”旁边的按钮,我们新建一个分辨率,比如2400x1080。


创建好后我们回到编辑视图(Scene),在Canvas下右键创建一个image。

然后使用Anchor Present工具让image填充整个Canvas
步骤及效果如下图。


这样,画布的基本的设置就完成了。
1.3实现在Unity画布上写字
在Project面板上创建一个文件夹,文件夹命名为“Scripts”。

点击Scripts文件夹,在Project窗口右键创建一个C#脚本,命名为 DrawLinesWithMouse

双击打开后,应该会自动打开Visual Studio来编写脚本。
然后编写以下代码


然后Ctrl+S保存,之后回到Unity编辑器
在Hierachy(层级面板)中,右键创建一个空物体,命名为Draw Manager。


将脚本挂载到Draw Manager中
(直接将脚本拖入Inspector面板或者在DrawManager面板中的Add Component 中搜索 DrawLinesWithMouse,然后确定。

现在运行项目,尝试在画布上按住鼠标拖动书写,应该能画出红色的字迹
(如下方GIF所示)

我们再次回到DrawManager中,观察DrawLinesWithMouse脚本
可以根据个人喜好调节笔迹的参数。

比如说将Line Width调成0.1,Line Color 调成纯黑色,然后运行项目,效果如图。

1.4实现“一键清除字迹”
测试没有问题后,我们将给负责手写的脚本,也就是 DrawLinesWithMouse这个脚本升级,也就是添加功能
假如我们觉得书写的比较乱的时候,想一键清空画布上的笔迹
我们可以尝试修改DrawLinesWithMouse脚本

修改代码完成后
现在,我们创建一个按钮
在Hierachy(层级面板)中,右键创建一个按钮,根据项目需要来选择Button还是Button-TextMeshPro
本教程使用Button-TextMeshPro。

然后会自动弹出TMP Importer,分别点击“Import TMP Essentials”和“Import TMP Example & Extra”按钮,然后关闭窗口。

然后将按钮“Button”重新命名为“ClearButton”
之后点击Button旁边的“三角号”,点击“Text(TMP)”
在Inspector面板中可以修改显示的文本。

如果要显示中文的话,需要创建一个TMP字体。
用默认的LiberationSans字体是不支持显示中文的。
这时候我们需要快捷键Win+E 打开资源管理器。
然后在上面的搜索框中将下面的路径复制到搜索栏上
C:\Windows\Fonts

这里是存放字体的文件夹,挑一个支持中文的字体然后将它拖入到Unity中。
(提示:尽量不要拖入微软雅黑字体,因为导入的时间非常的长)

这里用苹方字体来做演示。

然后在Unity中创建一个名为Fonts的文件夹,将要使用的字体文件拖入到该文件夹中,然后选中该字体,Shift+Ctrl+F12来快速创建一个TMP字体。



然后选择Button下的Text(TMP),在Inspector面板中把生成的字体拖入到Font Asset的位置来更换支持中文显示的字体。

现在,就可以在文本框里输入中文了。

当然也可以调节字体大小,字重,左右对齐,文字居中,根据个人喜好调整。
现在看画布的按钮有点小,我们重新选中Button,然后可以按下R键(输入法为英文模式下摁R)进入物体缩放模式,鼠标按住中间的白色方块然后上下拖动调整合适的大小。

然后把这个按钮移动到合适的位置(选中Button然后在编辑状态下按W)


一切调整完成后,我们就要开始设置这个按钮了。



此时,运行游戏,用鼠标写字,写好之后点击按钮,就会清除屏幕上的所有字迹(如下方GIF所示)。

现在,在Unity上用鼠标写字的基本功能就完成了!
2. 接入百度的手写文字OCR识别API
(注:由于教程的时效性,一些操作细节,比如百度云的应用创建入口和创建方式可能会和本教程有所差异,如有不同之处,一切以实际为准)
2.1 基础设置
创建Baidu Ai应用
首先点击这个链接,用自己的百度账号登录,没有百度账号就自己注册一个
https://login.bce.baidu.com/?redirect=https%3A%2F%2Fconsole.bce.baidu.com%2Fai%2F%3Ffromai%3D1#/ai/ocr/app/list
(如果手机上有使用百度的App产品并且是登录状态也可以使用App的扫码登录,比如百度贴吧)

登录成功后先点击三道杠图标,再点击产品服务,然后找到文字识别

点击公有云服务,然后点击应用列表

然后创建应用

应用归属:个人
应用描述:文字识别

创建完成后下载SDK



下载好压缩包后找到下载位置
在你的浏览器上按下Ctrl+J快速定位下载内容
(以Chorme浏览器为例,基于Chorme内核的浏览器应该都可以用此快捷键)

选择一个合适的文件路径然后用解压软件解压这个压缩包

解压完成后会出现这两个文件夹,我们主要使用netstandard2.0框架,当然具体细节稍后再说,现在我们先回到Unity

回到Unity
我们要根据PlayerSetting的对应选项选择对应的SDK
具体步骤是
① 点击File菜单。
② 选择BuildSettings。
③ 选择PlayerSettings。
④ 选择OtherSettings。
⑤选择APICompatibility选项,根据选项版本选择对应的SDK
(我们前面说过,选择netstandard2.0)



然后回到Assets文件夹,创建一个文件夹,命名为Plugins,并打开该文件夹



2.2 编写脚本及环境的正确配置(Newtonsoft.Json.dll)

然后编写脚本如下。

API KEY和Secret Key的查看。

编写此脚本完成后
此时会发现脚本会有两处报错。

发生这种情况的原因主要是Newtonsoft.Json.dll配置的问题,我们在百度下载到的SDK中net45自带的Newtonsoft.Json.dll版本太旧,所以我们需要正确引入最新的Newtonsoft.Json.dll。
首先是Visual Studio部分
在“解决方案资源管理器”中,点击解决方案,然后右键
点击“管理解决方案中的NuGet程序包”。

在NuGet-解决方案中下载并安装新的Newtonsoft.Json


正确安装之后,编译器的两个报错就消失了。

虽然编译器报错是消失了,可是Unity编辑器重载编辑后的脚本还是会显示报错。
别担心,这不是Unity编辑器的Bug,这还是Newtonsoft.Json.dll的问题。

我们之前在Unity导入了一个百度SDK里面的Newtonsoft.Json.dll,就是它的问题,我们的这个脚本需要更高版本的Newtonsoft.Json.dll,百度提供的这个Newtonsoft.Json.dll版本低,所以Unity会报错。
因此,我们需要删除百度提供的旧版本,安装新版本
在浏览器上搜索Newtonsoft官网,通常第一个就是了。

点进去,然后点击Download。

此时网站会出现一个弹窗,提供下载选择,我们选择下载Json NET。

然后跳转到改项目的GitHub上,点击Json.130r3.zip
此时浏览器会自动下载
(考虑到大部分人上不去GitHub,所以这里留下一个百度网盘下载Json.130r3.zip的链接,以供方便下载)
链接:https://pan.baidu.com/s/1BXB7YKZ_SIIE2rn9h6t_1g?pwd=SZMT
提取码:SZMT
--来自百度网盘超级会员V4的分享

然后解压下载好的压缩包

按照图示的这个路径找到Newtonsoft.Json.dll(这个是新版的)

然后回到Unity删除百度旧版的Newtonsoft.Json.dll

将新版的Newtonsoft.Json.dll拖入Unity
(注意拖入的文件夹,还有就是Newtonsoft.Json.dll新版旧版不要弄混了!)

如果以上步骤都正确,此时的情况如上图,会提醒警告信息,像是
“Assets\Scripts\HandwritingRecognition.cs(105,33): warning CS1701: Assuming assembly reference 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' used by 'AipSdk' matches identity 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' of 'Newtonsoft.Json', you may need to supply runtime policy”
尽管有警告
但此时,它已经不影响项目的正常运行了
现在在Hierachy面板上创建一个空物体,命名为OCR Manager,并将脚本挂载到OCR Manager上去

一切都设置好了之后
我们还需要回到百度智能云平台,目的是领取应用接口免费使用次数
https://login.bce.baidu.com/?redirect=https%3A%2F%2Fconsole.bce.baidu.com%2Fai%2F%3Ffromai%3D1#/ai/ocr/app/list


免费资源大概10分钟之内数据就可以更新了
(注:百度的手写识别接口仅有500次免费次数)
领取免费资源成功之后
现在,可以尝试运行项目
先用鼠标在画板上写字

然后按下空格键
之后将会在Unity控制台(Console)中返回文字识别结果,如下图


至于为什么控制台返回的结果是这种格式的,请自行查阅百度官方文档
https://ai.baidu.com/ai-doc/OCR/Vkibizy8i#%E6%89%8B%E5%86%99%E6%96%87%E5%AD%97%E8%AF%86%E5%88%AB

至此,Unity接入百度API识别手写文字的基础框架就已经完成了!
3. 手写文字识别功能的进一步优化
3.1 自定义文字识别区域
虽然我们成功实现了百度OCR文字识别,但是从刚刚控制台返回的结果来看,似乎出了一些问题

手写文字是识别成功了,但是它也将按钮上的文字也识别并返回结果到控制台了,这将会干扰最终的识别结果
因此我们要优化"HandwritingRecognition"代码
我们要用代码控制文字识别的区域,所以我们要修改代码
修改如下

然后Ctrl+S 保存,回到Unity
此时发现OCR Manager中的HandwritingRecognition多了一个ScreenShot Rect

这里解释一下,screenshotRect的作用是控制截取屏幕的范围
以屏幕的左下角为起点(0,0)
以上方向和右方向作为正方向延伸
X,Y值控制着起点的初始左边(默认是0,0)
W即Screen.width,代表当前屏幕的宽度
H即Screen.height,代表当前屏幕的高度
例:new Rect(100, 100, 500, 500)表示从屏幕上(100,100)的位置开始,截取宽度为500,高度为500的区域。
知道了这些之后,我们就根据调节screenshotRect中的四个参数来调节文字识别区域的范围,比如说W:2000,H:1080
(根据项目的实际情况多次尝试)
通常不建议调节X,Y值,就默认0,0吧
如下图

3.2 添加一个文字识别的按钮
假如我们的项目最后将要在移动设备运行(如安卓手机)
而现在触发文字识别的方式是按下物理键盘上的空格
放到安卓手机上似乎是行不通的
所以我们需要添加一个按钮,并编写一个方法,通过按下屏幕上的按钮来进行文字识别

然后添加一个按钮(Recognize),其中的文本命名为“开始识别”

然后给新添加的按钮添加方法


最后的结果如下

3.3 文字识别结果在屏幕上可视化
我们还要在刚才的基础上在添加一个功能,那就是
这样用户就可以看得到到文字的识别结果,达到向用户反馈信息的目的
那么就继续修改代码




最终结果

3.4 文字识别结果包含特定字符将触发事件
我们继续添加功能,当用户在画板上手写文字,然后返回识别结果,当识别结果包含特定的字符时,就会触发某个事件
比如说,当识别结果包含"数字媒体"这四个字时,就显示隐藏的按钮“你赢了”
修改代码如下


然后Ctrl+S保存
回到Unity,进行如下设置



最终效果

现在这个Unity手写文字识别的框架完成度已经很很高了
利用这个框架可以做一个简易的看图写字小游戏
比如在画布上放一个苹果的图片,要求用户在画布上写出苹果两个字
我们需要把公共变量Keyword写上"苹果"两个字
再放上需要隐藏的按钮(或者是其他的什么游戏元素也可以)
当用户手写"苹果"两个字并且被成功识别
隐藏的元素就会显示出来
可以根据自己的创意和想法自行调整
本教程完
By Arz-神奇的阿零Tianlst
2023.7.19