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.pswp.cn/bicheng/14369.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/14369.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/14369.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

.Net Core學習筆記 框架特性(注入、配置)

注&#xff1a;直接學習的.Net Core 6&#xff0c;此版本有沒有startup.cs相關的內容 項目Program.cs文件中 是定義項目加載 啟動的地方 //通過builder對項目進行配置、服務的加載 var builder WebApplication.CreateBuilder(args); builder.Services.AddControllers();//將…

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…

如何安裝 Docker

引言 - 介紹 Docker 技術的重要性和應用場景 - 簡要解釋 Docker 的工作原理和優勢 Docker 的安裝 Docker 在不同平臺上的安裝方法&#xff08;Windows、Mac、Linux&#xff09; Docker 是一個開源的容器化平臺&#xff0c;可以幫助開發人員和運維團隊更輕松地打包、交付和運行…

python 裝飾器 帶參數和不帶參數

裝飾器是Python語言中一種特殊的語法&#xff0c;用于在不修改原函數代碼的情況下&#xff0c;為函數添加額外的功能或修改函數的行為。通過裝飾器&#xff0c;我們可以在函數執行前后執行一些額外的代碼&#xff0c;或者修改函數的參數。 要使用裝飾器引入函數和參數&#xf…

Linux_應用篇(07) 系統信息與系統資源

在應用程序當中&#xff0c;有時往往需要去獲取到一些系統相關的信息&#xff0c;譬如時間、日期、以及其它一些系統相關信息&#xff0c;本章將向大家介紹如何通過 Linux 系統調用或 C 庫函數獲取系統信息&#xff0c; 譬如獲取系統時間、日期以及設置系統時間、日期等&#x…

restTemplate返回報文亂碼問題

默認服務端使用UTF8編碼 排查1&#xff1a; 請求前手動設置UTF-8編碼解析報文 RestTemplate restTemplate new RestTemplate(); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); ResponseEntity<String> excha…

三能一體運營體系助力政企支撐水平提升

生產力的發展是現代社會孜孜不倦的追求&#xff0c;由此產生了我們熟悉的“機械化、電子化、信息化”乃至現今正在發生的“智能化”四次工業革命。這些是由技術的突破性發展帶來的&#xff0c;但我們也注意到生產力發展的另一個助力&#xff0c;即生產效率的提升&#xff0c;19…

【MySQL數據庫】mysql日志管理、備份與恢復

mysql日志管理、備份與恢復 MySQL數據庫備份及日志一、數據庫備份分類&#xff1a;如何選擇邏輯備份策略 (頻率)完全備份與恢復備份恢復 增量備份與恢復實現增量備份 基于時間點與位置恢復 二.MySQL日志管理 MySQL數據庫備份及日志 在生產環境中&#xff0c;數據的安全性是至關…