云计算百科
云计算领域专业知识百科平台

鸿蒙端侧OCR实战:Core Vision Kit离线文字识别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

鸿蒙端侧OCR实战:Core Vision Kit离线文字识别

需求与选型

移动端要做文字识别(OCR),第一反应往往是接云端 API。但在实际项目里,端侧方案越来越值得优先考虑,尤其这三个场景:图片涉及证件、票据等敏感信息,不能出设备;弱网或离线环境(巡检、仓储)必须可用;调用量大、按次计费的云 API 成本压不住。

两条路线对比:

维度云端 OCR API端侧(Core Vision Kit)
网络依赖 必须 无,离线可用
隐私 图片上传到服务端 数据不出设备
成本 按次计费 免费
延迟 网络往返,几百 ms 起 端侧推理,通常百 ms 级
模型能力 强,场景丰富 印刷体为主,手写/艺术字是边界

鸿蒙侧的端选方案是 Core Vision Kit 的 textRecognition:模型跑在设备上,支持简体中文、繁体中文、英文、日文、韩文的印刷体识别,无需申请任何权限(OCR 本身不涉及敏感权限),Stage 模型下即可直接调用。本文用"选图 → 识别 → 取词"这个小工具,把完整链路走一遍。

调用范式:三步拿到识别结果

import { textRecognition } from '@kit.CoreVisionKit';
import { image } from '@kit.ImageKit';

let visionInfo: textRecognition.VisionInfo = { pixelMap: pixelMap };
let result: textRecognition.TextRecognitionResult =
await textRecognition.recognizeText(visionInfo);

范式极简:构造 VisionInfo(包一个 PixelMap)→ 调 recognizeText → 解析结果。但有几个约束要先交代清楚,都是实际会踩的点:

  • 输入只认 PixelMap,格式必须 RGBA_8888。相册、相机、资源文件解出的 PixelMap 默认就是这个格式,一般不用手动转;从网络拿 JPEG/PNG 解码后同样成立。
  • 图片建议不超过 4096×4096。超大图先缩放,速度和精度都更稳。
  • 可以传第二个参数 TextRecognitionConfiguration,目前只有一个开关 isDirectionDetectionSupported(默认 true)。如果图片方向已知,关掉它能省一次方向检测,提速明显:

let config: textRecognition.TextRecognitionConfiguration = {
isDirectionDetectionSupported: false // 方向已知时跳过检测
};
let result = await textRecognition.recognizeText(visionInfo, config);

结果解析:块/行/字三级树 + 坐标

TextRecognitionResult 是一棵从粗到细的三级树:blocks(文本块)→ lines(文本行)→ words(单词)。每层都同时给文本内容和 cornerPoints 边界框坐标(顺时针四点,第一个点是左上角)。

// 只要全文:拼接块的文本即可
const fullText = result.blocks.map(b => b.value).join('\\n');

// 要行级/字级信息(取词、框选、高亮)时下钻
for (const block of result.blocks) {
for (const line of block.lines) {
console.info(`行文本: ${line.value}`); // 行内容
console.info(`行坐标: ${JSON.stringify(line.cornerPoints)}`);
for (const word of line.words) {
// word.value / word.cornerPoints:单词级内容和坐标
}
}
}

cornerPoints 是整套 API 里最值钱的部分——它意味着不仅能拿到"图里写了什么",还能拿到"写在哪里"。点击取词、划选翻译、区域高亮、票据字段定位,全都建立在坐标之上。

完整实现:选图取词工具

下面是一个可以直接跑的页面:相册选图 → 转 PixelMap → 识别 → 展示全文,错误路径全部兜住。

import { textRecognition } from '@kit.CoreVisionKit';
import { image } from '@kit.ImageKit';
import { fileIo } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct OcrPage {
@State resultText: string = '';
@State loading: boolean = false;

async pickAndRecognize(): Promise<void> {
const picker = new photoAccessHelper.PhotoViewPicker();
const res = await picker.select({
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
maxSelectNumber: 1
});
const uri = res.photoUris[0];
if (!uri) return;

this.loading = true;
try {
// 1. URI → PixelMap
const file = await fileIo.open(uri, fileIo.OpenMode.READ_ONLY);
const source = image.createImageSource(file.fd);
const pixelMap = await source.createPixelMap();

// 2. 端侧识别
const visionInfo: textRecognition.VisionInfo = { pixelMap };
const result = await textRecognition.recognizeText(visionInfo);

// 3. 解析结果
this.resultText = result.blocks.map(b => b.value).join('\\n');
if (!this.resultText) {
this.resultText = '未识别到文字,请换一张更清晰的图片';
}

pixelMap.release();
source.release();
} catch (err) {
const e = err as BusinessError;
this.resultText = `识别失败(code=${e.code}),请重试`;
} finally {
this.loading = false;
}
}

build() {
Column({ space: 16 }) {
Button('选择图片并识别')
.onClick(() => this.pickAndRecognize())

if (this.loading) {
LoadingProgress().width(40).height(40)
} else {
Scroll() {
Text(this.resultText)
.fontSize(16)
.copyOption(CopyOptions.InApp) // 识别结果可直接长按复制
}
.layoutWeight(1)
.padding(16)
}
}
.width('100%')
.height('100%')
.padding(16)
}
}

两个工程细节:loading 态让识别期间 UI 有明确反馈(端侧推理虽快,大图也要几百 ms);pixelMap 和 ImageSource 用完即 release(),列表页反复识别的场景漏释放会持续涨内存。

踩坑与调优

错误码要逐个兜。recognizeText 的 Promise 里会抛业务错误,实际遇到最多的是这几个:

  • 200 识别超时——大图或后台负载时偶发,提示重试即可;
  • 401 参数校验失败——九成是 PixelMap 无效或已 release;
  • 1001400001 运行失败——可重试一次;
  • 1001400002 服务异常——引导重启应用。

识别效果差的排查顺序。端侧模型对"清晰、正对、背景简单"的印刷体效果最好,效果差时按这个顺序查:

  • 图片是否过小或过模糊(先看分辨率,低于几十像素高的文本行基本没戏);
  • 文字是否倾斜严重——方向检测只管 90°/180° 级别的旋转,不管小角度纠偏;
  • 背景是否杂乱、文字是否被遮挡。
  • 手写体和艺术字是能力边界,需要这类识别时再考虑云端方案,端侧别硬扛。

    小结

    Core Vision Kit 的 textRecognition 用极低的集成成本换来了免费、离线、隐私安全的端侧 OCR:一次 Promise 调用,拿到带坐标的三级文本树。它适合印刷体识别的主流场景(票据、名片、截图取词、无网录入),调用范式也是 Core Vision Kit 全家族端侧 AI 能力(人脸检测、卡证识别等)的通用模板,学会这一个,其余能力照葫芦画瓢即可。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 鸿蒙端侧OCR实战:Core Vision Kit离线文字识别
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!