AiStudio:PaddleClas 预测部署(四)
基于上篇文章部署三,将详细介绍Python 和 C# 调用Dll传参 实现PaddleClas的预测部署
往下进行前,需要已经完成文章部署三的cmake编译工作
add_executable(${DEMO_NAME} ${SRCS})
改为
ADD_library(${DEMO_NAME} SHARED ${SRCS})
否则会生成exe文件
能够按照文章部署三1.4章节成功编译,并打开:
‘
传输前,需要在编译生成的C++项目中更改main.cpp,(如果忘记如何更改请查看文章部署三):
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <opencv2/core/utils/filesystem.hpp>
#include <ostream>
#include <vector>
#include <cstring>
#include <fstream>
#include <numeric>
#include <include/cls.h>
#include <include/cls_config.h>
using namespace std;
using namespace cv;
using namespace PaddleClas;
static PaddleClas::Classifier *clas; //定义全局对象
extern "C" __declspec(dllexport) int LoadModel(char* cfig); //表示python可以调用该dll
extern "C" __declspec(dllexport) int Infer(char* jpg); //表示python可以调用该dll
int LoadModel(char* cfig) { //加载模型
ClsConfig config(cfig);
config.PrintConfigInfo();
clas = new PaddleClas::Classifier(config.cls_model_path, config.cls_params_path,
config.use_gpu, config.gpu_id, config.gpu_mem,
config.cpu_math_library_num_threads, config.use_mkldnn,
config.use_tensorrt, config.use_fp16,
config.resize_short_size, config.crop_size);
return 0;
}
int Infer(char* jpg) { //预测图片
std::string path(jpg);
std::vector<std::string> img_files_list;
if (cv::utils::fs::isDirectory(path)) {
std::vector<cv::String> filenames;
cv::glob(path, filenames);
for (auto f : filenames) {
img_files_list.push_back(f);
}
}
else {
img_files_list.push_back(path);
}
std::cout << "img_file_list length: " << img_files_list.size() << std::endl;
double elapsed_time = 0.0;
int warmup_iter = img_files_list.size() > 5 ? 5 : 0;
for (int idx = 0; idx < img_files_list.size(); ++idx) {
std::string img_path = img_files_list[idx];
cv::Mat srcimg = cv::imread(img_path, cv::IMREAD_COLOR);
cv::cvtColor(srcimg, srcimg, cv::COLOR_BGR2RGB);
double run_time = clas->Run(srcimg);
if (idx >= warmup_iter) {
elapsed_time += run_time;
std::cout << "Current image path: " << img_path << std::endl;
std::cout << "Current time cost: " << run_time << " s, "
<< "average time cost in all: "
<< elapsed_time / (idx + 1 - warmup_iter) << " s." << std::endl;
}
else {
std::cout << "Current time cost: " << run_time << " s." << std::endl;
}
}
return 0;
}
from ctypes import *
import ctypes
dll=CDLL("G:\\projects\\PaddleClas-release-2.0\\deploy\\cpp_infer\\out\\Release\\clas_system.dll")
config=bytes("G:/projects/PaddleClas-release-2.0/deploy/cpp_infer/tools/config.txt","utf-8")
jpg=bytes('E:/PaddleClas-release-2.0/demo/cat_9.jpg',"utf-8")
LoadModel = dll.LoadModel(config) #加载模型
infer = dll.Infer(jpg) #预测图片
原因在于生成的DLL再调用其他DLL文件,但是该文件DLL没有找到,可以将预测库内paddle_inference_install_dir\paddle\lib\
paddle_fluid.dll 文件复制到 生成DLL的Release目录内:
# model load config
use_gpu 1 #使用gpu
gpu_id 0
gpu_mem 2000 #4000 #gpu内存,根据自己gpu内存来
cpu_math_library_num_threads 10
use_mkldnn 1
use_tensorrt 0
use_fp16 0
# cls config
cls_model_path G:\projects\PaddleClas-release-2.0\output\ResNet50_vd\best_model\mp\inference.pdmodel #inference 模型文件路径
cls_params_path G:\projects\PaddleClas-release-2.0\output\ResNet50_vd\best_model\mp\inference.pdiparams #inference 权重文件路径
resize_short_size 256
crop_size 224
inference文件再部署一四章节中有说明和导出
成功预测(此次使用的模型是再本机训练的,轮数不高只做示例,若提高效果可以尝试使用预训练模型训练后的模型,具体内容请查看PaddleClasGitHub)
C#调用DLL前,需要创建一个控制台应用,如果有问题可以参考部署三2.6章节
关联DLL从目录PaddleClas-release-2.0\deploy\cpp_infer\out\Release
复制到C#项目 ConsoleApp1\bin\Debug\netcoreapp3.1
目录内
using System;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
[DllImport("clas_system.dll", EntryPoint = "LoadModel", CharSet = CharSet.Ansi)]
public static extern void LoadModel(string config);//,string jpg
[DllImport("clas_system.dll", EntryPoint = "Infer", CharSet = CharSet.Ansi)]
public static extern void Infer(string jpg);//,string jpg
static void Main()
{
string config = "G:/projects/PaddleClas-release-2.0/deploy/cpp_infer/tools/config.txt";
string jpg = "E:/PaddleClas-release-2.0/demo/cat_9.jpg";
LoadModel(config);
Infer(jpg);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
预测程序没有设置返回值,预测结果即显示在控制台内,在此基础上我们还可以添加更多便于预测的方法,比如在控制台内输入图片路径,或者一批图片等等,再或者创建窗体(需要修改c++返回值),更多有趣的功能可以自己尝试~