PaddleX模型C++部署後Python調用并讀取dll傳回資料
提示:這裡可以添加系列文章的所有文章的目錄,目錄需要自己手動添加
例如:第一章 Python 機器學習入門之pandas的使用
提示:寫完文章後,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- PaddleX模型C++部署後Python調用并讀取dll傳回資料
- 前言
- 一、預測結果資料類型C++預定義
-
- 1. 四種模型預測結果内容
- 2. C++結果類型預定義
- 二、C++預測代碼
-
- 1.分類C++預測代碼
- 2. 檢測C++預測代碼
- 3. 語義分割C++預測代碼
- 4. 執行個體分割C++預測代碼
- 四、python調用dll
-
- 1. python中定義各模型結果類
- 2. 結果展示
- 總結
前言
上篇文章講了PaddleX的c++部署方式,本篇講如何如何用python調用生成的dll做推理,python讀取dll傳回的預測結果。分類、檢測、語義分割、執行個體分割的dllpython調用本文都會涉及到。
一、預測結果資料類型C++預定義
1. 四種模型預測結果内容
由于檢測、 語義分割、執行個體分割的結果資料類型較複雜,是以除了int和float其他包含結構體或者數組或者清單的結果類型我都打包成了PyObject傳給python。
分類結果:包含一個category, category id和一個score, 分别為str, int和float
檢測結果:所有檢測目标的category,category ID, score以及bboxx的[x,y,h,w]
語義分割結果:label map和score map
執行個體分割結果:所有執行個體的category id、category、score、bbox、mask
2. C++結果類型預定義
在paddlex.h裡定義結構體
分類結果
typedef struct classi {
char* cate;
int cate_id;
float score;
}Classi;
檢測結果都轉為python list, bbox的x, y, h, w拆分為四個list
typedef struct _DETECT {
PyObject* cate;
PyObject* cate_id;
PyObject* score;
PyObject* xmin;
PyObject* ymin;
PyObject* w;
PyObject* h;
} DETECT;
語義分割結果出了label和score之外加入label_size和score_size
typedef struct _SemSeg {
int label_size;
int score_size;
PyObject* label;
PyObject* score;
}SemSeg;
執行個體分割也把bbox結果的x, y, h, w拆成了四個清單,還多加了一個boxes_num也就是執行個體的個數
typedef struct _InsSeg {
PyObject* cate;
PyObject* cate_id;
PyObject* score;
PyObject* xmin;
PyObject* ymin;
PyObject* w;
PyObject* h;
PyObject* InsSegMask;
PyObject* mask_len;
int boxes_num;
} InsSeg;
paddlex.h裡聲明外部函數
二、C++預測代碼
1.分類C++預測代碼
先聲明需要在.cpp裡引入Python.h庫
#include <Python.h>
Classi ClassiImage(int height, int width, uchar* frame_data, char* model_dir_p, int model_dir_len);
Classi ClassiImage(int height,
int width,
uchar* frame_data,
char* model_dir_p,
int model_dir_len) {
int count = 0;
cv::Mat image(height, width, CV_8UC3);
uchar* pxvec = image.ptr<uchar>(0);
for (int row = 0; row < height; row++) {
pxvec = image.ptr<uchar>(row);
for (int col = 0; col < width; col++) {
for (int c = 0; c < 3; c++) {
pxvec[col * 3 + c] = frame_data[count];
count++;
}
}
}
int length = model_dir_len;
char* aa = new char[length];
for (int i = 0; i < length; i++) {
aa[i] = model_dir_p[i * 2];
}
std::string model_dir = aa;
PaddleX::ClsResult result;
std::string key = "";
std::string image_list;
int gpu_id = 0;
bool use_trt = 0;
bool use_gpu = 1;
PaddleX::Model model;
model.Init(model_dir, use_gpu, use_trt, gpu_id, false);
model.predict(image, &result);
Classi ret;
char CATE;
strcpy(&CATE, result.category.c_str());
// ret.cate = NULL;
ret.cate = &CATE;
ret.cate_id = result.category_id;
ret.score = result.score;
return ret;
}
傳入的參數 int height, int width, uchar* frame_data, char* model_dir_p, int model_dir_len分别為預測圖像的高、寬、圖像矩陣位址指針、模型路徑位址指針、模型路徑字元串長度。
下面這段代碼用于還原圖像矩陣,該代碼參考自
添加連結描述
//讀取圖像矩陣
int count = 0;
cv::Mat image(height, width, CV_8UC3);
uchar* pxvec = image.ptr<uchar>(0);
for (int row = 0; row < height; row++) {
pxvec = image.ptr<uchar>(row);
for (int col = 0; col < width; col++) {
for (int c = 0; c < 3; c++) {
pxvec[col * 3 + c] = frame_data[count];
count++;
}
}
}
下面這段代碼用于還原模型路徑字元串
int length = model_dir_len;
char* aa = new char[length];
for (int i = 0; i < length; i++) {
aa[i] = model_dir_p[i * 2];
}
std::string model_dir = aa;
下面這段代碼調用模型預測
PaddleX::ClsResult result;
std::string key = "";
std::string image_list;
int gpu_id = 0;
bool use_trt = 0;
bool use_gpu = 1;
PaddleX::Model model;
model.Init(model_dir, use_gpu, use_trt, gpu_id, false);
model.predict(image, &result);
以上三段代碼分類、檢測、語義分割、執行個體分割都一樣
下面這段代碼是分類結果的傳回,這裡四種模型不一樣。
Classi ret;
char CATE;
strcpy(&CATE, result.category.c_str());
// ret.cate = NULL;
ret.cate = &CATE;
ret.cate_id = result.category_id;
ret.score = result.score;
return ret;
category字元串通過指針位址賦給ret.cate
cate_id和score分貝時int和float類型直接指派即可,最終傳回ret。
2. 檢測C++預測代碼
圖像矩陣的還原,模型路徑的還原還有結果的預測代碼與分類一緻,下面這段傳回的是檢測結果,比分類複雜一些。我們把category, category id, score, bbox的x, y, h, w分别放在不同的清單中,最終傳回所有結果合起來的結構體ret
std::cout << "result mask data size: " << typeid(result.boxes[1].mask.data[0]).name() << std::endl;
DETECT ret;
ret.cate = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.cate, Py_BuildValue("s", result.boxes[i].category));
}
ret.cate_id = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
int cate_id = result.boxes[i].category_id;
PyList_Append(ret.cate_id, Py_BuildValue("i",result.boxes[i].category_id));
}
ret.score = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
//int a = round(result.boxes[i].score * 1000000);
PyList_Append(ret.score, Py_BuildValue("f", result.boxes[i].score));
}
ret.xmin = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.xmin, Py_BuildValue("f", result.boxes[i].coordinate[0]));
}
ret.ymin = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.ymin, Py_BuildValue("f", result.boxes[i].coordinate[1]));
}
ret.w = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.w, Py_BuildValue("f", result.boxes[i].coordinate[2]));
}
ret.h = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.h, Py_BuildValue("f", result.boxes[i].coordinate[3]));
}
return ret;
3. 語義分割C++預測代碼
圖像矩陣的還原,模型路徑的還原還有結果的預測代碼與分類一緻,下面這段傳回的是語義分割結果。我們利用循環從預測結果result中讀取label_map和score_map并寫入清單中,同時也傳回label_size和score_size。
PaddleX::SegResult result;
std::string model_dir = aa;
std::string key = "";
std::string image_list;
int gpu_id = 0;
bool use_trt = 0;
bool use_gpu = 1;
PaddleX::Model model;
model.Init(model_dir, use_gpu, use_trt, gpu_id, false);
model.predict(image, &result);
SemSeg ret;
ret.label_size = result.label_map.data.size();
ret.score_size = result.score_map.data.size();
ret.label = PyList_New(0);
std::cout << "type of ret.label" << typeid(ret.label).name()
<< std::endl;
for (int i = 0; i < result.label_map.data.size(); i++) {
PyList_Append(ret.label, Py_BuildValue("i", result.label_map.data[i]));
}
ret.score = PyList_New(0);
for (int i = 0; i < result.score_map.data.size(); i++) {
int a = round(result.score_map.data[i] * 1000000);
PyList_Append(ret.score, Py_BuildValue("i", a));
}
return ret;
4. 執行個體分割C++預測代碼
圖像矩陣的還原,模型路徑的還原還有結果的預測代碼與分類一緻,下面這段傳回的是執行個體分割的結果。從預測結果的boxes裡的每個bbox循環讀取category, category id, score, bbox的x, y, h, w以及InsSegMask, mask_len和boxes_num分别寫入不同的PyList中。
InsSeg ret;
ret.cate = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.cate, Py_BuildValue("s", result.boxes[i].category));
}
ret.cate_id = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
int cate_id = result.boxes[i].category_id;
PyList_Append(ret.cate_id, Py_BuildValue("i", result.boxes[i].category_id));
}
ret.score = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
// int a = round(result.boxes[i].score * 1000000);
PyList_Append(ret.score, Py_BuildValue("f", result.boxes[i].score));
}
ret.xmin = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.xmin, Py_BuildValue("f", result.boxes[i].coordinate[0]));
}
ret.ymin = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.ymin, Py_BuildValue("f", result.boxes[i].coordinate[1]));
}
ret.w = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.w, Py_BuildValue("f", result.boxes[i].coordinate[2]));
}
ret.h = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.h, Py_BuildValue("f", result.boxes[i].coordinate[3]));
}
ret.InsSegMask = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
for (int j = 0; j < result.boxes[i].mask.data.size(); j++) {
PyList_Append(ret.InsSegMask, Py_BuildValue("i",
result.boxes[i].mask.data[j]));
//std::cout << result.boxes[j].mask.data[j] << std::endl;
}
}
ret.mask_len = PyList_New(0);
for (int i = 0; i < result.boxes.size(); i++) {
PyList_Append(ret.mask_len, Py_BuildValue("i", result.boxes[i].mask.data.size()));
}
ret.boxes_num = result.boxes.size();
return ret;
四、python調用dll
1. python中定義各模型結果類
class InsSegResult(Structure):
_fields_ = [
("cate", py_object),
("cate_id", py_object),
("score", py_object),
("xmin", py_object),
("ymin", py_object),
("w", py_object),
("h", py_object),
("InsSegMask", py_object),
("mask_len", py_object),
("boxes_num", c_int)
]
class ClassiResult(Structure):
_fields_ = [
("cate", c_wchar_p),
("cate_id", c_int),
("score", c_float)
]
class SemSegResult(Structure):
_fields_ = [
("label_size", c_int),
("score_size", c_int),
("label", py_object),
("score", py_object)
]
class DetResult(Structure):
_fields_ = [
("cate", py_object),
("cate_id", py_object),
("score", py_object),
("xmin", py_object),
("ymin", py_object),
("w", py_object),
("h", py_object)
]
2. 結果展示
下圖是我用python調用dll推理出的語義分割模型結果,模型為UNet,python讀取dll傳回的結果成功
下面展示部分UNet畫出的結果
總結
提示:這裡對文章進行總結:
例如:以上就是今天要講的内容,本文僅僅簡單介紹了pandas的使用,而pandas提供了大量能使我們快速便捷地處理資料的函數和方法。