当前位置: 首页 > 科技观察

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

时间:2023-03-13 06:29:09 科技观察

了解更多开源内容请访问:开源基础软件社区https://ost.51cto.com1.Tesseract简介(Apache2.0License)是一个C++图像OCR识别库,可以跨平台运行。本示例基于Tesseract库进行适配,使其可以运行在OpenAtomOpenHarmony(以下简称“OpenHarmony”)上,并新增了N-API接口供上层应用调用,使得上层应用可以使用Tesseract提供的相关函数。2.效果展示动物图片识别文字身份信息识别:提取文字信息到本地文件:相关代码已经上传到SIG仓库,链接如下:https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/OCR演示。3.目录结构4.调用过程调用过程主要涉及三个方面。一、应用层实现示例效果,包括页面布局和业务逻辑代码;中间层主要起到桥梁作用,为应用调用提供N-API接口,再通过第三方库的接口调用具体实现;Native层使用第三方库Tesseract提供具体实现功能。五、源码分析本示例的源码分析主要涉及两个方面,一是N-API接口的实现,二是应用层的页面布局和业务逻辑。N-API实现1.首先在index.d.ts文件中定义接口/***初始化文本识别引擎*@paramlang识别的语言,eg:eng,chi_sim,eng+chi_sim,是否为Nullpassed对于中英文(eng+chi_sim)*@paramtrainDir训练模型目录,如果为Null或不passed则为默认目录**@return是否初始化成功0=>success,-1=>failure*/exportconstinitOCR:(lang:string,trainDir:string)=>Promise;exportconstinitOCR:(lang:string,trainDir:string,callback:AsyncCallback)=>void;/***复制代码开始识别*@paramimagePath图片路径(目前支持的图片格式有png、jpg、tiff)**@return识别结果*/exportconststartOCR:(imagePath:string)=>Promise;exportconststartOCR:(imagePath:string,callback:AsyncCallback)=>void;/***销毁资源*/exportconstdestroyOCR:()=>void;从代码中可以看出,N-API接口initOCR和startOCR都采用了两种方式,一种是Promise,一种是Callback的方式。在示例的应用层,使用了他们的Callback方法。2.注册N-API模块和接口EXTERN_C_STARTstaticnapi_valueInit(napi_envenv,napi_valueexports){napi_property_descriptordesc[]={{"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);返回出口;}EXTERN_C_ENDstaticnapi_moduledemoModule={.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))voidRegisterHelloModule(void){napi_module_register(&demoModule);}通过nm_modname定义模块名,注册与nm_register_func接口函数,Init函数中,initOCR、startOCR、destroyOCR对应的局部实现函数inJS都指定了,这样就可以在相应的本地实现函数中调用三方库Tesseract的具体实现。3、以startOCR的Callback方法为例,介绍在N-API中的具体实现staticnapi_valueStartOCR(napi_envenv,napi_callback_infoinfo){OH_LOG_ERROR(LogType::LOG_APP,"OCRStartOCR111");size_targc=2;napi_valueargs[2]={nullptr};//1.获取参数napi_get_cb_info(env,info,&argc,args,nullptr,nullptr);//2。共享数据autoaddonData=newStartOCRAddOnData{.asyncWork=nullptr,};//3.N-API类型转换为C/C++类型charimagePath[1024]={0};size_t长度=0;napi_get_value_string_utf8(env,args[0],imagePath,1024,&length);addonData->args0=string(图像路径);napi_create_reference(env,args[1],1,&addonData->callback);//4。创建异步工作napi_valueresourceName=nullptr;napi_create_string_utf8(env,"startOCR",NAPI_AUTO_LENGTH,&resourceName);napi_create_async_work(env,nullptr,resourceName,executeStartOCR,completeStartOCRForCallback,(void*)addonData,&addonData->asyncWork);//异步创建work加入队列,底层调度执行napi_queue_async_work(env,addonData->asyncWork);napi_value结果=0;napi_get_null(环境,结果);returnresult;}首先通过napi_get_cb_info方法获取JS端传入的参数信息,并将该参数转换成C++对应的类型,然后创建异步工作。异步工作的方法参数包括执行的函数和函数执行完成的回调函数我们看一下执行函数:staticvoidexecuteStartOCR(napi_envenv,void*data){//通过data获取数据StartOCRAddOnData*addonData=(StartOCRAddOnData*)data;napi_value结果值;try{if(api!=nullptr){//调用具体实现读取图片像素PIX*pix=pixRead((constchar*)addonData->args0.c_str());//设置api的图片像素api->SetImage(pix);//调用文字提取接口获取图片中的文字char*result=api->GetUTF8Text();addonData->result=结果;//释放资源pixDestroy(&pix);删除[]结果;}}catch(std::exceptione){std::stringerror="Error:";if(initResult!=0){error+=“请先初始化tesseractocr。”;}else{错误+=e.what();}addonData->result=error;}}该方法中通过data获取JS传入的参数,然后调用Tesseract库中提供的接口调用具体的文字提取函数获取图片中的文字。执行完成后会回调completeStartOCRForCallback。在这个方法中,执行函数中返回的结果会被转换成对应的JS类型,然后通过Callback返回。staticvoidcompleteStartOCRForCallback(napi_envenv,napi_statusstatus,void*data){StartOCRAddOnData*addonData=(StartOCRAddOnData*)data;napi_value回调=nullptr;napi_get_reference_value(env,addonData->callback,&callback);napi_valueundefinedundefined=nullptr(,&undefined);napi_value结果=nullptr;napi_create_string_utf8(env,addonData->result.c_str(),addonData->result.length(),&result);//执行回调函数napi_valuereturnVal=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);deleteaddonData;}应用层实现应用层主要分为三个模块:动物图片文字识别、身份信息识别、提取文字到本地文件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({左:this.columnSpace,右:this.columnSpace}).columnsTemplate("1fr1fr1fr")//网格宽度分为3部分。rowsTemplate("1fr1fr")//网格高度分为两部分。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开始对话框打开111');this.ocrDialog.open();ToolUtils.ocrResult(ToolUtils.aobamao,(result)=>{console.log('111OCRresult='+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('111OCRresult='+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(Horizo??ntalAlign.Center).height('90%')}.justifyContent(FlexAlign.Start).width('50%')}.width('100%').height('100%')}身份信息识别布局的最外层是一个levelLayout,分为左右两部分,左边的子布局是竖排的,包含两张不同的身份证图片,右边的子布局也是竖排的,主要是标题区和内容展示区识别结果3.提取文本到本地文件Row(){Column(){Image('/common/save2FileImages/testImage1.png').onClick(()=>{//点击图片进行信息识别ToolUtils.ocrResult(ToolUtils.testImage1,(result)=>{letpath=this.dir+'ocrresult1.txt';try{letfd=fileio.openSync(path,0o100|0o2,0o666);fileio.writeSync(fd,result);fileio.closeSync(fd);this.displayText='filewrite'+path;}catch(e){console.log('OCRfileioerror='+e);}});})Image('/common/save2FileImages/testImage2.png').onClick(()=>{//点击图片进行信息识别ToolUtils.ocrResult(ToolUtils.testImage2,(result)=>{letpath=this.dir+'ocrresult2.txt';让fd=fileio.openSync(path,0o100|0o2,0o666);fileio.writeSync(fd,result);fileio.closeSync(fd);this.displayText='文件写入'+路径;});})}Column(){Text(this.title)Column(){Text(this.displayText)}}}这个函数首先通过接口识别图片中的文字,然后通过接口将文字写入文件fileio的能力。六、总结实例通过Native方法将C++三方库集成到应用程序中,通过N-API方法应用程序调用向上层提供接口。对于依赖第三方库能力的应用,可以通过该方式将第三方库移植到Native中,通过N-API提供应用调用的接口。了解更多开源知识,请访问:开源基础软件社区https://ost.51cto.com。