AI通用文字识别初体验
一、功能简介
文字识别的核心技术是OCR(Optical Character Recognition,光学字符识别)。OCR是一种通过拍照、扫描等光学输入方式,把各种票据、卡证、表格、报刊、书籍等印刷品文字转化为图像信息,再利用文字识别技术将图像信息转化为计算机等设备可以使用的字符信息的技术。
HarmonyOS提供的文字识别功能在一定程度上支持文本倾斜、拍摄角度倾斜、复杂光照条件以及复杂文本背景等场景的文字识别。
二、搭建HarmonyOS环境
HarmonyOS开发环境搭建,可参照如下步骤进行:
1.安装DevEco Studio
DevEco Studio的下载链接如下:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/software_install-0000001053582415
2.设置DevEco Studio开发环境
DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
- 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
- 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
三、代码结构解析
基于AI的通用文字识别示例教程主要内容包括:图片列表展示、输入文本、分词、通用文字识别、结果展示等功能。DevEco Studio工程代码结构如下:
- provider:PictureProvider图片适配类,获取所有图片,并将图片放到图片列表中。
- slice:MainAbilitySlice本示例教程主页面。
- util:工具类
- LogUtil是日志打印类,对HiLog日志进行了封装。
- WordRecognition是通用文字识别类,对图片中的文字进行识别并保存。
- WordSegment是分词类,对输入文本进行分词。
- MainAbility:主程序入口,DevEco Studio生成,未添加逻辑,不需变更。
- MyApplication:DevEco Studio生成,不需变更。
- resources:存放工程使用到的资源文件
- resources\base\element中存放DevEco studio自动生成的配置文件string.json,不用变更。
resources\base\graphic中存放页面样式文件:
background_ability_page.xml用于设置界面背景颜色。
background_ability_main.xml用于设置界面布局样式。
button_element.xml用于设置按钮样式。 - resources\base\layout中布局文件:
ability_main.xml用于展示图片和输入文本。
item_image_layout.xml用于设置图片滑动区域图片。 - resources\base\media下存放图片资源(本教程使用了8张.jpg图片,开发者自行准备;icon.png由DevEco Studio生成不需变更)。
- resources\base\element中存放DevEco studio自动生成的配置文件string.json,不用变更。
- config.json:配置文件。
四、代码实践
1.添加并展示图片
首先在"resources\base\media"目录下添加8张jpg图片(分别命名为1-8.jpg),并加载图片id数组,代码如下:
private int[] pictureLists = new int[]{ResourceTable.Media_1, ResourceTable.Media_2,
ResourceTable.Media_3, ResourceTable.Media_4, ResourceTable.Media_5,
ResourceTable.Media_6, ResourceTable.Media_7, ResourceTable.Media_8};
接着获取图片id数组和MainAbilitySlice对象,代码如下:
public PictureProvider(int[] pictureLists, Context context) {
this.pictureLists = pictureLists;
this.context = context;
}
定义ViewHolder类,用于列表中展示图片,代码如下:
private static class ViewHolder {
Image image;
}
最后将图片到页面,代码如下:
@Override
public Component getComponent(int var1, Component var2, ComponentContainer var3) {
ViewHolder viewHolder = null;// Component中展示图片类
Component component = var2;
if (component == null) {
component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_image_layout,
null, false);
viewHolder = new ViewHolder();
Component componentImage = component.findComponentById(ResourceTable.Id_select_picture_list);
if (componentImage instanceof Image) {
viewHolder.image = (Image) componentImage;
}
component.setTag(viewHolder);//设置需要展示的图片
} else {
if (component.getTag() instanceof ViewHolder) {
viewHolder = (ViewHolder) component.getTag();
}
}
if (viewHolder != null) {
viewHolder.image.setPixelMap(pictureLists[var1]);
}
return component;
}
2.识别图片中的文字
首先调用文字识别方法对图片文字进行识别,代码如下:
wordRecognition(slice, pictureLists[index], handle); //index为待识别图片下标
public void wordRecognition(Context context, int resId, MainAbilitySlice.MyEventHandle myEventHandle) {
mediaId = resId;
// 实例化ITextDetector接口
iTextDetector = VisionManager.getTextDetector(context);
// 实例化VisionImage对象image,并传入待检测图片pixelMap
pixelMap = getPixelMap(resId);
VisionImage image = VisionImage.fromPixelMap(pixelMap);
// 定义VisionCallback<Text>回调,异步模式下用到
VisionCallback<Text> visionCallback = getVisionCallback();
// 定义ConnectionCallback回调,实现连接能力引擎成功与否后的操作
ConnectionCallback connectionCallback = getConnectionCallback(image, visionCallback);
// 建立与能力引擎的连接
VisionManager.init(context, connectionCallback);
}
定义将图片中文字识别结果通过sendResult()方法发送到主线程的方法,代码如下:
private VisionCallback getVisionCallback() {
return new VisionCallback<Text>() {
@Override
public void onResult(Text text) {
sendResult(text.getValue());
}
};
}
连接引擎成功后进行文字识别,并将识别结果通过sendResult()方法发送到主线程,代码如下:
private ConnectionCallback getConnectionCallback(VisionImage image, VisionCallback<Text> visionCallback) {
return new ConnectionCallback() {
@Override
public void onServiceConnect() {
// 实例化Text对象text
Text text = new Text();
// 通过TextConfiguration配置textDetector()方法的运行参数
TextConfiguration.Builder builder = new TextConfiguration.Builder();
builder.setProcessMode(VisionConfiguration.MODE_IN);
builder.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT); // 此处变量名将会被调整
builder.setLanguage(TextConfiguration.AUTO);
TextConfiguration config = builder.build();
iTextDetector.setVisionConfiguration(config);
// 调用ITextDetector的detect()方法
if (!IS_ASYNC) {
int result2 = iTextDetector.detect(image, text, null); // 同步
sendResult(text.getValue());
} else {
int result2 = iTextDetector.detect(image, null, visionCallback); // 异步
}
}
@Override
public void onServiceDisconnect() {
// 释放 成功:同步结果码为0,异步结果码为700
if ((!IS_ASYNC && (result == 0)) || (IS_ASYNC && (result == IS_ASYNC_CODE))) {
iTextDetector.release();
}
if (pixelMap != null) {
pixelMap.release();
pixelMap = null;
}
VisionManager.destroy();
}
};
}
最后将文字识别结果发送到主线程(MainAbilitySlice类中接收),代码如下:
public void sendResult(String value) {
if (iTextDetector != null) {
iTextDetector.release();
}
if (pixelMap != null) {
pixelMap.release();
pixelMap = null;
VisionManager.destroy();
}
if (value != null) {
maps.put(mediaId, value);
}
if ((maps != null) && (maps.size() == pictureLists.length)) {
InnerEvent event = InnerEvent.get(1, 0, maps);
handle.sendEvent(event);
} else {
wordRecognition(slice, pictureLists[index], handle);
index++;
}
}