OpenHarmony集成OCR三方库实现文字提取

1. 简介

Tesseract(Apache 2.0 License)是一个可以进行图像OCR识别的C++库,可以跨平台运行 。本样例基于Tesseract库进行适配,使其可以运行在OpenAtom OpenHarmony(以下简称“OpenHarmony”)上,并新增N-API接口供上层应用调用,这样上层应用就可以使用Tesseract提供的相关功能。

2. 效果展示

动物图片识别文字

身份信息识别

提取文字信息到本地文件

3. 目录结构

4. 调用流程

调用过程主要涉及到三方面,首先应用层实现样例的效果,包括页面的布局和业务逻辑代码;中间层主要起桥梁的作用,提供N-API接口给应用调用,再通过三方库的接口去调用具体的实现;Native层使用了三方库Tesseract提供具体的实现功能。

5. 源码分析

本样例源码的分析主要涉及到两个方面,一方面是N-API接口的实现,另一方面是应用层的页面布局和业务逻辑。

N-API实现

1. 首先在index.d.ts文件中定义好接口

/*** 初始化文字识别引擎* @param lang 识别的语言, eg:eng、chi_sim、 eng+chi_sim,为Null或不传则为中英文(eng+chi_sim)* @param trainDir 训练模型目录,为Null或不传则为默认目录** @return 初始化是否成功 0=>成功,-1=>失败*/
export const initOCR: (lang: string, trainDir: string) => Promise<number>;export const initOCR: (lang: string, trainDir: string, callback: AsyncCallback<number>) => void;/*** 开始识别* @param imagePath 图片路径(当前支持的图片格式为png, jpg, tiff)** @return 识别结果*/
export const startOCR: (imagePath: string) => Promise<string>;
export const startOCR: (imagePath: string, callback: AsyncCallback<string>) => void;/*** 销毁资源*/
export const destroyOCR: () => void;

代码中可以看出N-API接口initOCR和startOCR都采用了两种方式,一种是Promise,一种是Callback的方式。在样例的应用层,使用的是它们的Callback方式。

2.注册N-API模块和接口

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc[] = {
{
"initOCR", nullptr, InitOCR, nullptr, nullptr, nullptr, napi_default, nullptr
},
{
"startOCR", nullptr, StartOCR, nullptr, nullptr, nullptr, napi_default, nullptr
},
{
"destroyOCR", nullptr, DestroyOCR, nullptr, nullptr, nullptr, napi_default, nullptr
},
{
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "tesseract",
.nm_priv = ((void *)0),
.reserved = {
0
},
};extern "C" __attribute__((constructor)) void RegisterHelloModule(void) {
napi_module_register(& demoModule);
}

通过nm_modname定义模块名,nm_register_func注册接口函数,在Init函数中指定了JS中initOCR,startOCR,destroyOCR对应的本地实现函数,这样就可以在对应的本地实现函数中调用三方库Tesseract的具体实现了。

3.以startOCR的Callback方式为例介绍N-API中的具体实现

static napi_value StartOCR(napi_env env, napi_callback_info info) {OH_LOG_ERROR(LogType::LOG_APP, "OCR StartOCR 111");size_t argc = 2;napi_value args[2] = { nullptr };//1. 获取参数napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);//2. 共享数据auto addonData = new StartOCRAddOnData{.asyncWork = nullptr,};//3. N-API类型转成C/C++类型char imagePath[1024] = { 0 };size_t length = 0;napi_get_value_string_utf8(env, args[0], imagePath, 1024, &length);addonData->args0 = string(imagePath);napi_create_reference(env, args[1], 1, &addonData->callback);//4. 创建async worknapi_value resourceName = nullptr;napi_create_string_utf8(env, "startOCR", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, executeStartOCR, completeStartOCRForCallback, (void *)addonData, &addonData->asyncWork);//将创建的async work加到队列中,由底层调度执行napi_queue_async_work(env, addonData->asyncWork);napi_value result = 0;napi_get_null(env, &result);return result;
}

首先通过napi_get_cb_info方法获取JS侧传入的参数信息,将参数转成C++对应的类型,然后创建异步工作,异步工作的方法参数中包含,执行的函数以及函数执行完成的回调函数。

我们看一下执行函数

static void executeStartOCR(napi_env env, void* data) {//通过data来获取数据StartOCRAddOnData * addonData = (StartOCRAddOnData *)data;napi_value resultValue;try {if (api != nullptr) {//调用具体的实现,读取图片像素PIX * pix = pixRead((const char*)addonData->args0.c_str());//设置api的图片像素api->SetImage(pix);//调用文字提取接口,获取图片中的文字char * result = api->GetUTF8Text();addonData->result = result;//释放资源pixDestroy (& pix);delete[] result;}} catch (std::exception e) {std::string error = "Error: ";if (initResult != 0) {error += "please first init tesseractocr.";} else {error += e.what();}addonData->result = error;}
}

这个方法中通过data获取JS传入的参数,然后调用Tesseract库中提供的接口,调用具体的文字提取功能,获取图片中的文字。

执行完成后,会回调到completeStartOCRForCallback,在这个方法中会将执行函数中返回的结果转换为JS的对应类型,然后通过Callback的方式返回。

static void completeStartOCRForCallback(napi_env env, napi_status status, void * data) {StartOCRAddOnData * addonData = (StartOCRAddOnData *)data;napi_value callback = nullptr;napi_get_reference_value(env, addonData->callback, &callback);napi_value undefined = nullptr;napi_get_undefined(env, &undefined);napi_value result = nullptr;napi_create_string_utf8(env, addonData->result.c_str(), addonData->result.length(), &result);//执行回调函数napi_value returnVal = nullptr;napi_call_function(env, undefined, callback, 1, &result, &returnVal);//删除napi_ref对象if (addonData->callback != nullptr) {napi_delete_reference(env, addonData->callback);}//删除异步工作项napi_delete_async_work(env, addonData->asyncWork);delete addonData;
}

应用层实现

应用层主要分为三个模块:动物图片文字识别,身份信息识别,提取文字到本地文件

1. 动物图片文字识别

build() {Column() {Row() {Text('点击图片进行文字提取  提取结果 :').fontSize('30fp').fontColor(Color.Blue)Text(this.ocrResult).fontSize('50fp').fontColor(Color.Red)}.margin('10vp').height('10%').alignItems(VerticalAlign.Center)Grid() {ForEach(this.images, (item, index) => {GridItem() {AnimalItem({path1: item[0],path2: item[1]});}})}.padding({left: this.columnSpace, right: this.columnSpace}).columnsTemplate("1fr 1fr 1fr")      // Grid宽度均分成3份.rowsTemplate("1fr 1fr")     // Grid高度均分成2份.rowsGap(this.rowSpace)                  // 设置行间距.columnsGap(this.columnSpace)            // 设置列间距.width('100%').height('90%')}.backgroundColor(Color.Pink)}

布局主要使用了Grid的网格布局,每个Item都是对应的图片,通过点击图片可以对点击图片进行文字提取,将提取出的文字显示在标题栏。

2. 身份信息识别

build() {Row() {Column() {Image('/common/idImages/aobamao.jpg').onClick(() => {//点击图片进行信息识别console.log('OCR begin dialog open 111');this.ocrDialog.open();ToolUtils.ocrResult(ToolUtils.aobamao, (result) => {console.log('111 OCR result = ' + result);this.result = result;this.ocrDialog.close();});}).margin('10vp').objectFit(ImageFit.Auto).height('50%')Image('/common/idImages/weixiaobao.jpg').onClick(() => {//点击图片进行信息识别this.ocrDialog.open();ToolUtils.ocrResult(ToolUtils.weixiaobao, (result) => {console.log('111 OCR result = ' + result);this.result = result;this.ocrDialog.close();});}).margin('10vp').objectFit(ImageFit.Auto).height('50%')}.width(this.screenWidth/2).padding('20vp')Column() {Text(this.title).height('10%').fontSize('30fp').fontColor(this.titleColor)Column() {Text(this.result).fontColor('#0000FF').fontSize('50fp')}.justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).height('90%')}.justifyContent(FlexAlign.Start).width('50%')}.width('100%').height('100%')}

身份信息识别的布局最外层是一个水平布局,分为左右两部分,左边的子布局是垂直布局,里面是两张不同的身份证图片,右边子布局也是垂直布局,主要是标题区和识别结果的内容显示区。

3. 提取文字到本地文件

Row() {Column() {Image('/common/save2FileImages/testImage1.png').onClick(() => {//点击图片进行信息识别ToolUtils.ocrResult(ToolUtils.testImage1, (result) => {let path = this.dir + 'ocrresult1.txt';try {let fd = fileio.openSync(path, 0o100 | 0o2, 0o666);fileio.writeSync(fd, result);fileio.closeSync(fd);this.displayText = '文件写入' + path;} catch (e) {console.log('OCR fileio error = ' + e);}});})Image('/common/save2FileImages/testImage2.png').onClick(() => {//点击图片进行信息识别ToolUtils.ocrResult(ToolUtils.testImage2, (result) => {let path = this.dir + 'ocrresult2.txt';let fd = fileio.openSync(path, 0o100 | 0o2, 0o666);fileio.writeSync(fd, result);fileio.closeSync(fd);this.displayText = '文件写入' + path;});})}Column() {Text(this.title)Column() {Text(this.displayText)}}}

这个功能首先通过接口识别出图片中的文字,然后再通过fileio的能力将文字写入文件中。

6. 总结

样例通过Native的方式将C++的三方库集成到应用中,通过N-API方式提供接口给上层应用调用。对于依赖三方库能力的应用,都可以使用这种方式来进行,移植三方库到Native,通过N-API提供接口给应用调用。

为了帮助到大家能够更有效的学习OpenHarmony 开发的内容,下面特别准备了一些相关的参考学习资料:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14369.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu服务器运行Subspace节点和Farm

提供Subspace 节点部署&性能优化&机房托管&运维监控等服务。myto88 磁盘格式化 将插入的磁盘格式化。 sudo mkfs.ext4 -m 0 -T largefile4 /dev/sd*磁盘挂载 此处为语雀内容卡片&#xff0c;点击链接查看&#xff1a;https://www.yuque.com/u25096009/lvoxa…

企商在线荣登甲子光年“2024中国AI算力层创新企业”榜单

5月15日&#xff0c;「AI创生时代——2024甲子引力X科技产业新风向」大会在北京顺利举办&#xff0c;大会发布2024【星辰100】创新企业榜。企商在线凭借全栈式一体化AI算力能力&#xff0c;与超聚变、寒武纪等企业共同入选“2024中国AI算力层创新企业”榜单。 本次大会由中国科…

AJAX(JQuery版本)

目录 前言 一.load方法 1.1load()简介 1.2load()方法示例 1.3load()方法回调函数的参数 二.$.get()方法 2.1$.get()方法介绍 2.2详细说明 2.3一些例子 2.3.1请求test.php网页并传送两个参数 2.3.2显示test返回值 三.$.post()方法 3.1$.post()方法介绍 3.2详细说明 …

什么是云计算安全?如何保障云计算安全

云计算彻底改变了数据存储的世界&#xff0c;它使企业可以远程存储数据并随时随地从任何位置访问数据。存和取变得简单&#xff0c;也使得云上数据极易造成泄露或者被篡改&#xff0c;所以云计算安全就显得非常重要了。那么什么是云计算安全&#xff1f; 其实&#xff0c;云计…

WPS PPT学习笔记 1 排版4原则等基本技巧整理

排版原则 PPT的排版需要满足4原则&#xff1a;密性、对齐、重复和对比4个基本原则。 亲密性 彼此相关的元素应该靠近&#xff0c;成为一个视觉单位&#xff0c;减少混乱&#xff0c;形成清晰的结构。 两端对齐&#xff0c;1.5倍行距 在本例中&#xff0c;19年放左边&#x…

是谁的项目还在烂大街?一个基于 SpringBoot 的高性能短链系统

看了几百份简历&#xff0c;真的超过 90% 的小伙伴的项目是商城、RPC、秒杀、论坛、外卖、点评等等烂大街的项目&#xff0c;人人都知道这些项目烂大街了&#xff0c;但大部分同学还是得硬着头皮做&#xff0c;没办法&#xff0c;网络上能找到的、教程比较完善的就这些项目了&a…

基于机器学习预测未来的二氧化碳排放量(随机森林和XGBoost)

基于机器学习预测未来的二氧化碳排放量&#xff08;随机森林和XGBoost&#xff09; 简介&#xff1a; CO2排放是当今全球关注的环境问题之一。本文将使用Python对OWID提供的CO2排放数据集进行分析&#xff0c;并尝试构建机器学习模型来预测未来的CO2排放趋势。我们将探索数据…

kafka Kerberos集群环境部署验证

背景 公司需要对kafka环境进行安全验证,目前考虑到的方案有Kerberos和SSL和SASL_SSL,最终考虑到安全和功能的丰富度,我们最终选择了SASL_SSL方案。处于知识积累的角度,记录一下kafka keberos安装部署的步骤。 机器规划 目前测试环境公搭建了三台kafka主机服务,现在将详细…

ViLT学习

多模态里程碑式的文章&#xff0c;总结了四种多模态方法&#xff0c;根据文字和图像特征特征抽取方式不通。 文章的贡献主要是速度提高了&#xff0c;使用了数据增强&#xff0c;文本的mask 学习自b站朱老师的论文讲解

电赛控制类PID算法实现

一、什么是PID PID&#xff08;Proportional-Integral-Derivative&#xff09;是一种经典的控制算法&#xff0c;广泛应用在自动化控制系统中。它是通过对被控对象的测量值和设定值进行比较&#xff0c;并根据误差的大小来调整输出信号&#xff0c;实现对被控对象的稳定控制。 …

【C++】map和set的封装

目录 前言一、红黑树的设计1.1 红黑树存储节点的设计1.2 红黑树的迭代器1.3 map的设计1.4 set的设计1.5关于map与set的const_iterator设计 前言 我们知道map和set的底层都是用红黑树实现的&#xff0c;但是set和map的结构不一样&#xff0c;set只有一个参数K&#xff0c;而map…

前端基础:1-2 面向对象 + Promise

面向对象 对象是什么&#xff1f;为什么要面向对象&#xff1f; 通过代码抽象&#xff0c;进而藐视某个种类物体的方式 特点&#xff1a;逻辑上迁移更加灵活、代码复用性更高、高度的模块化 对象的理解 对象是对于单个物体的简单抽象对象是容器&#xff0c;封装了属性 &am…

Linux_应用篇(07) 系统信息与系统资源

在应用程序当中&#xff0c;有时往往需要去获取到一些系统相关的信息&#xff0c;譬如时间、日期、以及其它一些系统相关信息&#xff0c;本章将向大家介绍如何通过 Linux 系统调用或 C 库函数获取系统信息&#xff0c; 譬如获取系统时间、日期以及设置系统时间、日期等&#x…

三能一体运营体系助力政企支撑水平提升

生产力的发展是现代社会孜孜不倦的追求&#xff0c;由此产生了我们熟悉的“机械化、电子化、信息化”乃至现今正在发生的“智能化”四次工业革命。这些是由技术的突破性发展带来的&#xff0c;但我们也注意到生产力发展的另一个助力&#xff0c;即生产效率的提升&#xff0c;19…

【MySQL数据库】mysql日志管理、备份与恢复

mysql日志管理、备份与恢复 MySQL数据库备份及日志一、数据库备份分类&#xff1a;如何选择逻辑备份策略 (频率)完全备份与恢复备份恢复 增量备份与恢复实现增量备份 基于时间点与位置恢复 二.MySQL日志管理 MySQL数据库备份及日志 在生产环境中&#xff0c;数据的安全性是至关…

在未来你将何去何从?

在数字化的浪潮中&#xff0c;信息技术行业无疑是推动全球经济和社会发展的重要动力。随着科技的不断迭代与进步&#xff0c;云计算、大数据、人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;、5G通信和区块链等技术已经深入到我们生活的每一个角落&am…

鸿蒙原生应用元服务开发-鸿蒙真机运行项目实战与注意事项

一、解压项目注意项目包不能为中文 二、用数据线将装好DevEco Studio的电脑与设置为开发者模式的鸿蒙手机相连接。 三、将项目包托进DevEco Studio 中 注意项目包文件不能有嵌套 四、查看设备运行 五、点击项目结构 六、勾选红色框圈部分 登录开发者账号 七、选择好公司 八、等…

我是如何使用 Next.js14 + Tailwindcss 重构个人项目的

前言 去年在学习 React 和 Nest 的时候&#xff0c;参考了大佬 imsyy 的项目 DailyHot&#xff0c;以此项目的灵感基于 React 开发&#xff0c;完成之后就没怎么在意。 后来发现这个项目还有点小流量&#xff0c;每天差不多 200-400 的 IP 访问量&#xff1a; 我又抽时间优…

深度学习之基于Pytorch框架手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 手写数字识别是数字图像处理领域的一个经典问题&#xff0c;也是深度学习技术的一个常用应用场…