1、下载PaddleOCR源码:https://github.com/PaddlePaddle/PaddleOCR.git
2、下载推理模型
3、下载PaddleOCR 的Windows预测库,官网上有可以直接下载:下载安装Linux预测库 — Paddle-Inference documentation (paddlepaddle.org.cn)
4、解压PaddleOCR源码;
5、打开visual studio 2019 选继续但无需代码,打开Cmake文件;
6、打开config.cpp 将char strs[str.length() + 1];改为 char* strs = new char[str.length() + 1];
将 char d[delim.length() + 1]; 改为char* d = new char[delim.length() + 1];
7、按照Windows_2019_build.md配置好相关的库,主要是设置路径。
接下来是重点了:
8、在cmakelist中添加如下所示的三行代码:
9、编写自己的接口头文件header.h,并放入include中,可以参照如下样例:
/*
#pragma once
#ifndef _CVI_RE_
#define _CVI_RE_
#ifdef CVI_EXPORTS
#define CVI_API __declspec(dllexport)
#else
#define CVI_API __declspec(dllimport)
#endif
*/
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
struct OCRTextRect {
public:
char* OCRText; //识别的信息
int ptx, pty; //Rect的起始坐标
int width, height; //Rect的宽和高
OCRTextRect() : OCRText(""), ptx(0), pty(0), width(0), height(0)
{
}
};
#define DLLEXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C" {
#endif
//DLLEXPORT char* PaddleOCRText(cv::Mat& img);
//DLLEXPORT int PaddleOCRTextRect(cv::Mat& , OCRTextRect*);
DLLEXPORT int Initial_Model();
DLLEXPORT int PaddleOCRDetectionRect(cv::Mat& img, OCRTextRect* resptr);
#ifdef __cplusplus
}
#endif
10 编写自己的函数实现文件,放入src中,代码可以参考如下:
#include <include/header.h>
#include <include/ocr_det.h>
#include <include/ocr_rec.h>
#include <include/config.h>
#include <iostream>
#include <direct.h>
#include <stdio.h>
#include <codecvt>
#define LOCK_MODEL() std::unique_lock<std::recursive_mutex> locker(g_lockModel);
std::recursive_mutex g_lockModel;
//std::shared_ptr<PaddleOCR::DBDetector> detcvi(std::make_shared<PaddleOCR::DBDetector>());
std::shared_ptr<PaddleOCR::DBDetector> detcvi=nullptr;
//PaddleOCR::DBDetector det;
//PaddleOCR::CRNNRecognizer rec;
//std::shared_ptr<PaddleOCR::CRNNRecognizer> reccvi(std::make_shared<PaddleOCR::CRNNRecognizer>());
std::shared_ptr<PaddleOCR::CRNNRecognizer> reccvi;
/*
DLLEXPORT char* PaddleOCRText(cv::Mat& img)
{
std::vector<std::pair<std::string,cv::Rect>> str_res;
std::string tmpstr;
if (!img.data) {
return "could not read Mat ";
}
PaddleOCR::OCRConfig config = readOCRConfig();
//打印config参数
config.PrintConfigInfo();
//图像检测文本
PaddleOCR::DBDetector det(config.det_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.max_side_len, config.det_db_thresh,
config.det_db_box_thresh, config.det_db_unclip_ratio,
config.use_polygon_score, config.visualize,
config.use_tensorrt, config.use_fp16);
PaddleOCR::Classifier* cls = nullptr;
if (config.use_angle_cls == true) {
cls = new PaddleOCR::Classifier(config.cls_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.cls_thresh,
config.use_tensorrt, config.use_fp16);
}
PaddleOCR::CRNNRecognizer rec(config.rec_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.char_list_file,
config.use_tensorrt, config.use_fp16);
//检测文本框
std::vector<std::vector<std::vector<int>>> boxes;
det.Run(img, boxes);
//OCR识别
str_res = rec.RunOCR(boxes, img, cls);
for (auto item : str_res) {
tmpstr += item.first + ":" + std::to_string(item.second.x) +
"," + std::to_string(item.second.y) + "," + std::to_string(item.second.width)
+ "," + std::to_string(item.second.height) + "#";
}
char* reschar = new char[tmpstr.length() + 1];
tmpstr.copy(reschar, std::string::npos);
return reschar;
}
DLLEXPORT int PaddleOCRTextRect(cv::Mat& img, OCRTextRect* resptr)
{
std::vector<std::pair<std::string, cv::Rect>> str_res;
std::string tmpstr;
if (!img.data) {
return 0;
}
PaddleOCR::OCRConfig config = readOCRConfig();
//打印config参数
config.PrintConfigInfo();
//图像检测文本
PaddleOCR::DBDetector det(config.det_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.max_side_len, config.det_db_thresh,
config.det_db_box_thresh, config.det_db_unclip_ratio,
config.use_polygon_score, config.visualize,
config.use_tensorrt, config.use_fp16);
PaddleOCR::Classifier* cls = nullptr;
/*if (config.use_angle_cls == true) {
cls = new PaddleOCR::Classifier(config.cls_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.cls_thresh,
config.use_tensorrt, config.use_fp16);
}*/
/*
PaddleOCR::CRNNRecognizer rec(config.rec_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.char_list_file,
config.use_tensorrt, config.use_fp16);
//检测文本框
std::vector<std::vector<std::vector<int>>> boxes;
det.Run(img, boxes);
//OCR识别
str_res = rec.RunOCR(boxes, img, cls);
try
{
for (int i = 0; i < str_res.size(); ++i) {
char* reschar = new char[str_res[i].first.length() + 1];
str_res[i].first.copy(reschar, std::string::npos);
resptr[i].OCRText = reschar;
resptr[i].ptx = str_res[i].second.x;
resptr[i].pty = str_res[i].second.y;
resptr[i].width = str_res[i].second.width;
resptr[i].height = str_res[i].second.height;
//std::cout << "cout:" << str_res[i].first << std::endl;
}
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
return str_res.size();
}
*/
PaddleOCR::OCRConfig readOCRConfig()
{
保证config.txt从本DLL目录位置读取
//获取DLL自身所在路径(此处包括DLL文件名)
char DllPath[_MAX_PATH] = { 0 };
getcwd(DllPath, _MAX_PATH);
std::cout << DllPath << std::endl;
strcat(DllPath, "\\config.txt");
std::cout << DllPath << std::endl;
截取DLL所在目录(去掉DLL文件名)
//char drive[_MAX_DRIVE];
//char dir[_MAX_DIR];
//char fname[_MAX_FNAME];
//char ext[_MAX_EXT];
//_splitpath(DllPath, drive, dir, fname, ext);
字符串拼接
//strcat(dir, "config.txt");
return PaddleOCR::OCRConfig(DllPath);
}
DLLEXPORT int Initial_Model()
{
PaddleOCR::OCRConfig config = readOCRConfig();
//打印config参数
config.PrintConfigInfo();
//图像检测文本
std::shared_ptr<PaddleOCR::DBDetector> det = std::make_shared<PaddleOCR::DBDetector>(config.det_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.max_side_len, config.det_db_thresh,
config.det_db_box_thresh, config.det_db_unclip_ratio,
config.use_polygon_score, config.visualize,
config.use_tensorrt, config.use_fp16);
//PaddleOCR::DBDetector det_init(config.det_model_dir, config.use_gpu, config.gpu_id,
//config.gpu_mem, config.cpu_math_library_num_threads,
//config.use_mkldnn, config.max_side_len, config.det_db_thresh,
//config.det_db_box_thresh, config.det_db_unclip_ratio,
//config.use_polygon_score, config.visualize,
//config.use_tensorrt, config.use_fp16);
std::shared_ptr<PaddleOCR::CRNNRecognizer> rec = std::make_shared<PaddleOCR::CRNNRecognizer>(config.rec_model_dir, config.use_gpu, config.gpu_id,
config.gpu_mem, config.cpu_math_library_num_threads,
config.use_mkldnn, config.char_list_file,
config.use_tensorrt, config.use_fp16);
//PaddleOCR::CRNNRecognizer rec_init(config.rec_model_dir, config.use_gpu, config.gpu_id,
//config.gpu_mem, config.cpu_math_library_num_threads,
//config.use_mkldnn, config.char_list_file,
//config.use_tensorrt, config.use_fp16);
//PaddleOCR::CRNNRecognizer rec_init(config.rec_model_dir, config.use_gpu, config.gpu_id,
//config.gpu_mem, config.cpu_math_library_num_threads,
//config.use_mkldnn, config.char_list_file,
//config.use_tensorrt, config.use_fp16);
//det = det_init;
//rec = rec_init;
detcvi = det;
reccvi = rec;
if (detcvi == NULL || reccvi == NULL) {
cout << "模型初始化失败!" << endl;
return -1;
}
return 0;
}
DLLEXPORT int PaddleOCRDetectionRect(cv::Mat& img, OCRTextRect* resptr)
{
//检测文本框
std::vector<std::pair<std::string, cv::Rect>> str_res;
std::vector<std::vector<std::vector<int>>> boxes;
if (detcvi == NULL)
{
cout << "det model initialize failed" << endl;
return -1;
}
detcvi->Run(img, boxes);
/*for (int i = 0; i < boxes.size(); i++) { //对生成的检测框进行扩展,上下左右各扩展5个像素
int x1 = boxes[i][0][0] - 0;
int y1 = boxes[i][0][1] - 0;
int x2 = boxes[i][3][0] + 0;
int y2 = boxes[i][3][1] + 0;
if (x1 < 0) { //判断扩展后是否越界
x1 = 0;
}
if (y1 < 0) {
y1 = 0;
}
if (x2 > img.cols) {
x2 = img.cols;
}
if (y2 < img.rows) {
y2 = img.rows;
}
boxes[i][0][0] = x1;
boxes[i][0][1] = y1;
boxes[i][1][0] = x2;
boxes[i][1][1] = y1;
boxes[i][2][0] = x1;
boxes[i][2][1] = y2;
boxes[i][3][0] = x2;
boxes[i][3][1] = y2;
}*/
//OCR识别
PaddleOCR::Classifier* cls = nullptr;
if (reccvi == NULL)
{
cout << "rec model initialize failed" << endl;
return -1;
}
str_res = reccvi->RunOCR(boxes, img, cls);
try
{
for (int i = 0; i < str_res.size(); ++i) {
char* reschar = new char[str_res[i].first.length() + 1];
str_res[i].first.copy(reschar, std::string::npos);
resptr[i].OCRText = reschar;
resptr[i].ptx = str_res[i].second.x;
resptr[i].pty = str_res[i].second.y;
resptr[i].width = str_res[i].second.width;
resptr[i].height = str_res[i].second.height;
//std::cout << "cout:" << str_res[i].first << std::endl;
}
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
return str_res.size();
}
11、按照正常步骤保存并生成,就可以得到自己的dll。
12、分别调用初始化函数、和识别函数就能实现文字识别功能。