本文章记录,如何将PaddleOCR应用到window下的C++项目中,实现利用摄像头实时显示输出,上述即为实际的检测效果。看得出来,对不同大小语言文字检测性能都还不错。
主要过程包括:①PaddleOCR的编译,②VS2019的属性配置,③cpp文件修改用来显示图像
官方给出在VS中cmake,https://gitee.com/paddlepaddle/PaddleOCR/blob/release/2.0/deploy/cpp_infer/docs/windows_vs2019_build.md
本文采用cmake-gui中进行编译。
①PaddleOCR源码:https://github.com/PaddlePaddle/PaddleOCR
②PaddlePaddle C++ 预测库 fluid_inference:https://www.paddlepaddle.org.cn/documentation/docs/en/guides/05_inference_deployment/inference/windows_cpp_inference_en.html
③OpenCV,用于读图、画图等操作
配置好cmake选项,congfigure,generate。
新建VS2019项目,将PaddleOCR源文件和头文件(见下图)全部添加到项目中。并配置项目属性。
2.2.1 加载OCR预测模型
下载链接https://github.com/PaddlePaddle/PaddleOCR,此处用的是mobile形式的。
config.txt将作为项目main.cpp的输入参数,务必将文件中的模型文件路径填写正确。
2 main.cpp修改
修改部分见代码,主要包括输入参数、摄像头取帧、识别文字标记边界。
int main()
{
OCRConfig config("D:/E/z_pp/config.txt");
config.PrintConfigInfo();
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.visualize, config.use_tensorrt, config.use_fp16);
Classifier* cls = nullptr;
if (config.use_angle_cls == true) {
cls = new 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);
}
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);
cv::Mat srcimg;
VideoCapture capture;
capture.open(0, CAP_DSHOW);
while (capture.read(srcimg))
{
//auto start = std::chrono::system_clock::now();
std::vector>> boxes; //vector: [][0](x1,y1), [][1](x2,y1), [][2](x2,y2),[][3](x1,y2), 顺时针四个角
det.Run(srcimg, boxes);
rec.Run(boxes, srcimg, cls);
//auto end = std::chrono::system_clock::now();
//auto duration = std::chrono::duration_cast(end - start);
//std::cout << "Cost "
// << double(duration.count()) *
// std::chrono::microseconds::period::num /
// std::chrono::microseconds::period::den
// << "s" << std::endl;
for (int i = 0; i < boxes.size(); i++)
{
printf("%d %d %d %d\n", boxes[i][0][0], boxes[i][0][1], boxes[i][2][0], boxes[i][2][1]);
line(srcimg, Point(boxes[i][0][0], boxes[i][0][1]), Point(boxes[i][1][0], boxes[i][1][1]), Scalar(0, 255, 0), 3);
line(srcimg, Point(boxes[i][1][0], boxes[i][1][1]), Point(boxes[i][2][0], boxes[i][2][1]), Scalar(0, 255, 0), 3);
line(srcimg, Point(boxes[i][2][0], boxes[i][2][1]), Point(boxes[i][3][0], boxes[i][3][1]), Scalar(0, 255, 0), 3);
line(srcimg, Point(boxes[i][3][0], boxes[i][3][1]), Point(boxes[i][0][0], boxes[i][0][1]), Scalar(0, 255, 0), 3);
}
cv::imshow("PaddleOCR", srcimg);
char ch = waitKey(1); if (ch == 27)break;
}
return 0;
}
系列之(一)