记录---纯前端也能实现 OCR?

news/2025/3/3 16:56:06/文章来源:https://www.cnblogs.com/smileZAZ/p/18748697

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

前言

前端时间有一个 OCR 的需求,原本考虑调用现成的 OCR 接口,但由于只是做一个我个人使用的工具,花钱购买 OCR 接口显得有些奢侈。于是就想着找找是否有现成的库可以自己部署或直接使用,结果发现了一个可以在纯前端实现 OCR 的库——Tesseract.js

Tesseract.js

Tesseract.js 是一个基于 Google Tesseract OCR 引擎的 JavaScript 库,利用 WebAssembly 技术将的 OCR 引擎带到了浏览器中。它完全运行在客户端,无需依赖服务器,适合处理中小型图片的文字识别。

主要特点

  • 多语言支持:支持多种语言文字识别,包括中文、英文、日文等。
  • 跨平台:支持浏览器和 Node.js 环境,灵活应用于不同场景。
  • 开箱即用:无需额外依赖后端服务,直接在前端实现 OCR 功能。
  • 自定义训练数据:支持加载自定义训练数据,提升特定场景下的识别准确率。

安装

通过 npm 安装

npm install tesseract.js

通过 CDN 引入

<script src="https://unpkg.com/tesseract.js@latest/dist/tesseract.min.js"></script>

基本使用

以下示例展示了如何使用 Tesseract.js 从图片中提取文字:

import Tesseract from 'tesseract.js';Tesseract.recognize('image.png', // 图片路径'chi_sim',   // 识别语言(简体中文){logger: info => console.log(info), // 实时输出进度日志}
).then(({ data: { text } }) => {console.log('识别结果:', text);
});

示例图片

 

运行结果

可以看到,虽然识别结果不完全准确,但整体准确率较高,能够满足大部分需求。

更多用法

1. 多语言识别

Tesseract.js 支持多语言识别,可以通过字符串或数组指定语言代码:

// 通过字符串的方式指定多语言
Tesseract.recognize('image.png', 'eng+chi_sim').then(({ data: { text } }) => {console.log('识别结果:', text);
});// 通过数组的方式指定多语言
Tesseract.recognize('image.png', ['eng','chi_sim']).then(({ data: { text } }) => {console.log('识别结果:', text);
});
eng+chi_sim 表示同时识别英文和简体中文。Tesseract.js 内部会将字符串通过 split 方法分割成数组:
const currentLangs = typeof langs === 'string' ? langs.split('+') : langs;

2. 处理进度日志

可以通过 logger 回调函数查看任务进度:

Tesseract.recognize('image.png', 'eng', {logger: info => console.log(info.status, info.progress),
});

输出示例:

3. 自定义训练数据

如果需要识别特殊字符,可以加载自定义训练数据:

const worker = await createWorker('语言文件名', OEM.DEFAULT, {logger: info => console.log(info.status, info.progress),gzip: false, // 是否对来自远程的训练数据进行 gzip 压缩langPath: '/path/to/lang-data' // 自定义训练数据路径
});

[!warning] 注意:

  1. 第一个参数为加载自定义训练数据的文件名,不带后缀。
  2. 加载自定义训练数据的文件后缀名必须为 .traineddata
  3. 如果文件名不是 .traineddata.gzip,则需要设置 gzipfalse

举例

const worker = await createWorker('my-data', OEM.DEFAULT, {logger: info => console.log(info.status, info.progress),gzip: false,langPath: 'http://localhost:5173/lang',
});

加载效果:

4. 通过前端上传图片

通常,图片是通过前端让用户上传后进行解析的。以下是一个简单的 Vue 3 示例:

<script setup>
import { createWorker } from 'tesseract.js';async function handleUpload(evt) {const files = evt.target.files;const worker = await createWorker("chi_sim");for (let i = 0; i < files.length; i++) {const ret = await worker.recognize(files[i]);console.log(ret.data.text);} 
}
</script><template><input type="file" @change="handleUpload" />
</template>

完整示例

下面提供一个简单的 OCR 示例,展示了如何在前端实现图片上传、文字识别以及图像处理。

代码

<!--* @Author: zi.yang* @Date: 2024-12-10 09:15:22* @LastEditors: zi.yang* @LastEditTime: 2025-01-14 08:06:25* @Description: 使用 tesseract.js 实现 OCR* @FilePath: /vue-app/src/components/HelloWorld.vue
-->
<script setup lang="ts">
import { ref } from 'vue';
import { createWorker, OEM } from 'tesseract.js';const uploadFileName = ref<string>("");
const imgText = ref<string>("");const imgInput = ref<string>("");
const imgOriginal = ref<string>("");
const imgGrey = ref<string>("");
const imgBinary = ref<string>("");async function handleUpload(evt: any) {const file = evt.target.files?.[0];if (!file) return;uploadFileName.value = file.name;imgInput.value = URL.createObjectURL(file);const worker = await createWorker("chi_sim", OEM.DEFAULT, {logger: info => console.log(info.status, info.progress),});const ret = await worker.recognize(file, { rotateAuto: true }, { imageColor: true, imageGrey: true, imageBinary: true });imgText.value = ret.data.text || '';imgOriginal.value = ret.data.imageColor || '';imgGrey.value = ret.data.imageGrey || '';imgBinary.value = ret.data.imageBinary || '';
}// 占位符 svg
const svgIcon = encodeURIComponent('<svg t="1736901745913" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4323" width="140" height="140"><path d="M804.9 243.4c8.1 0 17.1 10.5 17.1 24.5v390.9c0 14-9.1 24.5-17.3 24.5H219.3c-8 0-17.3-10.7-17.3-24.5V267.9c0-14 9.1-24.5 17.3-24.5h585.6m0-80H219.3c-53.5 0-97.3 47-97.3 104.5v390.9c0 57.3 43.8 104.5 97.3 104.5h585.4c53.5 0 97.3-47 97.3-104.5V267.9c0-57.5-43.7-104.5-97.1-104.5z" fill="#5E9EFC" p-id="4324"></path><path d="M678.9 294.5c28 0 50.6 22.7 50.6 50.6 0 28-22.7 50.6-50.6 50.6s-50.6-22.7-50.6-50.6c0-28 22.7-50.6 50.6-50.6z m-376 317.6l101.4-215.7c6-12.8 24.2-12.8 30.2 0l101.4 215.7c5.2 11-2.8 23.8-15.1 23.8H318c-12.2 0-20.3-12.7-15.1-23.8z" fill="#5E9EFC" p-id="4325"></path><path d="M492.4 617L573 445.7c4.8-10.1 19.2-10.1 24 0L677.6 617c4.1 8.8-2.3 18.9-12 18.9H504.4c-9.7 0-16.1-10.1-12-18.9z" fill="#5E9EFC" opacity=".5" p-id="4326"></path></svg>');
const placeholder = 'data:image/svg+xml,' + svgIcon;
</script><template><div class="custom-file-upload"><label for="file-upload" class="custom-label">选择文件</label><span id="file-name" class="file-name">{{ uploadFileName || '未选择文件' }}</span><input id="file-upload" type="file" @change="handleUpload" /></div><div class="row"><div class="column"><p>输入图像</p><img alt="原图" :src="imgInput || placeholder"></div><div class="column"><p>旋转,原色</p><img alt="原色" :src="imgOriginal || placeholder"></div><div class="column"><p>旋转,灰度化</p><img alt="灰度化" :src="imgGrey || placeholder"></div><div class="column"><p>旋转,二值化</p><img alt="二进制" :src="imgBinary || placeholder"></div></div><div class="result"><h2>识别结果</h2><p>{{ imgText || '暂无结果' }}</p></div>
</template><style scoped>
/* 隐藏原生文件上传按钮 */
input[type="file"] {display: none;
}/* 自定义样式 */
.custom-file-upload {display: inline-block;cursor: pointer;margin-bottom: 30px;
}.custom-label {padding: 10px 20px;color: #fff;background-color: #007bff;border-radius: 5px;display: inline-block;font-size: 14px;cursor: pointer;
}.custom-label:hover {background-color: #0056b3;
}.file-name {margin-left: 10px;font-size: 14px;color: #555;
}.row {display: flex;width: 100%;justify-content: space-around;
}.column {width: 24%;padding: 5px;border: 1px solid #ccc;border-radius: 5px;background-color: #f9f9f9;text-align: center;min-height: 100px;
}.column > p {margin: 0 0 10px 0;padding: 5px;border-bottom: 1px solid #ccc;font-weight: 600;
}.column > img {width: 100%;
}.result {margin-top: 20px;padding: 10px;border: 1px solid #ccc;border-radius: 5px;background-color: #f9f9f9;
}.result > h2 {margin: 0;
}.result > p {white-space: pre-wrap;word-wrap: break-word;word-break: break-all;font-size: 16px;line-height: 1.5;color: #333;margin: 10px 0;
}
</style>

实现效果

资源加载失败

Tesseract.js 在运行时需要动态加载三个关键文件:Web Workerwasm训练数据。由于默认使用的是 jsDelivr CDN,国内用户可能会遇到网络加载问题。为了解决这个问题,可以通过指定 unpkg CDN 来加速资源加载:

const worker = await createWorker('chi_sim', OEM.DEFAULT, {langPath: 'https://unpkg.com/@tesseract.js-data/chi_sim/4.0.0_best_int',workerPath: 'https://unpkg.com/tesseract.js/dist/worker.min.js',corePath: 'https://unpkg.com/tesseract.js-core/tesseract-core-simd-lstm.wasm.js',
});

如果需要离线使用,可以将这些资源下载到本地,并将路径指向本地文件即可。

结语

Tesseract.js 是目前前端领域较为成熟的 OCR 库,适合在无需后端支持的场景下快速实现文字识别功能。通过合理的图片预处理和优化,可以满足大部分中小型应用的需求。

相关链接

  • Tesseract.js 文档: tesseract-ocr.github.io/
  • Tesseract.js Demo: tesseract.projectnaptha.com/

本文转载于:https://juejin.cn/post/7459791088791797786

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

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

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

相关文章

系统首页加载异常耗时问题

最近发现一个问题,之前开发好的一个项目部署到公司内网供部门内同事使用后,大家都反应每次登录系统后首页加载很长时间才刷出信息,且基本都是第一次(重新刷新浏览器则不会卡);若是把浏览器的记录删除掉,重启电脑,再访问系统同样是出现首页加载耗时时间长的问题。 为了这…

使用watch指令实时监控nvidia显卡状态

当你在训练模型等需要实时检查英伟达显卡状态的时候,使用watch是很好的解决方案相较于传统的nvidia-smi -l 1指令实时查看的显示效果不好看,watch可以标记处更新的部分,并且是动态刷新指令 watch -n 1 -d nvidia-smi-n或--interval watch缺省每2秒运行一下程序,可以用-n或-in…

国外知名字处理软件PowerFont软件的国内替代

国外知名字处理软件PowerFont在国内外广泛应用,可以同时处理shx跟TTF字库。并且可以进行路径优化,也可以导入dxf,plt文件来设计字符,用在激光打标等场合,但是无法在win10操作系统使用,而且价格昂贵,所以需要替代; 替代软件基本实现了powerfont常用功能,并且针对powerf…

【Qt 头文件】解决添加头文件之后,仍然提示找不到头文件的问题

类似于问题:在Qt项目中通过Add Existing Directory...添加头文件目录之后,代码仍然会报“D:\WorkSpace\mupdf\include\xxx.h:25: error: xxx.h: No such file or directory”错误。 如图中,在Custom中创建了Logmanager源文件以及对应的头文件,想要其他文件夹下的文件中使用…

jmeter定时器的使用10

1,固定定时器 2,高斯随机定时器 3,吞吐量定时器 本文永久更新地址:1,固定定时器 固定定时器也叫思考时间,就是在请求前停留一定的时间 如果把固定定时器放到根结点,就会对所有的请求都起作用 如果把固定定时器放到具体某个请求的子节点下,那作用域就是当前请求 设置了3s…

jmeter的界面介绍

前言 jmeter是一款进行接口自动化,性能测试的开源的工具 界面 jmeter菜单里面有个文件--模板,这个主要是一些请求不知道怎么设置时可以选择预制的一些模板选择对应的模板点击创建,就可以生成一个对应的记录,我们选择jdbc,创建后,就会生成jdbc,填写一些提示的信息运行菜单…

Worker模块源码实战:万字长文解析DolphinScheduler如何实现亿级任务调度

Apache DolphinScheduler的Worker模块是其分布式调度系统的核心组件之一,负责任务执行、资源管理及集群动态调度。本文将通过源码剖析,揭示其设计思想与实现细节. 1、Worker接收Master RPC请求架构图Worker服务的Netty提供和Master JDK动态代理接口调用,请参考Dolphinschedu…

oracle数据库借助ASH报告对enq: TX - row lock contention(行锁阻塞)问题进行排查

1、什么是ASH报告ASH报告是(Active Session History单词简写) ,利用 ASH 报告可以分析持续时间通常只有几分钟的瞬间性能问题 根据各种维度(如 time、session、module、action 或 sql_id )或这些维度的组合进行确定范围或目标的性能分析,瞬间性能问题持续的时间。 2、生成AS…

CUDA与Cython之BatchGather

以学习CUDA为目的,接上一篇关于Cython与CUDA架构下的Gather算子实现,这里我们加一个Batch的维度,做一个BatchGather的简单实现。技术背景 在前面一篇文章中,我们介绍过Cython+CUDA框架下实现一个简单的Gather算子的方法。这里演示Gather算子的升级版本实现——BatchGather算…

Ntdll DLL取消挂钩-磁盘导入

一、介绍 本文介绍如何通过将已挂钩的 NTDLL 的文本段覆盖为从磁盘的 NTDLL 映像中获取的未挂钩版本来实现 NTDLL 反挂钩。执行 NTDLL 反挂钩的步骤如下: 通过读取或映射(下面展示了这两种方法)从磁盘检索一个干净版本的 NTDLL 的句柄。 获取属于当前进程的挂钩 NTDLL 的句柄…

华大基因测序芯片(Flowcell)

一、公司简介: 深圳华大智造科技股份有限公司(简称华大智造)秉承“创新智造引领生命科技”的理念,致力于成为生命科技核心工具缔造者,专注于生命科学与生物技术领域,以仪器设备、试剂耗材等相关产品的研发、生产和销售为主要业务,为精准医疗、精准农业和精准健康等行业提…