光学字符识别或光学字符阅读器 (OCR) 是将文本图像转换为机器编码文本的过程。例如,您可以拍摄书页的图片,然后通过 OCR 软件运行它以提取文本。

在这篇博文中,我们将使用Tesseract OCR 库。Tesseract 是用 C/C++ 编写的,最初是在 1985 年到 1994 年间由惠普公司开发的。惠普在 2005 年开源了该软件。从那时起,谷歌一直在开发和维护它。

2018 年 10 月发布的最新版本 4 包含一个新的 OCR 引擎,该引擎使用基于 LSTM 的神经网络系统,这应该会显着提高准确性。版本 4 支持 123 种开箱即用的语言。源代码托管在 GitHub 上:https : //github.com/tesseract-ocr/tesseract

如前所述,Tesseract 引擎是用 C++ 编写的,不能在浏览器中运行。使用 C++ 引擎的唯一方法是将图片从 Web 应用程序发送到服务器,通过引擎运行它并将文本发回。

但是几年来,存在 Tesseract C++ 引擎的 JavaScript 端口,它在浏览器中运行并且不依赖于任何服务器端代码。该库名为 Tesseract.js,您可以在 GitHub 上找到源代码:https : //github.com/naptha/tesseract.js
该引擎最初是用ASM.js编写的,最近已移植到 WebAssembly。

我们将使用库的第 2 版。版本 2 是 Tesseract 4.1 的 WebAssembly 端口。当浏览器不支持 WebAssembly 时,库会回退到 ASM.js。

安装

您可以通过从 CDN 加载 Tesseract.js 将其添加到您的项目中

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

或通过安装它npm

npm install tesseract.js

基本用法

该库提供了recognize将图像作为输入并返回带有识别文本的对象的方法。这里有一个简单的例子

    const exampleImage = 'https://tesseract.projectnaptha.com/img/eng_bw.png';const worker = Tesseract.createWorker({logger: m => console.log(m)});Tesseract.setLogging(true);work();async function work() {await worker.load();await worker.loadLanguage('eng');await worker.initialize('eng');let result = await worker.detect(exampleImage);console.log(result.data);result = await worker.recognize(exampleImage);console.log(result.data);await worker.terminate();}

基本.html

参数

recognize方法需要一个图像作为第一个参数。该库支持 bmp、jpg、png 和 pbm 格式的图像。

图像可以提供给方法作为

  • imgvideo, 或canvas元素
  • 文件对象(来自文件<input>
  • Blob 对象
  • 图像的路径或 URL
  • base64 编码的图像

更多信息参见官方文档:https :
//github.com/naptha/tesseract.js/blob/master/docs/image-format.md

在调用recognize方法之前,您必须使用 来创建工作createWorker()线程,使用 加载 tesseract.js 核心脚本load(),使用 加载一种或多种语言的机器学习模型loadLanguage(...),最后使用 初始化 Tesseract API initialize(...)。您指定为initialize调用参数的语言可以是您加载的语言的子集loadLanguage()

下一个示例预先加载英语和西班牙语模型,但随后仅在下一次 API 调用中使用英语。

await worker.loadLanguage('eng+spa');
await worker.initialize('eng');

稍后在应用程序中,您只需通过另一个initialize(...)调用切换到另一种语言。

进步

OCR 进程运行几秒钟,如果要向用户显示进度信息,则配置一个进度侦听器。您可以通过将对象作为参数传递给createWorker()调用来做到这一点。该logger属性需要在识别过程中多次调用的函数。

    const worker = Tesseract.createWorker({logger: m => console.log(m)});

您在 logger 函数中作为参数获得的对象包含工作人员和作业 ID 以及属性statusprogressstatus是描述当前操作的字符串,progress是一个介于 0 和 1 之间的数字,表示当前进度的百分比。

进度示例:

{workerId: "Worker-0-4d98d", jobId: "Job-0-a37f4", status: "recognizing text", progress: 0.8285714285714286}

如果您需要更多内部信息,请将日志记录标志设置为 true。该库然后将更多信息打印到开发人员控制台中:setLogging(true)

结果

recognize()方法返回一个 Promise。您从成功调用中获得的对象包含data保存有关已识别文本的信息的属性。你要么访问文本与text属性,它包含了识别的文本作为一个字符串,或者你通过访问linesparagraphswords,或symbols性质。每个组元素都包含一个confidence分数,告诉您引擎的信心程度。分数是一个介于 0 到 100 之间的数字;较高的值表示较高的置信度。

{text: "Mild Splendour of the various-vested Nig ..."hocr: "<div class='ocr_page' id= ..."tsv: "1 1 0 0 0 0 0 0 1486 ..."box: nullunlv: nullosd: nullconfidence: 90blocks: [{...}]psm: "SINGLE_BLOCK"oem: "DEFAULT"version: "4.0.0-825-g887c"paragraphs: [{...}]lines: (8) [{...}, ...]words: (58) [{...}, {...}, ...]symbols: (295) [{...}, {...}, ...]
}

当您使用属性lines和访问文本时paragraphs,您将获得按行和段落分组的文本。该words包含每个识别的词的数组,symbols让你访问的每个字符。

这些属性的每个元素都包含bbox表示边界框 x/y 坐标的属性。在演示应用程序中,我使用此信息在所选文本周围绘制一个矩形。

这是words数组中元素的示例。该text属性包含单词,并confidence告诉我们置信度分数。line,并paragraph引用该单词所在的行和段落对象。symbols是一个单独保存每个字符的数组 ( Mild)。

{symbols: Array(4)0: {choices: Array(1), image: null, text: "M", confidence: 99.03752899169922, baseline: {...}, ...}1: {choices: Array(1), image: null, text: "i", confidence: 98.83988952636719, baseline: {...}, ...}2: {choices: Array(1), image: null, text: "l", confidence: 99.01886749267578, baseline: {...}, ...}3: {choices: Array(1), image: null, text: "d", confidence: 99.0378646850586, baseline: {...}, ...}choices: [{...}]text: "Mild"confidence: 91.87923431396484baseline: {x0: 38, y0: 84, x1: 167, y1: 85, has_baseline: true}bbox: {x0: 38, y0: 34, x1: 167, y1: 85}is_numeric: falsein_dictionary: falsedirection: "LEFT_TO_RIGHT"language: "eng"is_bold: falseis_italic: falseis_underlined: falseis_monospace: falseis_serif: falseis_smallcaps: falsefont_size: 17font_id: -1font_name: ""page: ...block: ...paragraph: {lines: Array(8), text: "Mild Splendour ...", confidence: 91.35659790039062, ...}line: {words: Array(6), text: "Mild Splendour ...", confidence: 92.46450805664062, ...}
}

如果要查看完整的结果对象,请访问 URL Basic Usage并打开开发人员控制台。

探测

Tesseract.js 库提供的另一种方法是detect(). 此方法尝试检测方向和脚本。像recognize()这个方法需要一个图像作为第一个参数并返回一个 Promise。

  const result = await worker.detect(image);

结果对象包含属性data,该属性保存有关检测到的脚本和方向以及相应的置信度分数的信息。

{tesseract_script_id: 1script: "Latin"script_confidence: 39.58333969116211orientation_degrees: 0orientation_confidence: 29.793731689453125
}

更多信息参见官方文档:https :
//github.com/naptha/tesseract.js/blob/master/docs/api.md#worker-detect

清理

该库在 Web Worker 中运行 OCR 引擎。如果您的应用程序不再需要该工作线程,您应该使用worker.terminate().

更多例子

查看文档页面以获取更多代码示例:https :
//github.com/naptha/tesseract.js/blob/master/docs/examples.md

演示应用程序

在本节中,我将展示如何将 Tesseract.js 库合并到 Angular/Ionic 应用程序中。

您可以在 GitHub 上找到完整应用程序的源代码:https :
//github.com/ralscha/blog2019/blob/master/webocr

演示应用程序托管在我的服务器上,您可以通过以下 URL 访问它:https :
//omed.hplar.ch/webocr/

演示应用程序不依赖于任何服务器端代码,OCR 在 Web 浏览器本地运行,不向服务器发送任何数据。

该应用程序基于 Ionic 空白入门模板。首先,我将最新版本的 Tesseract.js 添加npm install tesseract.js到项目中。

在 TypeScript 代码中,我导入了库

import {createWorker, RecognizeResult} from 'tesseract.js';

作为输入,应用程序使用类型为 file ( type="file")的输入标记。每次用户选择一个文件时,onFileChange都会调用该方法,该方法从输入标记中提取 File 对象并将其传递给该recognize()方法。

  <input #fileSelector (change)="onFileChange($event)" accept="image/*" style="display: none;"type="file">

主页.html

然后,所选图片也被加载到 Image 对象中。应用程序不使用img标签来显示图片。相反,它将图片绘制到画布中。我在这里使用画布是因为每当用户单击文本时,应用程序都会在文本周围绘制矩形。

  async onFileChange(event: Event): Promise<void> {// @ts-ignorethis.selectedFile = event.target.files[0];this.progressStatus = '';this.progress = null;this.result = null;this.words = null;this.symbols = null;this.selectedLine = null;this.selectedWord = null;this.selectedSymbol = null;this.image = new Image();this.image.onload = () => this.drawImageScaled(this.image);this.image.src = URL.createObjectURL(this.selectedFile);/*const worker = createWorker({logger: progress => {this.progressStatus = progress.status;this.progress = progress.progress;this.progressBar.set(progress.progress * 100);this.changeDetectionRef.markForCheck();}});*/const worker = createWorker({workerPath: 'tesseract-202/worker.min.js',corePath: 'tesseract-202/tesseract-core.wasm.js',logger: progress => {this.progressStatus = progress.status;this.progress = progress.progress;this.progressBar.set(progress.progress * 100);this.changeDetectionRef.markForCheck();}});await worker.load();await worker.loadLanguage(this.language);await worker.initialize(this.language);this.progressBar.set(0);try {if (this.selectedFile) {const recognizeResult = await worker.recognize(this.selectedFile);if (recognizeResult) {this.result = recognizeResult.data;} else {this.result = null;}await worker.terminate();}} catch (e) {this.progressStatus = e;this.progress = null;} finally {this.progressBar.complete();this.progressStatus = null;this.progress = null;}// reset file input// @ts-ignoreevent.target.value = null;}

主页.ts

为了显示结果,我使用了Angular Material 项目中的列表元素。您可以使用命令将 Angular Material 添加到任何 Angular 项目。ng add @angular/material

这里是单词列表的模板:

  <div *ngIf="words" class="table-container mat-elevation-z1 ion-margin-top"><table [dataSource]="words" mat-table><ng-container matColumnDef="text"><th *matHeaderCellDef mat-header-cell>Word</th><td *matCellDef="let word" mat-cell> {{word.text}} </td></ng-container><ng-container matColumnDef="confidence"><th *matHeaderCellDef mat-header-cell>Confidence</th><td *matCellDef="let word" mat-cell> {{word.confidence | number:'1.2-2'}} %</td></ng-container><tr *matHeaderRowDef="elementColumns; sticky: true" mat-header-row></tr><tr (click)="onWordClick(word)" *matRowDef="let word; columns: elementColumns;"[ngClass]="{'highlight': selectedWord === word}"mat-row></tr></table></div>

主页.html

当用户单击列表项时,应用程序会在所选文本周围绘制一个矩形

  drawBBox(bbox: { x0: number, x1: number, y0: number, y1: number }): void {if (bbox) {this.redrawImage();if (this.ratio === null) {throw new Error('ratio not set');}this.ctx.beginPath();this.ctx.moveTo(bbox.x0 * this.ratio, bbox.y0 * this.ratio);this.ctx.lineTo(bbox.x1 * this.ratio, bbox.y0 * this.ratio);this.ctx.lineTo(bbox.x1 * this.ratio, bbox.y1 * this.ratio);this.ctx.lineTo(bbox.x0 * this.ratio, bbox.y1 * this.ratio);this.ctx.closePath();this.ctx.strokeStyle = '#bada55';this.ctx.lineWidth = 2;this.ctx.stroke();}}onLineClick(line: Line): void {this.words = line.words;this.drawBBox(line.bbox);this.symbols = null;this.selectedLine = line;this.selectedWord = null;this.selectedSymbol = null;}

主页.ts

自托管

当您的应用程序创建并初始化 TesseractWorker 时,该库将下载多个文件。

const worker = createWorker({...});
await worker.load();
await worker.loadLanguage(this.language);
await worker.initialize(this.language);

默认情况下,这些文件不是打包应用程序的一部分,Tesseract.js 将从 3rd 方服务器下载这些文件。最新版本将下载这些文件:

  • https://unpkg.com/tesseract.js@2.1.4/dist/worker.min.js (56 KB)
  • https://unpkg.com/tesseract.js-core@2.1.0/tesseract-core.wasm.js (1.0 MB)
  • https://tessdata.projectnaptha.com/4.0.0/eng.traineddata.gz (10.4 MB)

如果应用程序调用该detect()方法,则会下载一个附加文件。

  • https://tessdata.projectnaptha.com/4.0.0/osd.traineddata.gz (4.1 MB)

当您编写从本地服务器下载文件要快得多的内部应用程序时,这不是最佳解决方案。或者您希望完全控制所有应用程序资源,而不必担心这些 3rd 方服务器的可用性。如果其中一台服务器不工作,您的应用程序将不再工作。

无论是什么原因,您都可以轻松自托管这些文件。Web Worker JavaScript 和 Web Assembly 文件是 Tesseract.js npm 包的一部分,因此我们可以将这两个文件从 node_modules 目录复制到 build 文件夹。在 Angular 应用程序中,您可以通过将以下两个条目添加到 build->options->assets 数组来实现。

                "glob": "worker.min.js","input": "node_modules/tesseract.js/dist/","output": "./tesseract-202"},{"glob": "tesseract-core.wasm.js","input": "node_modules/tesseract.js-core/","output": "./tesseract-202"}],

angular.json

Angular CLI 负责将这两个文件复制到 build 文件夹。在应用程序中,我们需要告诉 Tesseract.js 它必须从本地目录加载这两个文件,而不是从 unpkg.com 获取它们。

    const worker = createWorker({workerPath: 'tesseract-202/worker.min.js',corePath: 'tesseract-202/tesseract-core.wasm.js',...});

该库从 tessdata.projectnaptha.com 下载的机器学习模型不能作为 npm 包使用。有不同的方式来自我托管它们。如果您只需要支持几种语言,您可以从 Git 存储库(GitHub - naptha/tessdata: Tesseract Language Trained Data)下载文件,并在构建过程中使用 npm 脚本将它们放入构建文件夹。

请注意,这些文件非常大,每次构建应用程序时下载它们可能需要一些时间。

您可以下载所需的文件并将它们复制到您控制的 HTTP 服务器上,而不是将它们添加到项目中。如果您需要支持多种语言,您可以克隆整个存储库。

git clone https://github.com/naptha/tessdata.git

下载所有文件需要 4.8 GB 的磁盘空间!

每种语言都有三种不同的版本:普通、快速和最佳。最好的版本为您提供更高的 OCR 准确性,但缺点是您的应用程序必须下载更大的机器学习模型文件。对于英语语言,最佳文件大小为 12.2 MB,正常为 10.4 MB,快速为 1.89 MB。

与 Web Worker 文件一样,您需要在作为参数传递给createWorker.

    const worker = createWorker({workerPath: 'tesseract-202/worker.min.js',corePath: 'tesseract-202/tesseract-core.wasm.js',langPath: 'https://myserver/4.0.0',...});

该库通过组合langPath+ 语言代码 + '.traineddata.gz'创建 URL

更多信息请访问官方文档页面:https :
//github.com/naptha/tesseract.js/blob/master/docs/local-installation.md

使用 Tesseract.js 在浏览器中使用 OCR相关推荐

  1. 使用 Tesseract.js 在浏览器中进行 OCR

    光学字符识别或光学字符阅读器 (OCR) 是将文本图像转换为机器编码文本的过程.例如,您可以为书页拍照,然后通过 OCR 软件运行以提取文本. 在这篇博文中,我们将使用Tesseract OCR 库. ...

  2. js判断wifi_使用JS在浏览器中判断当前网络连接状态的几种方法

    使用JS在浏览器中判断当前网络状态的几种方法如下: 1. navigator.onLine 2. ajax请求 3. 获取网络资源 4. bind() 1. navigator.onLine 通过na ...

  3. [js] 在不支持js的浏览器中如何隐藏JavaScript代码?

    [js] 在不支持js的浏览器中如何隐藏JavaScript代码? 在<script>标签之后的代码中添加"<!-– ",不带引号. 在</script&g ...

  4. 狗和披萨:使用TensorFlow.js在浏览器中实现计算机视觉

    目录 起点 托管说明 MobileNet v1 运行物体识别 终点线 下一步是什么?绒毛动物? 下载TensorFlowJS示例-6.1 MB TensorFlow + JavaScript.现在,最 ...

  5. 使用TensorFlow.js在浏览器中进行深度学习入门

    目录 设置TensorFlow.js 创建训练数据 检查点 定义神经网络模型 训练AI 测试结果 终点线 内存使用注意事项 下一步是什么?狗和披萨? 下载TensorFlowJS示例-6.1 MB T ...

  6. 使用face-api和Tensorflow.js在浏览器中进行AI年龄估计

    目录 性别和年龄检测 下一步是什么? 下载源-10.6 MB 在上一篇文章中,我们学习了如何使用face-api.js和Tensorflow.js在浏览器中对人的情绪进行分类. 如果您尚未阅读该文章, ...

  7. 图像迁移风格保存模型_用TensorFlow.js在浏览器中部署可进行任意图像风格迁移的模型...

    风格迁移一直是很多读者感兴趣的内容之一,近日,网友ReiichiroNakano公开了自己的一个实现:用TensorFlow.js在浏览器中部署可进行任意图像风格迁移的模型.让我们一起去看看吧! Gi ...

  8. js如何在浏览器中运行php文件下载,JavaScript_用JS在浏览器中创建下载文件,但受限于浏览器,很多情况下 - phpStudy...

    用JS在浏览器中创建下载文件 但受限于浏览器,很多情况下我们都只能给出个链接,让用户点击打开->另存为.如下面这个链接: file.js 用户点击这个链接的时候,浏览器会打开并显示链接指向的文件 ...

  9. 使用迁移学习和TensorFlow.js在浏览器中进行AI情感检测

    目录 KNN分类器 迁移学习 我们的技术栈 配置 使用KNN分类器 将代码放在一起 测试结果 下一步是什么? 下载源-10.6 MB 在上一篇文章中,我们已经看到了加载预训练模型有多么容易.在本文中, ...

最新文章

  1. Mysterious Bacteria LightOJ - 1220[唯一分解定理+思维题]
  2. C# WinForm获取当前路径汇总
  3. Hyper-V备份:选择Hypervisor备份还是虚拟机备份
  4. 第7周实践项目2 队列的链式存储结构及其基本运算的实现
  5. android listview 禁止滚动
  6. 自定义函数strcomp(),实现两个字符串的比较
  7. 高等数学下-赵立军-北京大学出版社-题解-练习9.1
  8. 帝国CMS7.5小品屋在线小品相声视频网站模板修复版
  9. 使用 Adobe AIR 管理 WordPress 评论
  10. ros发布节点信息python_ROS入门笔记(一): ROS简介
  11. 网工路由交换相关配置
  12. 机器视觉光源知识总结(二)
  13. 发现一个记录笔记的方法(康奈尔笔记即5R笔记)
  14. python修改文件的某一行_简单文件操作python 修改文件指定行的方法
  15. session 对象的绑定、解绑和钝化、活化
  16. 优联键盘linux驱动,一个坚决不用樱桃轴的优联84客制化键盘
  17. setex php,python redis setex可以设value为list或者其他数据结构吗?
  18. 【ERROR】java java.lang.NoClassDefFoundError 的解决办法(全)
  19. win7在扩展屏/副屏显示任务栏
  20. 小爱同学控制灯 局域网

热门文章

  1. 报价、订货、付款方式、通关、保险、提单、结汇等问题解析
  2. creo安装后打开提示license错误
  3. 一篇文章让你了解ADAS-HIL测试方案
  4. 数据中心如何提高运维效率?数据中心综合能效管理解决方案——安科瑞 严新亚
  5. 积分中轮换对称性的本质
  6. Unity常用文件夹
  7. 视频网站如何选择视频服务器呢?
  8. vue大文件(视频)上传解决方案
  9. php防CC攻击代码
  10. Android11 无Root 访问data目录实现、Android11访问data目录、Android11解除data目录限制、Android11 data空白解决