当前位置:网站首页>【yolov5s目标检测】opencv加载onnx模型在GPU上进行推理
【yolov5s目标检测】opencv加载onnx模型在GPU上进行推理
2022-06-21 11:13:00 【十年一梦实验室】

推理截图
推理测试
源码:
main主程序:
#include "yolo.h"
#include <iostream>
#include<opencv2//opencv.hpp>
#include<math.h>
using namespace std;
using namespace cv;
using namespace dnn;
int main()
{
string model_path = "yolov5sGPU.onnx";//CPU可用 release GPU
Yolo test;
Net net;
if (test.readModel(net, model_path, true))//false: CPU true:GPU
{
cout << "read net ok!" << endl;
}
else {
return -1;
}
bool vedio = true;
if (vedio)
{
// 用 OpenCV 打开摄像头读取文件(你随便咋样获取图片都OK哪)
cv::VideoCapture cap = cv::VideoCapture("test2.mp4");
// 设置宽高 无所谓多宽多高后面都会通过一个算法转换为固定宽高的
// 固定宽高值应该是你通过YoloV5训练得到的模型所需要的
// 传入方式是构造 YoloV5 对象时传入 width 默认值为 640,height 默认值为 640
//cap.set(cv::CAP_PROP_FRAME_WIDTH, 1000);
//cap.set(cv::CAP_PROP_FRAME_HEIGHT, 800);
cv::Mat frame;
//生成随机颜色//
vector<Scalar> color;
srand(time(0));
for (int i = 0; i < 80; i++) {//80种类
int b = rand() % 256;
int g = rand() % 256;
int r = rand() % 256;
color.push_back(Scalar(b, g, r));
}
//color.push_back(Scalar(0, 0, 255));
while (cap.isOpened())
{
// 读取一帧
cap.read(frame);
if (frame.empty())
{
std::cout << "Read frame failed! or The End!" << std::endl;
break;
}
vector<Output> result;
if (test.Detect(frame, net, result))//返回true 检测到对象//
{
test.drawPred(frame, result, color);
}
else {
cout << "Detect Failed!" << endl;// CPU模式 有很多识别不到。GPU模式都可识别
}
//resize(frame, frame, Size(960, 540));
cv::imshow("result", frame);
if (cv::waitKey(1) == 27) break;
}
cv::destroyWindow("result");
return 0;
}
else//图片目录
{
//生成随机颜色//
vector<Scalar> color;
srand(time(0));
for (int i = 0; i < 80; i++) {//80种类
int b = rand() % 256;
int g = rand() % 256;
int r = rand() % 256;
color.push_back(Scalar(b, g, r));
}
//color.push_back(Scalar(0, 0, 255));
String folder_path = "./image";
//String folder_path = "./test2";
//String folder_path = "./test";
std::vector<cv::String> file_names;
cv::glob(folder_path, file_names); //get file names
for (int i = 0; i < file_names.size(); i++) {
vector<Output> result;
cv::Mat img;
std::cout << file_names[i] << std::endl;
img = cv::imread(file_names[i]);
if (!img.data) {
continue;
}
//resize(img, img, Size(956, 800));
if (test.Detect(img, net, result))//返回true 检测到对象//
{
test.drawPred(img, result, color);
}
else {
cout << "Detect Failed!" << endl;// CPU模式 有很多识别不到。GPU模式都可识别
}
//resize(img, img, Size(717, 600));//Size(956, 800)
//resize(img, img, Size(1434, 1200));
namedWindow("result", cv::WINDOW_AUTOSIZE);
imshow("result", img);
cv::waitKey(1000);//等待1秒//
}
//cv::destroyAllWindows();
cv::destroyWindow("result");
//system("pause");
}
return 0;
}yolo.h
#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#define YOLO_P6 false //是否使用P6模型//
struct Output {
int id; //结果类别id/
float confidence; //结果置信度//
cv::Rect box; //矩形框//
};
class Yolo {
public:
Yolo() {
}
~Yolo() {}
bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
bool Detect(cv::Mat& SrcImg, cv::dnn::Net& net, std::vector<Output>& output);
void drawPred(cv::Mat& img, std::vector<Output> result, std::vector<cv::Scalar> color);
private:
#if(defined YOLO_P6 && YOLO_P6==true)
const float netAnchors[4][6] = { { 19,27, 44,40, 38,94 },{ 96,68, 86,152, 180,137 },{ 140,301, 303,264, 238,542 },{ 436,615, 739,380, 925,792 } };
const int netWidth = 1280; //ONNX图片输入宽度
const int netHeight = 1280; //ONNX图片输入高度
const int strideSize = 4; //stride size
#else
const float netAnchors[3][6] = { { 10,13, 16,30, 33,23 },{ 30,61, 62,45, 59,119 },{ 116,90, 156,198, 373,326 } };
const int netWidth = 640; //ONNX图片输入宽度 yolov5s.onnx 640
const int netHeight = 640; //ONNX图片输入高度
const int strideSize = 3; //stride size
#endif // YOLO_P6
const float netStride[4] = { 8, 16.0,32,64 };
float boxThreshold = 0.25;
float classThreshold = 0.25;
float nmsThreshold = 0.45;
float nmsScoreThreshold = boxThreshold * classThreshold;
std::vector<std::string> className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
"fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
"elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
"hair drier", "toothbrush" };
};yolo.cpp
#include"yolo.h"
using namespace std;
using namespace cv;
using namespace cv::dnn;
bool Yolo::readModel(Net& net, string& netPath, bool isCuda = false) {
try {
net = readNet(netPath);
}
catch (const std::exception&) {
return false;
}
//cuda
if (isCuda) {
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);//_FP16
}
//cpu
else {
net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
}
return true;
}
bool Yolo::Detect(Mat& SrcImg, Net& net, vector<Output>& output) {
Mat blob;
int col = SrcImg.cols;
int row = SrcImg.rows;
int maxLen = MAX(col, row);
Mat netInputImg = SrcImg.clone();
if (maxLen > 1.2 * col || maxLen > 1.2 * row) {
Mat resizeImg = Mat::zeros(maxLen, maxLen, CV_8UC3);
SrcImg.copyTo(resizeImg(Rect(0, 0, col, row)));
netInputImg = resizeImg;
}
blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0, 0), true, false);
//如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句//
//blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(104, 117, 123), true, false);
//blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(114, 114,114), true, false);
net.setInput(blob);
std::vector<cv::Mat> netOutputImg;
//vector<string> outputLayerName{"345","403", "461","output" };
//net.forward(netOutputImg, outputLayerName[3]); //获取output的输出//
try
{ //release OK
net.forward(netOutputImg, net.getUnconnectedOutLayersNames());//debug报错 initCUDABackend CUDA backend will fallback to the CPU implementation for the layer "_input"
}
catch (const std::exception& e)
{
cout << e.what();
}
std::vector<int> classIds;//结果id数组//
std::vector<float> confidences;//结果每个id对应置信度数组//
std::vector<cv::Rect> boxes;//每个id矩形框//
float ratio_h = (float)netInputImg.rows / netHeight;
float ratio_w = (float)netInputImg.cols / netWidth;
int net_width = className.size() + 5; //输出的网络宽度是类别数+5//
float* pdata = (float*)netOutputImg[0].data;
for (int stride = 0; stride < strideSize; stride++) { //stride
int grid_x = (int)(netWidth / netStride[stride]);
int grid_y = (int)(netHeight / netStride[stride]);
for (int anchor = 0; anchor < 3; anchor++) { //anchors
const float anchor_w = netAnchors[stride][anchor * 2];
const float anchor_h = netAnchors[stride][anchor * 2 + 1];
for (int i = 0; i < grid_y; i++) {
for (int j = 0; j < grid_x; j++) {
float box_score = pdata[4]; ;//获取每一行的box框中含有某个物体的概率//
if (box_score >= boxThreshold) {
cv::Mat scores(1, className.size(), CV_32FC1, pdata + 5);
Point classIdPoint;
double max_class_socre;
minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
max_class_socre = (float)max_class_socre;
if (max_class_socre >= classThreshold) {
//rect [x,y,w,h]
float x = pdata[0]; //x
float y = pdata[1]; //y
float w = pdata[2]; //w
float h = pdata[3]; //h
int left = (x - 0.5 * w) * ratio_w;
int top = (y - 0.5 * h) * ratio_h;
classIds.push_back(classIdPoint.x);
confidences.push_back(max_class_socre * box_score);
boxes.push_back(Rect(left, top, int(w * ratio_w), int(h * ratio_h)));
}
}
pdata += net_width;//下一行//
}
}
}
}
//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)//
vector<int> nms_result;
NMSBoxes(boxes, confidences, nmsScoreThreshold, nmsThreshold, nms_result);
for (int i = 0; i < nms_result.size(); i++) {
int idx = nms_result[i];
Output result;
result.id = classIds[idx];
result.confidence = confidences[idx];
result.box = boxes[idx];
output.push_back(result);
}
if (output.size())
return true;
else
return false;
}
void Yolo::drawPred(Mat& img, vector<Output> result, vector<Scalar> color) {
for (int i = 0; i < result.size(); i++) {
int left, top;
left = result[i].box.x;
top = result[i].box.y;
int color_num = i;
//rectangle(img, result[i].box, color[result[i].id], 2, 8);
rectangle(img, result[i].box, color[result[i].id], 2, 8);
string label = className[result[i].id] + ":" + to_string(result[i].confidence);
int baseLine;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
top = max(top, labelSize.height);
//rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);
putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
}
//imshow("1", img);
imwrite("out.bmp", img);
//waitKey();
//destroyAllWindows();
}结论:
自己训练了一个单分类模型,同一个模型在GPU上推理能够实现百分之百检测到目标,在CPU上推理失败率很高。
参考:
https://blog.csdn.net/qq_45945548/article/details/121701492
https://github.com/doleron/yolov5-opencv-cpp-python
The End
边栏推荐
- 导航栏切换,留言板,文本框失去焦点
- 第九章Cisco ASA应用NAT
- Map集合遍历,添加替换,删除元素
- Scholar magic changes QT creator plug-in framework (with examples)
- C语言初阶(六)函数
- The out of the box caching function of angular server-side rendering applications
- 从零走进软件开发的世界
- 2022年安全员-C证上岗证题目及答案
- 基于QtQuick的QCustomPlot实现
- Coordinate transformation learning of OpenGL learning notes
猜你喜欢

Getting started with data visualization

考研政英平均分出炉!你目前什么水平?

Solon 1.8.3 发布,云原生微服务开发框架

QML入门到进阶

电源老化测试系统定制|充电桩自动化测试系统NSAT-8000概述

适配器电源自动测试设备|充电器ATE测试系统NSAT-8000介绍

From zero into the world of software development

泰克Tektronix示波器上位机软件NS-Scope介绍

Feature metric loss for self supervised learning of depth and egomotion
[Architect (Part 38)] locally install the latest version of MySQL database developed by the server
随机推荐
DevSecOps:应当做好的十件事
Secret magic weapon
永不落幕的数据库注入攻防
C语言初阶(六)函数
DevSecOps:S-SDLC企业最佳实践
Citus 11 for Postgres is completely open source and can be queried from any node (citus official blog)
What securities does qiniu use to open an account? Is it safe to open an account
Young people are reluctant to change their mobile phones, because they choose a more durable iPhone, and the parameter theory of domestic mobile phones is invalid
New experience of cultural tourism! 3dcat helps Guangzhou intangible cultural heritage "yuancosmos" block make a cool appearance
技术管理进阶——如何提升团队的合作和技术氛围
High performance parallel programming and optimization | lesson 01 homework
【100个 Unity踩坑小知识点】| Unity控制物体持续指向某个方向
C语言初阶(七)结构体
送分题,ArrayList 的扩容机制了解吗?
fix libpng warning: iCCP: Not recognizing known sRGB profile ......
15+城市道路要素分割应用,用这一个分割模型就够了!
【100个 Unity踩坑小知识点】| 在编辑器中绘制正方体虚线、球体虚线(Gizmos 辅助线框)
Implementation of qcustomplot based on qtquick
Compilation principle knowledge points sorting
From zero into the world of software development