C#使用Tesseract C++ API过程记录

Tesseract

Tesseract 是一个开源的光学字符识别(OCR)引擎,最初由 Hewlett-Packard(惠普)实验室开发,后来由 Google 收购并继续维护和开源贡献。Tesseract 可以识别多种语言的文字,广泛应用于将图片或扫描文档中的文本内容转换成可编辑的文本格式。随着深度学习技术的发展,Tesseract 也整合了基于深度神经网络的 OCR 模型,提升其识别准确率,特别是对于复杂排版和手写体的识别效果有所改善。

Tesseract 适合开发人员和研究人员使用,可以嵌入到各种应用中,比如文档数字化、图像处理软件、内容管理系统等。它支持命令行操作,也提供了丰富的 API 接口,支持 C++、Python、Java、Node.js 等多种编程语言,便于集成和调用。Tesseract 的核心功能包括文本检测、字符识别和后处理纠错,能够处理多种图像输入格式,输出包括纯文本、HOCR(HTML + OCR)格式、PDF 等多种格式。Tesseract 的高灵活性和强大的识别能力使其成为 OCR 领域中非常受欢迎的工具之一。

GitHub地址:https://github.com/tesseract-ocr/tesseract

image-20241227152937200

Tesseract提供了丰富的 API 接口,支持 C++、Python、Java、Node.js 等多种编程语言,没有C#的,实际上已经有大佬做了C#的封装了,并提供了一个示例项目,需要只是简单使用一下,用这个大佬的就很方便了。

感兴趣的可以瞧瞧:

项目GitHub地址:https://github.com/charlesw/tesseract

image-20241227153302569

示例GitHub地址:https://github.com/charlesw/tesseract-samples

image-20241227153437445

但这不是我们今天的主题,现在还处于学习阶段,能直接使用大佬的库确实很方便,但是如果自己能够知道大佬是怎么实现的,那不是也很酷吗?

实现的方式与大佬项目的方式是类似的,如下所示:

image-20241227153822517

需要依赖leptonica-1.82.0.dll与tesseract50.dll,然后通过DllImport导入其中的C++函数。

已经有现成的库了为什么不直接使用呢?

第一,项目中可能只需要用到Tesseract的几个C++ API而已,直接引用一大堆东西没有必要。第二,学习阶段,以自己学习掌握技能为主,自己先掌握了这项技能,然后偷懒了直接使用大佬的库也不迟。

Windows编译Tesseract

首先我们需要先在Windows上编译Tesseract,官方文档有一些介绍,文档地址:https://tesseract-ocr.github.io/tessdoc/Compiling.html。

查看文档之后,我使用这种方式:

image-20241227154722530

先来简单介绍一下vcpkg。

vcpkg

vcpkg是一个用来管理C++库的跨平台包管理工具,由微软开发并维护,旨在帮助开发者简化第三方库的集成和使用过程。vcpkg通过提供预编译的二进制包和源代码,使开发者能够在Windows、Linux和macOS等操作系统上轻松安装和管理C++库。它支持多种编译器,包括Visual Studio、GCC和Clang。vcpkg的使用非常简单,只需要下载并安装,然后通过命令行工具指定要安装的库名,vcpkg会自动下载、编译并安装所需的库及其依赖项。此外,vcpkg还具有版本控制功能,能够方便地切换库的不同版本。它对于提升开发效率、保持项目的一致性以及解决跨平台开发中的库兼容性问题非常有帮助。许多开源项目和商业软件都选择使用vcpkg来管理和分发依赖库。

使用vcpkg安装Tesseract

git clone https://github.com/microsoft/vcpkg.git
cd vcpkg; .\bootstrap-vcpkg.bat
vcpkg install tesseract:x64-windows

安装完成:

image-20241226105928367

vcpkg integrate install

image-20241226110526085

为这个 vcpkg 根目录应用了全局用户集成。 CMake 项目应使用:“-DCMAKE_TOOLCHAIN_FILE=D:/Learning/vcpkg/scripts/buildsystems/vcpkg.cmake”

现在所有 MSBuild C++ 项目都可以 #include 任何已安装的库。链接将会自动处理。安装新库后,它们将立即可用。

vcpkg list

image-20241226110859781

新建一个C++项目使用Tesseract C++ API

我写了两个简单的函数用于测试。

头文件:

#pragma once
extern "C" __declspec(dllexport) char* getChineseText(const char* imagePath);
extern "C" __declspec(dllexport) char* getEnglishText(const char* imagePath);
extern "C" __declspec(dllexport) void freeMemory(char* ptr);

源文件:

#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#include "test.h"
#include <iostream>void windows_cmd_support_utf8(void)
{system("chcp 65001 & cls"); //cls 用来清除 chcp 的输出
}char* getEnglishText(const char* imgPath) {tesseract::TessBaseAPI* api = new tesseract::TessBaseAPI();if (api->Init(NULL, "eng")) {fprintf(stderr, "Could not initialize tesseract.\n");delete api;return nullptr;}Pix* image = pixRead(imgPath);if (!image) {fprintf(stderr, "Could not read image file.\n");api->End();delete api;return nullptr;}api->SetImage(image);char* outText = api->GetUTF8Text();if (!outText) {fprintf(stderr, "OCR failed.\n");api->End();pixDestroy(&image);delete api;return nullptr;}api->Clear();api->End();delete api;pixDestroy(&image);return outText;
}char* getChineseText(const char* imgPath) {tesseract::TessBaseAPI* api = new tesseract::TessBaseAPI();if (api->Init(NULL, "chi_sim")) {fprintf(stderr, "Could not initialize tesseract.\n");delete api;return nullptr;}Pix* image = pixRead(imgPath);if (!image) {fprintf(stderr, "Could not read image file.\n");api->End();delete api;return nullptr;}api->SetImage(image);char* outText = api->GetUTF8Text();if (!outText) {fprintf(stderr, "OCR failed.\n");api->End();pixDestroy(&image);delete api;return nullptr;}api->Clear();api->End();delete api;pixDestroy(&image);return outText;
}void freeMemory(char* ptr) {delete[] ptr;
}int main()
{ const char* imgPath = "D:\\SemanticKernel-Test2.png";  // 替换为你的图像文件路径const char* imgPath2 = "D:\\test666.png";  // 替换为你的图像文件路径// 第一次调用char* result1 = getChineseText(imgPath);windows_cmd_support_utf8();std::cout << "OCR Result 1: " << result1 << std::endl;// 第二次调用char* result2 = getChineseText(imgPath2);std::cout << "OCR Result 2: " << result2 << std::endl;// 释放内存//freeMemory(result1);//freeMemory(result2);return 0;  // 程序正常结束}

注意📍📍📍

先将项目配置成X64:

image-20241227160709604

现在运行项目,会出现一个错误,因为并没有包含tessdata。

tessdata 是 Tesseract OCR 引擎使用的一种数据文件格式,用于存储语言模型和字符识别数据。Tesseract 通过加载这些数据文件来实现对不同语言文字的识别。每个语言都有一套对应的 tessdata 文件,通常命名为 lang.traineddata,其中 lang 是语言的缩写(例如,eng 表示英语,chi_sim 表示简体中文)。

tessdata的GitHub地址:https://github.com/tesseract-ocr/tessdata

image-20241227185027622

也可以看我后面分享的GitHub,一般只要中英文就可以了,如下所示:

image-20241227185504978

将tessdata文件夹放在x64的Debug目录下即可。

先测试中文识别效果:

测试图片1

测试图片2

查看效果:

image-20241227155928432

注意📍📍📍

如果不加上windows_cmd_support_utf8();

就会出现乱码,如下所示:

image-20241227160300511

并不是Tesseract识别中文效果不好,只是控制台默认没支持utf-8罢了。

再来测试一下英文:

测试图片1

测试图片2

效果如下所示:

image-20241227190017513

生成DLL

测试没有问题之后,现在需要生成DLL文件。

右键项目,点击属性,设置配置类型为DLL:

image-20241227190254191

生成解决方案之后,如下所示:

image-20241227190504150

这里需要搞清楚的是为什么头文件不用std::string而是char*呢?

#pragma once
extern "C" __declspec(dllexport) char* getChineseText(const char* imagePath);
extern "C" __declspec(dllexport) char* getEnglishText(const char* imagePath);
extern "C" __declspec(dllexport) void freeMemory(char* ptr);
  • extern "C":这告诉编译器这些函数应该按照C语言的方式进行链接,而不是C++的方式。这样可以确保这些函数在C语言中也可以被正确调用。
  • 简单的说std::string不是C语言风格的,所以不行。

在C#项目中调用C++ DLL

新建一个C#控制台项目用于测试。

测试代码如下:

using System.Runtime.InteropServices;class Program
{[DllImport("TesseractApiTest.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]public static extern IntPtr getEnglishText(string imagePath);[DllImport("TesseractApiTest.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]public static extern IntPtr getChineseText(string imagePath);static void Main(){string imagePath = @"D:\SemanticKernel-Test2.png";// 调用 DLL 中的函数IntPtr resultPtr = getChineseText(imagePath);if (resultPtr == IntPtr.Zero){return;}string? result = Marshal.PtrToStringUTF8(resultPtr);return; ;}
}

将项目设置成X64平台,将C++项目的所有输出文件,复制到X64的输出目录这里,如下所示:

image-20241227191524217

为了避免太混乱,本来想新建一个Libs文件夹,在放这些文件,在设置为嵌入的资源与如果较新就复制,但是就调用不了了,暂时没有解决,只能这样一堆放在这里了。

效果如下:

image-20241227191730397

这里需要注意一下,为什么是

  [DllImport("TesseractApiTest.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]public static extern IntPtr getEnglishText(string imagePath);

而不是

  [DllImport("TesseractApiTest.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]public static extern string getEnglishText(string imagePath);

在C#中直接使用 string 作为返回类型并不适用于从C++导出的函数,尤其是当该函数返回的是一个 char* 类型的指针时。原因在于 char* 是一个指向C风格字符串的指针,而C#中的 string 类型与C风格字符串并不直接兼容。C#的 string 类型是一个托管的字符串对象,而 char* 是一个非托管的指针,直接进行转换会导致运行时错误或无法预期的行为。

使用 IntPtr 作为返回类型可以解决这个问题,因为 IntPtr 是一个可以表示非托管指针的类型。你可以通过 Marshal 类将 IntPtr 转换为C#中的 string。这样可以确保你在C#中能够正确处理C++函数返回的字符串指针。

TesseractOCR-GUI中集成

之前跟大家分享的TesseractOCR-GUI需要在电脑上安装Tesseract才能用,因为只是简单的对Tesseract的命令行使用做了封装,现在通过这种方法,不需要安装Tesseract也能使用了。

GitHub地址:https://github.com/Ming-jiayou/TesseractOCR-GUI。

image-20241227192409247

git clone到本地,然后将平台设置成X64,先生成解决方案,然后将Libs文件夹下的内容,全部复制到x64的输出目录,如下所示:

image-20241227192607954

image-20241227192639528

现在直接点击应该就可以使用了:

image-20241227192803222

效果如下所示:

image-20241227193007146

速度还是很快的,目前为止我们尝试了TesseractOCR、PaddleOCR、VLM,其中TesseractOCR我感觉是最快的。

以上就是本期的分享内容,希望对你有所帮助。

推荐阅读:

C#调用C++代码,以OpenCV为例

C#调用Python脚本的方式(一),以PaddleOCR-GUI为例

C#调用Python代码的方式(二),以PaddleOCR-GUI为例

VLM-OCR-Demo:一个使用VLM用于OCR任务的示例

TesseractOCR-GUI:基于WPF/C#构建TesseractOCR简单易用的用户界面

使用Tesseract进行图片文字识别

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

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

相关文章

在交叉编译中,常见的ELF(elf)到底是什么意思?

ELF 是 Executable and Linkable Format 的缩写&#xff0c;中文翻译为“可执行与可链接格式”。它是一种通用的文件格式&#xff0c;主要用于存储可执行文件、目标文件&#xff08;编译后的中间文件&#xff09;、动态库&#xff08;.so 文件&#xff09;以及内存转储文件&…

使 el-input 内部的内容紧贴左边

<el-inputv-model"form.invitor"placeholder"PC端的自动取当前账号的手机号"readonlyclass"no-border-input" />::v-deep(.no-border-input .el-input__inner) { border: none; box-shadow: none; padding-left: 0; /* 确保内容紧贴左边 *…

国标GB28181-2022平台EasyGBS:安防监控中P2P的穿透方法

在安防监控领域&#xff0c;P2P技术因其去中心化的特性而受到关注&#xff0c;尤其是在远程视频监控和数据传输方面。P2P技术允许设备之间直接通信&#xff0c;无需通过中央服务器&#xff0c;这在提高效率和降低成本方面具有明显优势。然而&#xff0c;P2P技术在实际应用中也面…

前端开发 -- 自动回复机器人【附完整源码】

一&#xff1a;效果展示 本项目实现了一个简单的网页聊天界面&#xff0c;用户可以在输入框中输入消息&#xff0c;并点击发送按钮或按下回车键来发送消息。机器人会根据用户发送的消息内容&#xff0c;通过关键字匹配来生成自动回复。 二&#xff1a;源代码分享 <!DOCTYP…

【速成51单片机】1.已经学过stm32如何快速入门51单片机——软件下载与安装

引言 本系列专题用于已经熟悉stm32单片机的情况下&#xff0c;快速掌握51单片机。背景是我其实大一大二已经进入学校实验室了&#xff0c;已经学习了stm32单片机&#xff0c;但是现在大三期末考51单片机&#xff0c;实际期末复习更应该看老师给的重点和背书上知识点。但我不想…

node-js Express防盗链

什么是防盗连 一个简单的说明&#xff0c;假如在前端img标签想要引用图片网站上的图片&#xff0c;当你将图片地址放到img标签上想要显示的时候你发现&#xff0c;图片显示不了&#xff0c;这说明网站采用了防盗链。 怎么实现的呢 在请求头中一般会有 Referer&#xff0c;它…

68jQuery【jQuery操作DOM、事件】

jQuery jQuery操作DOM 元素节点的增删改查 创建元素节点 使用$(html)函数动态创建节点元素 函数$(html)只完成DOM元素创建&#xff0c;加入到页面还需要通过元素节点的插入或追加操作&#xff1b;同时&#xff0c;在创建DOM元素时&#xff0c;要注意字符标记是否完全闭合&am…

lin.security提权靶场渗透

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

基于aspose.words组件的word bytes转pdf bytes,去除水印和解决linux中文乱码问题

详情见 https://preferdoor.top/archives/ji-yu-aspose.wordszu-jian-de-word-byteszhuan-pdf-bytes

[python学习笔记]对象、引用、浅复制、深复制

学了这么多年编程&#xff0c;发现在学校都是浑水摸鱼&#xff0c;从来没有精通过一门语言&#xff0c;一个月熟悉python和算法。不积硅步&#xff0c;无以至千里。 本文笔记来自以下博客&#xff0c;请参考原文。 Python&#xff1a;深拷贝与浅拷贝 - 七落安歌 - 博客园 h…

arm架构 uos操作系统离线安装k8s

目录 操作系统信息 安装文件准备 主机准备 主机配置 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 系统参数设置(所有节点) 配置ipvs功能(所有节点) 安装docker&#xff08;所有节点&#xff09; 卸载老版本 安装docke…

Animated Drawings:让纸上的角色动起来

前言 今天介绍的这个工具非常的有意思&#xff1a;它可以让我们在纸上绘画的角色动起来。先一起来看看效果&#xff1a; 准备 首先&#xff0c;我们先准备一张绘画。可以在纸上进行绘制&#xff0c;也可以在电子设备上进行绘制。绘制内容不限&#xff0c;在这里为了方便演示&am…

【WRF模拟】如何得到更佳的WRF模拟效果?

【WRF模拟】如何得到更佳的WRF模拟效果&#xff1f; 模型配置&#xff08;The Model Configuration&#xff09;1.1 模拟区域domain设置1.2 分辨率Resolution (horizontal and vertical)案例&#xff1a;The Derecho of 29-30 June 2012 1.3 初始化和spin-up预热过程案例1-有无…

javaweb 04 springmvc

0.1 在上一次的课程中&#xff0c;我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求 /hello 后 &#xff0c;给浏览器返回字符串 “Hello World ~”。 其实呢&#xff0c;是我们在浏览器发起请求&#xff0c;请求了我们…

openGauss与GaussDB系统架构对比

openGauss与GaussDB系统架构对比 系统架构对比openGauss架构GaussDB架构 GaussDB集群管理组件 系统架构对比 openGauss架构 openGauss是集中式数据库系统&#xff0c;业务数据存储在单个物理节点上&#xff0c;数据访问任务被推送到服务节点执行&#xff0c;通过服务器的高并…

JS 设置按钮的loading效果

本文是在其他博主的博客JS学习笔记 | 遮罩层Loading实现_jsp loading-CSDN博客基础上&#xff0c;进行实践的。 目录 一、需求 二、Jspcss实现代码 一、需求 在springboot项目中的原始html5页面中&#xff0c;原本的功能是页面加载时&#xff0c;使用ajax向后端发送请求&…

QT线程 QtConcurrent (深入理解)

QT多线程专栏共有16篇文章,从初识线程到、QMutex锁、QSemaphore信号量、Emit、Sgnals、Slot主线程子线程互相传值同步变量、QWaitCondition、事件循环、QObjects、线程安全、线程同步、线程异步、QThreadPool线程池、ObjectThread多线程操作、 moveToThread等线程操作进行了全…

“游戏信息化”:游戏后台系统的未来发展

3.1可行性分析 开发者在进行开发系统之前&#xff0c;都需要进行可行性分析&#xff0c;保证该系统能够被成功开发出来。 3.1.1技术可行性 开发该游戏后台系统所采用的技术是vue和MYSQL数据库。计算机专业的学生在学校期间已经比较系统的学习了很多编程方面的知识&#xff0c;同…

第十六届“蓝桥杯”全国软件和信息技术专业人才大赛简介及资料大全

蓝桥杯全国软件和信息技术专业人才大赛是由工业和信息化部人才交流中心主办的一项全国性竞赛&#xff0c;面向全国高校大学生&#xff0c;累计参赛院校超过1200余所&#xff0c;参赛人数达40万人&#xff0c;是我国极有影响力的高校IT类赛事。 “第十六届蓝桥杯全国软件和信息…

电子电气架构 --- 什么是自动驾驶技术中的域控制单元(DCU)?

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…