openvino2023部署yolov8模型(解析部署)c++版本
前言
记得最开始尝试部署的时候直接进行了ai,拿着ai的代码就去跑,结果失败了,又去网上找了很久,都没有成功,直到看见了一篇gitee代码,拿上我就用,最后也是成功了。最离谱的是我换了一个模型(只是再训练了一次),不知道是不是中间哪里不一样,代码再次跑不通,痛定思痛决定还是搞懂为什么,最后再次跑通,发现跟之前b站学的理论对应上了,以此记录。
加载模型
这部分ai的还是对的,所以就不解释了。
cv::Mat CameraHandler::letterbox(const cv::Mat& source)
{
int col = source.cols;
int row = source.rows;
int _max = MAX(col, row);
cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC4);
source.copyTo(result(cv::Rect(0, 0, col, row)));
return result;
}
ov::Core core;
std::string modelPath=//路径
// Step 3: 编译模型到特定的设备,例如 "CPU"
ov::CompiledModel compiled_model = core.compile_model(modelPath, "CPU");
// Step 4: 创建推理请求
ov::InferRequest infer_request = compiled_model.create_infer_request();
cv::Mat letterbox_img = letterbox(frame);
float scale = letterbox_img.size[0] / 640.0;
cv::Mat blob = cv::dnn::blobFromImage(letterbox_img, 1.0 / 255.0, cv::Size(640, 640), cv::Scalar(), true);
// -------- Step 5. Feed the blob into the input node of the Model -------
// Get input port for model with one input
auto input_port = compiled_model.input();
// Create tensor from external memory
ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), blob.ptr(0));
// Set input tensor for model with one input
infer_request.set_input_tensor(input_tensor);
// -------- Step 6. Start inference --------
infer_request.infer();
// Step 10: 获取推理结果
ov::Tensor output_tensor = infer_request.get_output_tensor(0);
最后拿到output_tensor就是模型得到的东西,这部分代码只要跑通不报错,基本就没什么问题。
std::vector<Trash> detections;
//拿到内容
float* output_data=output_tensor.data<float>();
//形状
ov::Shape output_shape=output_tensor.get_shape();//(1,9,8400)
cv::Mat output_buffer(output_shape[1], output_shape[2], CV_32F, output_data);
transpose(output_buffer, output_buffer); //[8400,9]
//9是四个位置信息,五个类别
std::vector<int> class_ids;
std::vector<float> class_scores;
std::vector<cv::Rect> boxes;
// Figure out the bbox, class_id and class_score
for (int i = 0; i < output_buffer.rows; i++) {
cv::Mat classes_scores = output_buffer.row(i).colRange(4, 9);//取后5个数
cv::Point class_id;
double maxClassScore;
minMaxLoc(classes_scores, 0, &maxClassScore, 0, &class_id);
// std::cout<<maxClassScore<<std::endl;
if (maxClassScore > confidence_threshold) {
class_scores.push_back(maxClassScore);
class_ids.push_back(class_id.x);
float cx = output_buffer.at<float>(i, 0);
float cy = output_buffer.at<float>(i, 1);
float w = output_buffer.at<float>(i, 2);
float h = output_buffer.at<float>(i, 3);
int left = int((cx - 0.5 * w) * scale);
int top = int((cy - 0.5 * h) * scale);
int width = int(w * scale);
int height = int(h * scale);
boxes.push_back(cv::Rect(left, top, width, height));
}
}
//非极大值抑制
std::vector<int> indices;
float nms_threshold = 0.8;
cv::dnn::NMSBoxes(boxes, class_scores, confidence_threshold, nms_threshold, indices);
// -------- Visualize the detection results -----------
for (size_t i = 0; i < indices.size(); i++) {
Trash detection;
int index = indices[i];
int class_id = class_ids[index];
float confidence=class_scores[index];
detection.class_id = static_cast<int>(class_id);
detection.confidence = confidence;
detection.x_min = boxes[index].x;
detection.y_min = boxes[index].y;
detection.x_max = boxes[index].x+boxes[index].width;
detection.y_max = boxes[index].y+boxes[index].height;
detections.push_back(detection);
}
解析部分如上,最后将得到的detections就是我们需要的东西,由于我的代码是放在类的一个函数里面的,直接跑肯定是跑不通的。
解析
std::vector<Trash> detections;
//拿到内容
float* output_data=output_tensor.data<float>();
//形状
ov::Shape output_shape=output_tensor.get_shape();//(1,9,8400)
cv::Mat output_buffer(output_shape[1], output_shape[2], CV_32F, output_data);
transpose(output_buffer, output_buffer); //[8400,9]
output_data是将模型输出的东西转变成float类型,output_shape是我模型的形状,得到的是(1,9,8400),1是batch数,我推理一张图片,所以肯定是1。9是推理的结果,前四个是位置信息,我的任务是5分类,所以后面5个数是对应每个类别的可能性。8400是识别的个数,这个是模型自己规定的,具体原因可以自行查找,网上有很多讲解。
将output_data放进output_buffer,并且将9和8400逆置。
//9是四个位置信息,五个类别
std::vector<int> class_ids;
std::vector<float> class_scores;
std::vector<cv::Rect> boxes;
// Figure out the bbox, class_id and class_score
for (int i = 0; i < output_buffer.rows; i++) {
cv::Mat classes_scores = output_buffer.row(i).colRange(4, 9);//取后5个数
cv::Point class_id;
double maxClassScore;
minMaxLoc(classes_scores, 0, &maxClassScore, 0, &class_id);
// std::cout<<maxClassScore<<std::endl;
if (maxClassScore > confidence_threshold) {
class_scores.push_back(maxClassScore);
class_ids.push_back(class_id.x);
float cx = output_buffer.at<float>(i, 0);
float cy = output_buffer.at<float>(i, 1);
float w = output_buffer.at<float>(i, 2);
float h = output_buffer.at<float>(i, 3);
int left = int((cx - 0.5 * w) * scale);
int top = int((cy - 0.5 * h) * scale);
int width = int(w * scale);
int height = int(h * scale);
boxes.push_back(cv::Rect(left, top, width, height));
}
}
for循环8400每个结果,classes_scores将每个类别对应的分数取出,minMaxLoc是对比每个类别的可能性得到可能性最大的,并且将对应的位置存进class_id里面。
判断最大可能性的值是否大于置信度(自己规定的),大于就是我们需要的结果,将置信度和类别以及位置分别存入数组。
//非极大值抑制
std::vector<int> indices;
float nms_threshold = 0.8;
cv::dnn::NMSBoxes(boxes, class_scores, confidence_threshold, nms_threshold, indices);
再采用非极大值抑制,如果两个框交叉的UOI大于你规定的nms_threshold,那么就会抑制掉置信度小的。
// -------- Visualize the detection results -----------
for (size_t i = 0; i < indices.size(); i++) {
Trash detection;
int index = indices[i];
int class_id = class_ids[index];
float confidence=class_scores[index];
detection.class_id = static_cast<int>(class_id);
detection.confidence = confidence;
detection.x_min = boxes[index].x;
detection.y_min = boxes[index].y;
detection.x_max = boxes[index].x+boxes[index].width;
detection.y_max = boxes[index].y+boxes[index].height;
detections.push_back(detection);
}
将最后的结果存入detections里面。
总结
部署代码倒是挺多,就是c++版本的比较少,能力有限,有误麻烦指出,谢谢。
更多推荐
所有评论(0)