news 2026/5/16 4:00:45

06百度OCR手写识别接入-鸿蒙PC端Electron开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
06百度OCR手写识别接入-鸿蒙PC端Electron开发
欢迎加入开源鸿蒙 PC社区

https://harmonypc.csdn.net/

效果截图

第6篇:百度OCR手写识别接入

系列教程导航

篇号标题状态
01环境搭建与项目创建
02数据模型与单词仓库
03主入口页面与导航结构
04极速划词页面实现
05手写画布实现
06百度OCR手写识别接入本篇
07答案比对与反馈UI下一篇
08单词切换与底部导航
09词根分解与水印展示
10项目总结与优化方向

源码仓库:https://atomgit.com/qq_33247427/englishProject

一、为什么选择百度 OCR

1.1 华为端侧 OCR 的问题

HarmonyOS 提供了@kit.CoreVisionKittextRecognitionAPI,理论上可以在设备端完成文字识别,无需网络。但在实际开发中遇到了两个严重问题:

问题错误信息原因
服务未初始化“The service is abnormal”需要先调用init()
识别超时“Run timed out, please try again later”PixelMap 太大,端侧推理超时

即使加了init()和图片缩放,在部分真机上仍然不稳定。

1.2 百度手写 OCR 的优势
对比项华为 CoreVisionKit百度手写 OCR
网络依赖无(端侧)需要网络
稳定性部分设备超时稳定可靠
手写识别质量一般专门针对手写优化
首次使用需下载模型即用
免费额度无限每天 500 次(足够开发测试)
响应速度不稳定通常 1-2 秒
1.3 百度 OCR 申请步骤
  1. 注册 百度智能云账号
  2. 进入控制台 → 文字识别 → 创建应用
  3. 勾选「手写文字识别」能力
  4. 获取API KeySecret Key

二、网络权限配置

百度 OCR 需要网络请求,必须在module.json5中声明权限:

{ "module": { "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] } }

HarmonyOS 的INTERNET权限属于系统授权权限,声明即可使用,不需要动态申请。

三、BaiduOCRService 完整实现

3.1 文件结构

创建electron/src/main/ets/services/BaiduOCRService.ets

import{image}from'@kit.ImageKit';import{util}from'@kit.ArkTS';import{http}from'@kit.NetworkKit';constAPI_KEY='your_api_key_here';constSECRET_KEY='your_secret_key_here';letcachedToken:string='';
3.2 获取 Access Token

百度 API 使用 OAuth 2.0 认证,需要先用 API Key + Secret Key 换取 Access Token:

asyncfunctiongetAccessToken():Promise<string>{// Token 缓存,避免重复请求if(cachedToken){returncachedToken;}consturl=`https://aip.baidubce.com/oauth/2.0/token`+`?grant_type=client_credentials`+`&client_id=${API_KEY}`+`&client_secret=${SECRET_KEY}`;constreq=http.createHttp();try{constresp=awaitreq.request(url,{method:http.RequestMethod.POST});constdata=JSON.parse(resp.resultasstring)asRecord<string,string>;cachedToken=data['access_token'];console.log('BaiduOCR token 获取成功');returncachedToken;}finally{req.destroy();// 必须销毁,否则内存泄漏}}

关键点

  • Token 有效期 30 天,缓存后不需要每次都请求
  • http.createHttp()创建的实例用完必须destroy()
  • 生产环境应该把 Key 放在服务端,不要硬编码在客户端
3.3 PixelMap 转 Base64

百度 OCR 接受 Base64 编码的图片:

asyncfunctionpixelMapToBase64(pixelMap:image.PixelMap):Promise<string>{constpacker=image.createImagePacker();try{// 将 PixelMap 编码为 JPEG(比 PNG 小很多)constbuffer=awaitpacker.packing(pixelMap,{format:'image/jpeg',quality:90// 90% 质量,平衡大小和清晰度});// ArrayBuffer → Uint8Array → Base64 字符串consthelper=newutil.Base64Helper();constuint8=newUint8Array(buffer);constb64=helper.encodeToStringSync(uint8);returnb64;}finally{packer.release();// 释放 packer 资源}}

为什么用 JPEG 而不是 PNG?

  • 手写内容是黑白线条,JPEG 90% 质量足够清晰
  • JPEG 文件通常比 PNG 小 3-5 倍
  • 上传更快,百度 API 有请求体大小限制(4MB)
3.4 英文手写识别
exportasyncfunctionbaiduOCRRecognize(pixelMap:image.PixelMap):Promise<string>{try{constbase64=awaitpixelMapToBase64(pixelMap);consttoken=awaitgetAccessToken();// 百度手写文字识别接口consturl=`https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting?access_token=${token}`;constbody=`image=${encodeURIComponent(base64)}`;constreq=http.createHttp();try{constresp=awaitreq.request(url,{method:http.RequestMethod.POST,header:{'Content-Type':'application/x-www-form-urlencoded'},extraData:body});constresult=JSON.parse(resp.resultasstring)asRecord<string,Object>;constwordsResult=result['words_result']asArray<Record<string,string>>;if(wordsResult&&wordsResult.length>0){// 清洗结果:只保留英文字母和空格consttokens=wordsResult.map((w:Record<string,string>)=>w['words'].replace(/[^a-zA-Z\s]/g,'').trim().toLowerCase()).filter((s:string)=>s.length>0);if(tokens.length===0)return'';// 去重(水印和手写可能被重复识别)constseen=newSet<string>();constunique:string[]=[];for(consttoftokens){if(!seen.has(t)){seen.add(t);unique.push(t);}}returnunique.join(' ').trim();}return'';}finally{req.destroy();}}catch(e){console.error('BaiduOCR 识别失败:',JSON.stringify(e));return'';}}
3.5 中文手写识别
exportasyncfunctionbaiduOCRRecognizeChinese(pixelMap:image.PixelMap):Promise<string>{try{constbase64=awaitpixelMapToBase64(pixelMap);consttoken=awaitgetAccessToken();consturl=`https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting?access_token=${token}`;constbody=`image=${encodeURIComponent(base64)}`;constreq=http.createHttp();try{constresp=awaitreq.request(url,{method:http.RequestMethod.POST,header:{'Content-Type':'application/x-www-form-urlencoded'},extraData:body});constresult=JSON.parse(resp.resultasstring)asRecord<string,Object>;constwordsResult=result['words_result']asArray<Record<string,string>>;if(wordsResult&&wordsResult.length>0){// 只保留中文字符returnwordsResult.map((w:Record<string,string>)=>w['words'].replace(/[^\u4e00-\u9fa5]/g,'').trim()).filter((s:string)=>s.length>0).join('');}return'';}finally{req.destroy();}}catch(e){console.error('BaiduOCR 中文识别失败:',JSON.stringify(e));return'';}}

四、在页面中调用

4.1 导入服务
import{componentSnapshot}from'@kit.ArkUI';import{image}from'@kit.ImageKit';import{baiduOCRRecognize,baiduOCRRecognizeChinese}from'../services/BaiduOCRService';
4.2 doRecognize 方法
asyncdoRecognize(){if(this.isRecognizing||this.currentWord===null){return;}this.isRecognizing=true;this.feedbackText='识别中…';this.feedbackColor='#6B7280';try{// 1. 截取画布组件为 PixelMapconstpixelMap:image.PixelMap=awaitcomponentSnapshot.get('speedDictCanvas');// 2. 调用百度 OCRconsttext=awaitbaiduOCRRecognize(pixelMap);// 3. 比对答案this.recognizedText=text;this.checkAnswer(text);}catch(e){consterr=easRecord<string,string>;this.feedbackText='识别失败:'+(err['message']??'');this.feedbackColor='#B5533C';}this.isRecognizing=false;}
4.3 Loading 状态

识别过程需要 1-2 秒,用@State isRecognizing控制按钮状态:

Button(){Row({space:4}){if(this.isRecognizing){LoadingProgress().width(14).height(14).color('#FFFFFF')}Text(this.isRecognizing?'识别中':'识别').fontSize(13).fontColor('#FFFFFF')}}.enabled(!this.isRecognizing)// 识别中禁用按钮

五、API 响应格式

百度手写 OCR 返回的 JSON 格式:

{"log_id":1234567890,"words_result_num":2,"words_result":[{"words":"apple"},{"words":"Apple"}]}
  • words_result:识别到的文字块数组
  • 每个块的words字段是识别出的文字
  • 手写体可能被分成多个块(多行书写)
  • 水印文字也可能被识别到(需要去重)

六、结果清洗策略

6.1 为什么需要清洗

百度 OCR 会识别画布上所有可见文字,包括:

  • 用户手写的内容(我们需要的)
  • 水印文字(需要过滤或去重)
  • 误识别的噪点
6.2 清洗流程
原始结果 → 去除非字母字符 → 转小写 → 去空格 → 去重 → 拼接

示例:

输入: ["Apple", "apple", "app le"] 处理: ["apple", "apple", "app le"] → 去非字母 → ["apple", "apple", "apple"] 去重: ["apple"] 输出: "apple"

七、错误处理

7.1 常见错误
错误码含义处理方式
110Access Token 无效清除缓存重新获取
216201图片为空提示用户先书写
17每日调用量超限提示明天再试
网络错误无网络提示检查网络
7.2 容错代码
try{consttext=awaitbaiduOCRRecognize(pixelMap);// ...}catch(e){consterr=easRecord<string,string>;this.feedbackText='识别失败:'+(err['message']??'网络异常');this.feedbackColor='#B5533C';}

八、本篇小结

通过本篇教程,我们完成了:

  • 理解了选择百度 OCR 的原因(端侧 OCR 不稳定)
  • 完成了百度 OCR 服务申请和权限配置
  • 实现了 BaiduOCRService(Token 缓存 + PixelMap 转 Base64 + API 调用)
  • 掌握了 componentSnapshot 截图 + OCR 的完整链路
  • 实现了识别结果清洗和去重
  • 处理了 Loading 状态和错误情况

下一篇预告

第 7 篇:答案比对与反馈 UI— 我们将实现识别结果与正确答案的比对逻辑,以及画布上的大字体反馈浮层。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 3:57:18

Ai小程序入门07-事件交互(小白入门:按钮点击怎么响应?让AI帮你写交互逻辑)

Ai小程序入门07-事件交互(小白入门:按钮点击怎么响应?让AI帮你写交互逻辑) 📌 文章简介:如果说上一篇学习的“数据绑定”是让小程序拥有了血液(数据流动),那么本篇要讲的“事件交互”就是让小程序拥有了神经反射!用户在屏幕上点击按钮、滑动列表、输入文字,小程序必…

作者头像 李华
网站建设 2026/5/16 3:55:40

初次接触Taotoken平台从注册到完成第一次API调用的全过程体验

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 初次接触Taotoken平台从注册到完成第一次API调用的全过程体验 作为一名开发者&#xff0c;当需要接入多个大模型时&#xff0c;统一…

作者头像 李华
网站建设 2026/5/16 3:54:30

UAV-RIS混合网络中的SCA-AO联合优化框架

1. 项目概述 在无线通信领域&#xff0c;非线性优化问题常通过凸近似技术&#xff08;如SCA&#xff09;和交替优化&#xff08;AO&#xff09;方法解决。这些技术通过将复杂问题分解为一系列凸子问题&#xff0c;逐步逼近全局最优解&#xff0c;特别适用于多变量耦合的工程场景…

作者头像 李华
网站建设 2026/5/16 3:50:04

CRUD 入门:数据的增、查、改、删

在前一篇中&#xff0c;我们成功创建了数据库和表&#xff0c;并初步了解了数据类型。接下来&#xff0c;我们将进入数据库操作中最核心、最常用的部分——CRUD。CRUD 是四个基本操作的缩写&#xff1a;Create&#xff08;增加&#xff09;、Read&#xff08;查询&#xff09;、…

作者头像 李华
网站建设 2026/5/16 3:47:04

华硕游侠2-RX键盘多功能滚轮自定义M失效的解决方案

新买了一块游侠2 rx键盘&#xff0c;想着用自定义滚轮方便打开常用程序&#xff0c;但是发现在Armoury Crate中设置后不起作用&#xff0c;网上解决方案伤筋动骨&#xff0c;得不偿失&#xff0c;有一定风险。 经测试&#xff0c;自定义滚轮能正常执行宏定义&#xff0c;只是对…

作者头像 李华