Qt利用VCPKG和CMake和OpenCV和Tesseract实现中英文OCR

Qt利用VCPKG和CMake和OpenCV和Tesseract实现中英文OCR

  今天看 OpenCV 方面的教程,pdf 格式的,因为一些强迫症的习惯,喜欢添加一些书签,手动是不太愿意的,自然就想到利用OCR来实现。

  想要自己编码实现OCR,方案比较简单就是 Tesseract 。单独使用 Tesseract 也可以,但最好利用 OpenCV 来进行图像方面的处理,一大堆方法可以滤波,变换,就是不停地调参数让人心烦,不同的图,需要使用不同的方法,也不清爽。出于总结的需要,把过程记录下。

  这个项目就是个Demo,比较简单,网上的水货,只有 Qt Creator 和 CMake 和 vcpkg 的配合使用 ,有点参考价值。

1. 开发平台

  • os : win10 x64
  • Qt:6.6
  • compiler:msvc2022
  • 项目管理:cmake
  • 包管理: vcpkg
  • 开发库版本:
    • OpenCV : 4.8 ,这个很友好,有编译出来的库,不需要自己去弄
    • Tesseract-ocr : 5.3 巨坑,二进制文件为啥不包含lib ? 🤯

2. 下载文件

  • 先说说踩过的坑,希望有相关经验的大佬,给点指点吧。

    • Tesseract 的坑

      在 Tesseract 的 https://github.com/tesseract-ocr/tesseract#installing-tesseract,有二进制包,兴冲冲地下载后,一看原来不是库文件,是可执行文件,这如何编码,用进程对话来实现?这包何用,对开发无益

      tesseract-ocr-w64-setup-5.3.3.20231005.exe (64 bit) 安装后 没有lib库,只有可执行文件

    • sw 坑

      既然没有 Tesseract 现成的库,那就需要自己编译了,在Tesseract 上接触到了 sw,这也是一个包管理方面的东西,关键是会自动下载,自动解决包依赖的问题,看上去很方便,兴冲冲地下载使用,发现网速也是刚刚的,cmake 也能使用,看看文档 下载添加环境变量在cmake设置依赖的包,然后等待成功吧。

      find_package(SW REQUIRED)
      sw_add_package(
      	org.sw.demo.glennrp.png
      )
      sw_execute()
      
      
      add_executable(mytarget ${MY_SOURCES})
      target_link_libraries(mytarget
      	org.sw.demo.glennrp.png
      )
      

      看上去很美好,但是 sw_execute() 这一步时间长的也是让人醉了,只要CMakeFiles.txt 一有变动,这玩意就会折腾好一阵子。

      有大佬会的么,指点一下细节。这东西看上去不错,值得鼓掌和期待。希望好起来吧。

      还有个swgui的客户端,也是折腾了一下,但是最后也没掌握,也搞不懂。遂弃之。

2.1 下载安装 OpenCV 库

  这一步很简单,官网有很多版本的,我就找了一个最新的

  Releases - OpenCV
在这里插入图片描述

下载安装,添加环境变量就行。就可以省略向生成的目录下 复制 dll 的步骤。

2.2 下载安装 Tesseract-OCR库

  踩过了SW的坑,还是回到了VCPKG。利用 IDM 和 迅雷 实现手动加速网络。过程比较繁琐,但是没啥难度。另外使用PowerShell 会方便一点。

vcpkg install tesseract --triplet=x64-windows

具体步骤:

  • 执行 vcpkg install tesseract --triplet=x64-windows
  • ctrl + c 中断
  • 复制下载链接,手动 IDM 或者 迅雷
  • 重命名
  • 继续 执行 vcpkg install tesseract --triplet=x64-windows

慢慢征途,应该有本小说在伴。祝网速好运。

另外不要自己去手动编译 Tesseract 库,这库依赖也多,依赖 leptonica 、archive.dll、bz2.dll、clang_rt.asan_dynamic-x86_64.dll、gif.dll、jpeg62.dll、libcrypto-3-x64.dll、libcurl.dll、liblzma.dll、libpng16.dll、libsharpyuv.dll、libwebp.dll、libwebpmux.dll、lz4.dll、openjp2.dll、tiff.dll、zlib1.dll、zstd.dll,烦透啦。

2.3 下载训练好的语言包

3. CMakeLists.txt 内容

cmake_minimum_required(VERSION 3.24)

project(36_Opencv4_Tesseract_OCR LANGUAGES CXX)

#set(CMAKE_CXX_STANDARD 17)
#set(CMAKE_CXX_STANDARD_REQUIRED ON)

##################### 设置 QT库   #####################
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

# 添加自定义代码的 include 和 source 路径
#include_directories  (D:/Project/qt_common_tools/global_define)
#aux_source_directory (D:/Project/qt_common_tools/global_define COMMON_TOOLS_LIST)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core )
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core )


##################### vcpkg 库  #####################
#寻找 TESSERACT 库
FIND_PACKAGE(tesseract REQUIRED)
#寻找 LEPTONICA 库
FIND_PACKAGE(leptonica REQUIRED)


##################### opencv 库  #####################
set(OpenCV_DIR C:/OpenCV/opencv/build)

#寻找OpenCV库
FIND_PACKAGE(OpenCV REQUIRED)

##打印调试信息
#MESSAGE(STATUS "Project: ${PROJECT_NAME}")
#MESSAGE(STATUS "OpenCV library status:")
#MESSAGE(STATUS "    version: ${OpenCV_VERSION}")
#MESSAGE(STATUS "    libraries: ${OpenCV_LIBS}")
#MESSAGE(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")


##################### 修改入口点  #####################
# 设置程序为 windows 程序 修改入口点,不显示 console
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup")

#################### 内存泄露检查 #####################
#SET(CMAKE_CXX_FLAGS "-fsanitize=address")

#获取代码,在项目中,将所有代码都放在src文件夹中
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
#MESSAGE(STATUS "Src file: ${DIR_SRCS}")



#################### 设置源码编码  ####################
#add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>")
#add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/execution-charset:GBK>")


#{{{{{{{{{{{{{{{{{{{ 编译可执行程序 }}}}}}}}}}}}}}}}}}}}#
add_executable( ${PROJECT_NAME}
#    WIN32
    ${DIR_SRCS}
    ${COMMON_TOOLS_LIST}
)



#################### 添加链接库    #####################
set(VCPKG_INCLUDE_DIR C:/vcpkg/installed/x64-windows/include)
set(VCPKG_LIB_DIR     C:/vcpkg/installed/x64-windows/lib)

# 头文件路径
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ${VCPKG_INCLUDE_DIR})

# lib文件路径
TARGET_LINK_DIRECTORIES(${PROJECT_NAME}
        PUBLIC
        ${VCPKG_LIB_DIR})

# lib文件
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC
     ${OpenCV_LIBS}
     tesseract53
     leptonica
     Qt${QT_VERSION_MAJOR}::Core
)

# 设置默认打开VCPKG
#set_target_properties(${PROJECT_NAME} PROPERTIES VS_GLOBAL_VcpkgEnabled true)

#################### 设置app ico  #####################
##set(app_icon_resource_windows ${CMAKE_CURRENT_SOURCE_DIR}/logo.rc)
##message(STATUS "${app_icon_resource_windows}")

4. Main.cpp

//#include "chinese.h"
#include "qdebug.h"

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <tesseract/baseapi.h> // tesseract main header

#include <QBuffer>
using namespace cv;

int main()
{
    std::string image_name = "txt.jpg";
    Mat imageMat;
    imageMat = imread(image_name);
    // imshow(ANSI("原图"), imageMat);
    imshow("origin", imageMat);
    if (imageMat.empty()) {
        printf("No image data \n");
        return -1;
    }
    // Rect ccomp;
    // floodFill(imageMat,Point(3,3),Scalar(255,255,255),&ccomp,Scalar(10,10,10),Scalar(20,20,20));
    cv::cvtColor(imageMat, imageMat, cv::COLOR_BGR2GRAY);

    char *outText;
    tesseract::TessBaseAPI tessbaseApi;

    if (tessbaseApi.Init("./", "chi_sim+eng")) { // chi_sim+eng  把下载的语言包 和 可执行文件放到一起
        std::cout << stderr << std::endl;
        exit(1);
    }
    // tesseract 设置图片
    tessbaseApi.SetImage((uchar *) imageMat.data, imageMat.cols, imageMat.rows, 1, imageMat.cols);

    // 获取 ocr 结果
    outText = tessbaseApi.GetUTF8Text();
    if (outText == nullptr) {
        std::cout << "没有数据" << std::endl;
    }
    QBuffer buf;
    buf.setData(outText);
    buf.open(QIODevice::ReadOnly);
    while (!buf.atEnd()) {
        QString line = buf.readLine();
        // line = removedSpaceInterChinese(line); // 自定义的函数 , 移除中文之间的空格 可以不考虑
        if (!line.trimmed().isEmpty())
            qDebug() << line;
    }

    delete[] outText;

    waitKey();
    return 0;
}

4.1 中英文混合OCR

tessbaseApi.Init("./", "chi_sim+eng")  

使用 + 号 连接 chi_sim、eng 就行

5. 在Qt Creator 中设置 CMake + vcpkg

cmake导入库: 可以手动编写 ,但既然能够偷懒,为啥要动手 O(∩_∩)O

但是第一步还得手动:

5.1 在初始化配置文件里修改

在这里插入图片描述
如果切换编译模式 realease —> debug 也得手动添加 /(ㄒoㄒ)/~~

5.2 在构建配置里修改

刚刚又捣鼓出来了一个,直接在 工具配置里 添加 -DCMAKE_TOOLCHAIN_FILE:STRING=C:/vcpkg/scripts/buildsystems/vcpkg.cmake 就行

推荐指数:⭐⭐⭐⭐⭐
在这里插入图片描述

说明:在Qt工程中CMake使用vcpkg安装的库

# 在Qt工程中使用vcpkg安装的库,改成自己的vcpkg安装目录
1. qt 在项目中添加
CMAKE_TOOLCHAIN_FILE   C:/vcpkg/scripts/buildsystems/vcpkg.cmake

2. CMakeList.txt
##################### vcpkg 库  #####################
#寻找 TESSERACT 库
FIND_PACKAGE(tesseract REQUIRED)

#寻找 LEPTONICA 库
FIND_PACKAGE(leptonica REQUIRED)

#################### 链接库    #####################
set(VCPKG_INCLUDE_DIR C:/vcpkg/installed/x64-windows/include)  // 这一步其实也可以修改,不用绝对路径
set(VCPKG_LIB_DIR     C:/vcpkg/installed/x64-windows/lib)

# 头文件路径
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ${VCPKG_INCLUDE_DIR})

# lib文件路径
TARGET_LINK_DIRECTORIES(${PROJECT_NAME}
        PUBLIC
        ${VCPKG_LIB_DIR})

# lib文件
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC
     tesseract53
     leptonica
)

6. 效果截图

在这里插入图片描述
在这里插入图片描述

7. 小结

构建套件:Desktop Qt 6.6 MSVC2019 64bit 可以使用 MSVC2022 版的c 和 c++的编译器,也算方便。如果msvc添加了142生成工具,那也可以手动添加编译,选择 msvc2019模式就行。

如果没有使用Qt的模块【就这个程序而言,完全可以不用qt】,用std::cout 输出,会发现 QC的应用程序输出框全是乱码,但是不要慌!

用cmd去执行程序,代码页切换到utf-8 : chcp 65001

想说的也说完了,大功告成!

<think>好的,我现在需要帮助用户解决一个使用QtOpenCV在C++中实现图片区域选择并进行OCR识别的问题。用户之前已经询问过实时绘制方框的实现,现在进一步要求整合图片打开、区域选择显示OCR结果。 首先,我要确认用户的需求:他们想要一个完整的应用程序,能够打开图片,用鼠标选择区域,调用OCR识别,并显示结果。技术栈是C++、QtOpenCV。需要注意的是,用户可能希望整个过程高效且用户界面友好。 接下来,我需要考虑如何将之前的实时绘制方框代码与OpenCVOCR功能结合起来。之前的回答已经用Qt实现了方框绘制,现在需要加入OpenCV处理图像的部分,以及OCR识别。可能的问题包括如何将Qt的图像与OpenCV的Mat转换,如何截取选定区域,以及调用OCR库。 然后,用户提到使用C语言Qt开发,但Qt本身是C++的,所以可能需要确认用户是否真的需要纯C,但更可能是用C++,所以按Qt的C++来处理。另外,OCR部分需要选择适合的库,比如Tesseract,用户可能没有明确说明,所以需要建议一个常用的开源库。 接下来,结构上应该分为几个部分:界面设计(打开图片、显示区域)、事件处理(鼠标绘制)、图像处理(OpenCV读取区域截取)、OCR识别(Tesseract集成)、结果显示。需要确保各部分之间的数据流正确,比如从Qt的Graphics View获取选区坐标,转换成OpenCV的ROI,进行OCR处理,再返回结果显示在Qt的界面上。 可能遇到的挑战包括坐标系的转换,尤其是在有缩放或滚动的情况下,需要正确映射鼠标位置到图像的实际像素坐标。此外,内存管理需要注意,特别是在频繁打开关闭图片时,避免内存泄漏。 还要考虑如何整合OpenCVQt,比如使用QPixmap或QImage来显示OpenCV的Mat对象,可能需要颜色空间的转换,因为OpenCV默认使用BGR,而Qt使用RGB。 关于OCR部分,需要指导用户安装配置Tesseract库,并在项目中正确链接。可能需要处理不同语言的支持,以及如何提高识别准确率,比如预处理图像(灰度化、二值化等)。 最后,代码结构需要清晰,方便用户理解扩展。可能需要提供完整的示例代码,包括头文件、源文件必要的配置说明。同时,提醒用户注意常见的错误,比如路径问题、库的版本兼容性等。 总结,整个思考过程需要从需求分析开始,拆解各个功能模块,考虑技术实现细节,确保各部分协同工作,并提供足够的错误处理用户反馈,比如状态栏显示信息。同时,代码示例需要准确,注释清晰,帮助用户顺利实现功能。</think>以下是基于QtOpenCV实现的完整图片选区OCR解决方案(C++实现): --- ### **完整实现步骤** #### 1. 环境准备 ```bash # 所需库 Qt 5.15+ (Core, Gui, Widgets) OpenCV 4.5+ Tesseract OCR 5.0+ (需训练数据) ``` #### 2. 核心类设计 ```mermaid classDiagram class MainWindow { -cv::Mat cvImage -QGraphicsPixmapItem* imageItem -QGraphicsRectItem* rubberBand -QPoint origin +openImage() +processOCR(QRect) +mousePressEvent() +mouseMoveEvent() +mouseReleaseEvent() } ``` #### 3. 完整代码实现 **mainwindow.h** ```cpp #include <QMainWindow> #include <opencv2/opencv.hpp> #include <tesseract/baseapi.h> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); protected: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; private slots: void openImage(); private: Ui::MainWindow *ui; cv::Mat cvImage; QGraphicsPixmapItem* imageItem = nullptr; QGraphicsRectItem* rubberBand = nullptr; QPoint origin; void processOCR(const QRect& area); void showImage(const cv::Mat& image); cv::Mat qImageToMat(const QImage& qImage); }; ``` **mainwindow.cpp** ```cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QFileDialog> #include <QGraphicsScene> #include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->graphicsView->setScene(new QGraphicsScene(this)); connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::openImage); } void MainWindow::openImage() { QString path = QFileDialog::getOpenFileName(this, "打开图片", "", "Images (*.png *.jpg *.bmp)"); if (path.isEmpty()) return; cvImage = cv::imread(path.toStdString()); if (cvImage.empty()) { QMessageBox::critical(this, "错误", "无法加载图片"); return; } showImage(cvImage); } void MainWindow::showImage(const cv::Mat& image) { QImage qImg(image.data, image.cols, image.rows, image.step, QImage::Format_BGR888); QGraphicsScene* scene = ui->graphicsView->scene(); scene->clear(); imageItem = scene->addPixmap(QPixmap::fromImage(qImg)); ui->graphicsView->setSceneRect(qImg.rect()); } void MainWindow::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton && !cvImage.empty()) { origin = e->pos(); rubberBand = new QGraphicsRectItem; rubberBand->setPen(QPen(Qt::red, 2)); ui->graphicsView->scene()->addItem(rubberBand); } } void MainWindow::mouseMoveEvent(QMouseEvent *e) { if (rubberBand) { QRect rect(origin, e->pos()); rubberBand->setRect(rect.normalized()); ui->statusBar->showMessage( QString("选区: %1×%2").arg(rect.width()).arg(rect.height())); } } void MainWindow::mouseReleaseEvent(QMouseEvent *e) { if (rubberBand) { QRect selected = rubberBand->rect().toRect(); ui->graphicsView->scene()->removeItem(rubberBand); delete rubberBand; rubberBand = nullptr; if (selected.width() > 10 && selected.height() > 10) { processOCR(selected); } } } void MainWindow::processOCR(const QRect& area) { try { // 转换为OpenCV坐标系 cv::Rect roi(area.x(), area.y(), area.width(), area.height()); cv::Mat target = cvImage(roi).clone(); // 图像预处理 cv::cvtColor(target, target, cv::COLOR_BGR2GRAY); cv::threshold(target, target, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); // OCR识别 tesseract::TessBaseAPI tess; tess.Init(NULL, "chi_sim", tesseract::OEM_LSTM_ONLY); // 使用中文训练数据 tess.SetImage(target.data, target.cols, target.rows, 1, target.step); char* text = tess.GetUTF8Text(); ui->textEdit->setPlainText(QString::fromUtf8(text)); delete[] text; } catch (cv::Exception& e) { QMessageBox::critical(this, "错误", QString("OpenCV错误: %1").arg(e.what())); } } // QImage转Mat工具函数 cv::Mat MainWindow::qImageToMat(const QImage& qImage) { return cv::Mat(qImage.height(), qImage.width(), CV_8UC3, const_cast<uchar*>(qImage.bits()), static_cast<size_t>(qImage.bytesPerLine())); } ``` #### 4. 关键配置说明 1. **OpenCV配置** ```cmake find_package(OpenCV REQUIRED) target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS}) ``` 2. **Tesseract配置** ```cmake find_package(Tesseract REQUIRED) target_link_libraries(${PROJECT_NAME} PRIVATE ${Tesseract_LIBRARIES}) ``` 3. **中文语言包** - 下载chi_sim.traineddata - 放置到tessdata目录(需设置环境变量TESSDATA_PREFIX) #### 5. 使用流程 1. 点击菜单"文件->打开"选择图片 2. 按住鼠标左键拖动画出选区 3. 释放鼠标自动显示识别结果 4. 支持功能: - 选区实时显示 - 中英文混合识别 - 自动图像二值化处理 #### 6. 常见问题解决 **问题1:OpenCVQt坐标偏差** ```cpp // 坐标转换修正(考虑视图缩放) QPointF scenePos = ui->graphicsView->mapToScene(e->pos()); QRectF sceneRect = QRectF(originScenePos, scenePos).normalized(); ``` **问题2:OCR识别率低** ```cpp // 增强图像预处理 cv::GaussianBlur(target, target, cv::Size(3,3), 0); cv::resize(target, target, cv::Size(), 2, 2, cv::INTER_CUBIC); // 放大2倍 ``` **问题3:内存泄漏检测** ```bash valgrind --leak-check=full ./OCRApp ``` --- ### **扩展功能建议** 1. **多语言切换** ```cpp // 动态切换语言 tess.Init(NULL, "eng+chi_sim", tesseract::OEM_LSTM_ONLY); ``` 2. **识别结果编辑** ```cpp // 添加结果校对窗口 QDialog* editDialog = new QDialog; QTextEdit* editArea = new QTextEdit(editDialog); ``` 3. **批量处理功能** ```cpp QDirIterator it(inputDir, {"*.jpg","*.png"}, QDir::Files); while (it.hasNext()) { processBatch(it.next()); } ``` --- 该方案实现了从图像选择到OCR识别的完整流程,结合了Qt的优秀交互能力OpenCV的高效图像处理能力,适合需要精确区域识别的应用场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值