当前位置: 首页 > news >正文

在Qt中使用PaddleOCR进行文本识别

文章目录

  • 1.下载资源
    • 1.1.PaddlePaddle推理库
    • 1.2.PaddleOCR SDK
    • 1.3.PaddleOCR模型
  • 2.使用
  • 3.结果
  • Qt中字符串相似度计算(Levenshtein距离)

目前(20250819),最新的 PaddleOCR是V3.1.1
在这里插入图片描述

1.下载资源

假如我们想在Qt中调用PaddleOCR来进行字符识别,需要准备三样东西:

1.1.PaddlePaddle推理库

【下载安装 Windows 推理库】
目前windows下貌似只有CPU版本,也行,先用着。
在这里插入图片描述
因为PaddleOCR也是基于PaddlePaddle这个深度学习架构开发出来的东西,要运行其模型,必须要用其推理引擎。

1.2.PaddleOCR SDK

虽然我们使用的PaddleOCR是基于PaddlePaddle,但是也有很多预处理、后处理的操作,因此,还需要下载PaddleOCR的SDK来简化操作。
我们可以到【官方仓库】中,下载PaddleOCR/deploy/cpp_infer/,这里面的源码,就是我们要用到的SDK
在这里插入图片描述

1.3.PaddleOCR模型

模型到PaddleOCR模型库下载
【通用OCR产线使用教程】
在这里插入图片描述

展开上图所示的页面便可以按照你自己的需求下载相应版本的模型文件。
在 PaddleOCR 中,Classifier、DBDetector 和 CRNNRecognizer 这三个处理器(或模型)分别承担了光学字符识别流程中不同阶段的关键任务。
目前需要用到文本检测(文字在哪里)、文本识别(文文字是什么)这两个模型;Classifier是用来进行文字方向判断的,暂时不知道模型在哪里下载以及怎么用,先不管。
我直接下载最新V5版本的推理模型
在这里插入图片描述

2.使用

使用PaddleOCR SDK时,需要将cpp_infer文件夹拷贝到我们的工程目录中,然后将其中除了include、src这两个文件夹外的其他东西删除,然后将文件夹重命名为ocr(叫其他名也可以)
在这里插入图片描述
最后,将文件加到工程中。(有部分文件因为没用到,我没有将他们加进来)
在这里插入图片描述
屏蔽掉utility.h utility.cpp中的函数GetAllFiles,因为这个函数对unix是强依赖
在这里插入图片描述

修改pro文件
其中路径按照你实际的路径修改


# opencv
INCLUDEPATH += D:/Qt/opencv4.4.0/include
INCLUDEPATH += D:/Qt/opencv4.4.0/include/opencv2
CONFIG(release, debug|release){
LIBS += -LD:/Qt/opencv4.4.0/x64/vc15/lib -lopencv_world440
LIBS += -LD:/Qt/opencv4.4.0/x64/vc15/bin
}
else{
LIBS += -LD:/Qt/opencv4.4.0/x64/vc15/lib -lopencv_world440d
LIBS += -LD:/Qt/opencv4.4.0/x64/vc15/bin
}# paddlePaddle
PADDLEDIR = D:/Qt/paddleOCR/paddle_inference
INCLUDEPATH += $$PADDLEDIR/paddle/include
LIBS += -L$$PADDLEDIR/paddle/lib\
-lcommon -lpaddle_inference -llibpaddle_inference
LIBS += -L$$PADDLEDIR/third_party/install/onednn/lib
LIBS += -L$$PADDLEDIR/third_party/install/mklml/lib
# 下载下来的paddlePaddle中的第三方库是静态库,用的话会报错,
# 所以要自己用vcpkg来安装必要的库
INCLUDEPATH += D:\Qt\vcpkg\vcpkg\packages\yaml-cpp_x64-windows\include
LIBS += -LD:\Qt\vcpkg\vcpkg\packages\yaml-cpp_x64-windows\lib -lyaml-cpp
LIBS += -LD:\Qt\vcpkg\vcpkg\packages\yaml-cpp_x64-windows\bin# ocr
INCLUDEPATH += $$PWD/ocr

这里直接给出一段直接运行的代码,假如想要更好的体验,还是得封装一下的。

#include "ocr/include/ocr_det.h"
#include "ocr/include/ocr_rec.h"
#include "ocr/include/utility.h"using namespace cv;
void ocrTest()
{cv::Mat img = cv::imread("../general_ocr_002.png");img = img(cv::Rect(0, 0, 200, 200));imshow("the img", img);std::string model_dir = "D:/Qt/paddleOCR/model/PP-OCRv5_server_det_infer";bool        use_gpu = false;int         gpu_id  = 0;int         gpu_mem = 4000;int         cpu_math_library_num_threads = 4;bool        use_mkldnn = false;std::string limit_type = "max";int         limit_side_len      = 960;double      det_db_thresh       = 0.3;double      det_db_box_thresh   = 0.5;double      det_db_unclip_ratio = 2.0;std::string det_db_score_mode   = "slow";bool        use_dilation = false;bool        use_tensorrt = false;std::string precision    = "fp32";PaddleOCR::DBDetector detector(model_dir,use_gpu,gpu_id,gpu_mem,cpu_math_library_num_threads,use_mkldnn,limit_type,limit_side_len,det_db_thresh,det_db_box_thresh,det_db_unclip_ratio,det_db_score_mode,use_dilation,use_tensorrt,precision);std::vector<PaddleOCR::OCRPredictResult> ocr_results;std::vector<std::vector<std::vector<int>>> boxes;std::vector<double> times;detector.Run(img, boxes, times);qDebug() << boxes.size() << times.size();for (size_t i = 0; i < boxes.size(); ++i) {PaddleOCR::OCRPredictResult res;res.box = std::move(boxes[i]);ocr_results.emplace_back(std::move(res));}// sort boex from top to bottom, from left to rightPaddleOCR::Utility::sort_boxes(ocr_results);// 按照区域裁切图片// crop imagestd::vector<cv::Mat> img_list;for (size_t j = 0; j < ocr_results.size(); ++j) {cv::Mat crop_img = PaddleOCR::Utility::GetRotateCropImage(img, ocr_results[j].box);img_list.emplace_back(std::move(crop_img));}for (int i = 0; i < img_list.size(); ++i) {imshow(QString::number(i).toStdString(), img_list[i]);}std::vector<std::string> rec_texts(img_list.size(), std::string());std::vector<float> rec_text_scores(img_list.size(), 0);model_dir = "D:/Qt/paddleOCR/model/PP-OCRv5_server_rec_infer";std::string label_path = "../../ppocr/utils/ppocr_keys_v1.txt"; // 不需要存在这个文件,这样写就行;具体查看官方源码int         rec_batch_num = 6;int         rec_img_h = 32;int         rec_img_w = 320;PaddleOCR::CRNNRecognizer recognizer(model_dir,use_gpu,gpu_id,gpu_mem,cpu_math_library_num_threads,use_mkldnn,label_path,use_tensorrt,precision,rec_batch_num,rec_img_h,rec_img_w);recognizer.Run(img_list, rec_texts, rec_text_scores, times);for (int i = 0; i < rec_texts.size(); ++i) {qDebug() << rec_texts.at(i).c_str() << rec_text_scores.at(i);}
}

3.结果

在这里插入图片描述
感觉结果还行,但是耗时需要比较久。可能我用的是server模型的问题,切换mobile模型试试。

Qt中字符串相似度计算(Levenshtein距离)

目前的项目要求在检测出字符串后,计算一下检测出的字符串与目标字符串的相似度,这里提供一个基于Levenshtein距离计算相似度的函数。实测效果有那么点意思。

int levenshteinDistance(const QString &s1, const QString &s2) {// 步骤1: 获取字符串长度const int len1 = s1.size();const int len2 = s2.size();// 步骤2: 创建二维DP表 (len1+1 行, len2+1 列)QVector<QVector<int>> dp(len1 + 1, QVector<int>(len2 + 1, 0));// 步骤3: 初始化边界条件// 第一列:s1[0..i] 变成空字符串需要 i 次删除for (int i = 0; i <= len1; ++i) dp[i][0] = i;// 第一行:空字符串变成 s2[0..j] 需要 j 次插入for (int j = 0; j <= len2; ++j) dp[0][j] = j;// 步骤4: 填充DP表for (int i = 1; i <= len1; ++i) {for (int j = 1; j <= len2; ++j) {// 计算替换成本int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;// 状态转移方程:取三种操作的最小值dp[i][j] = std::min({dp[i - 1][j] + 1,     // 删除操作dp[i][j - 1] + 1,     // 插入操作dp[i - 1][j - 1] + cost // 替换操作});}}// 步骤5: 返回最终结果return dp[len1][len2]; // 右下角的值即为编辑距离
}// 计算相似度百分比(0~100)
double calculateSimilarity(const QString &s1, const QString &s2) {int maxLen = std::max(s1.length(), s2.length());if (maxLen == 0) return 100.0; // 空字符串视为相同int distance = levenshteinDistance(s1, s2);return (1.0 - static_cast<double>(distance) / maxLen) * 100.0;
}
http://www.lryc.cn/news/625302.html

相关文章:

  • ubuntu24.04 用apt安装的mysql修改存储路径(文件夹、目录)
  • Vue2+Vue3前端开发_Day1
  • 当宠物机器人装上「第六感」:Deepoc 具身智能如何重构宠物机器人照看逻辑
  • Ubuntu22.04安装docker最新教程,包含安装自动脚本
  • 雷卯针对香橙派Orange Pi 3 LTS开发板防雷防静电方案
  • 在 Windows 上使用 Kind 创建本地 Kubernetes 集群并集成Traefik 进行负载均衡
  • Linux下Nginx安装及负载均衡配置
  • pytest高级用法之插件开发
  • Docker核心---数据卷(堵门秘籍)
  • RxJava 在 Android 即时通讯中的应用:封装、处理与控制
  • OpenHarmony之打造全场景智联基座的“分布式星链 ”WLAN子系统
  • (第五篇)spring cloud之Ribbon负载均衡
  • C语言实战:从零开始编写一个通用配置文件解析器
  • 常见的 Bash 命令及简单脚本
  • 量子计算和超级计算机将彻底改变技术
  • 记录Webapi Excel 导出
  • 【qml-4】qml与c++交互(类型多例)
  • 【CPP】一个CPP的Library(libXXXcore)和测试程序XXX_main的Demo
  • kkfileview预览Excel文件去掉左上角的跳转HTM预览、打印按钮
  • Spring Boot 全局异常处理
  • JVM参数优化
  • 《算法导论》第 29 章 - 线性规划
  • Matplotlib数据可视化实战:Matplotlib子图布局与管理入门
  • Day10--滑动窗口与双指针--2875. 无限数组的最短子数组,76. 最小覆盖子串,632. 最小区间
  • Hugging Face 核心组件介绍
  • 【牛客刷题】岛屿数量问题:BFS与DFS解法深度解析
  • Git的初步学习
  • 系统架构设计师-操作系统-避免死锁最小资源数原理模拟题
  • git 创用操作
  • [系统架构设计师]云原生架构设计理论与实践(十四)