当前位置:   article > 正文

opencv调用yolov5模型进行目标检测(c++版)_yolov5 opencv c++

yolov5 opencv c++

一、环境安装

1. miniconda

(1)安装准备

在终端中输入以下命令

  1. sudo apt-get update //更新包列表
  2. sudo apt-get install build-essential //安装构建必需工具
  3. sudo apt-get install wget //安装wget
(2)下载

官网:https://docs.conda.io/en/latest/miniconda.html

或者

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

然后给文件添加运行权限

chmod +x Miniconda3-latest-Linux-x86_64.sh
(3)安装
./Miniconda3-latest-Linux-x86_64.sh

照着提示按步骤安装,过程中可以修改安装路径

(4)配置
sudo vim ~/.bashrc   //打开.bashrc文件

在文件末尾处添加

export PATH="/home/你的用户名/miniconda/bin:$PATH"  //这个是默认路径下的

保存退出后,使配置生效

source ~/.bashrc

可以添加清华的conda源来使用

  1. conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
  2. conda config --set show_channel_urls yes
(5)使用
  1. conda create -n yolov5 python=3.8 //创建名为yolov5且python版本3.8的虚拟环境
  2. conda activate yolov5 //用来激活环境的
  3. 在该环境下可以使用conda install来安装包

2. yolov5

(1)下载

官网:https://github.com/ultralytics/yolov5

 点击全部发行版,选择自己需要的yolov5版本的源代码和预训练权重文件下载

注:我所使用opencv版本为v4.5.0,一开始使用yolov5-v7.0版本出现无法调用该模型的错误,后经过调试发现opencv4.5.0无法读取ai.onnx版本超过v12的onnx模型,后来yolov5版本改为v6.2可以正常使用
(2)安装依赖

把预训练模型放入yolov5文件夹后,打开requirements.txt。

  1. #onnx>=1.9.0 # ONNX export
  2. #onnx-simplifier>=0.4.1 # ONNX simplifier

将这两行开头的的#号去掉,保存,然后在之前创建的conda环境中执行

pip install -r requirements.txt
(3)将.pt文件转化为.onnx文件
python export.py --weights yolov5m6.pt --include onnx --imgsz 640 640

二、调用代码

我用一个json文件存放模型的对应参数信息,调用时将从文件里读取存入到一个封装的struct结构体里。

  1. struct Net5_config
  2. {
  3. std::vector<float> CONFIDENCE_THRESHOLD; // 置信度
  4. std::vector<float> NMS_THRESHOLD; // nms阙值
  5. std::vector<float> SCORE_THRESHOLD; //得分阙值
  6. std::vector<int> INPUT_WIDTH; // 输入图像的宽度
  7. std::vector<int> INPUT_HEIGHT; // 输入图像的长度
  8. std::vector<std::string> classesFile; //coco.name等物品分类名称文件路径
  9. std::vector<std::string> modelWeights; //模型权重文件路径
  10. std::vector<std::string> netname; //模型权重文件名称
  11. int id = 0; //用于判断当前使用哪个模型
  12. };

然后又写了一个类来实现调用

  1. class Recognizerv5
  2. {
  3. public:
  4. Recognizerv5(Net5_config config); //yolo初始化配置
  5. bool IdentifyTarget(cv::Mat &frame, Result &output); //yolo模型推理
  6. bool drawRect(cv::Mat &frame, Result &output); //将识别结果画出来
  7. private:
  8. float confThreshold; //置信度阙值
  9. float nmsThreshold; //nms阙值
  10. float SCORE_THRESHOLD; //得分阙值
  11. int inpWidth; //图片输入宽度
  12. int inpHeight; //图片输入高度
  13. char netname[20]; //使用的模型的名字
  14. std::vector<std::string> classes; //物品类别目录
  15. cv::dnn::Net net; //用于模型推理
  16. };
  17. //存放识别的定位信息
  18. struct Result
  19. {
  20. std::vector<int> x;
  21. std::vector<int> y;
  22. std::vector<int> width;
  23. std::vector<int> height;
  24. std::vector<std::string> name;
  25. };
  26. //清空定位信息
  27. void Result_clear(struct Result &p)
  28. {
  29. p.name.clear();
  30. p.x.clear();
  31. p.y.clear();
  32. p.height.clear();
  33. p.width.clear();
  34. }
  35. //用于存放识别出来的物品框的信息
  36. struct Detection
  37. {
  38. int class_id; //物品类别下标
  39. float confidence; //置信度
  40. cv::Rect box; //方框信息
  41. };
  42. //用于复制图像
  43. cv::Mat format_yolov5(const cv::Mat &source)
  44. {
  45. int col = source.cols;
  46. int row = source.rows;
  47. int _max = MAX(col, row);
  48. cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
  49. source.copyTo(result(cv::Rect(0, 0, col, row)));
  50. return result;
  51. }
  52. //yolo初始化配置
  53. Recognizerv5::Recognizerv5(Net5_config config)
  54. {
  55. //将数据从struct结构体里传入class里
  56. std::cout << "Net use " << config.netname[config.id] << std::endl;
  57. this->confThreshold = config.CONFIDENCE_THRESHOLD[config.id];
  58. this->nmsThreshold = config.NMS_THRESHOLD[config.id];
  59. this->inpWidth = config.INPUT_WIDTH[config.id];
  60. this->inpHeight = config.INPUT_HEIGHT[config.id];
  61. this->SCORE_THRESHOLD = config.SCORE_THRESHOLD[config.id];
  62. strcpy(this->netname, config.netname[config.id].c_str());
  63. std::ifstream ifs(config.classesFile[config.id].c_str());
  64. std::string line;
  65. while (getline(ifs, line))
  66. this->classes.push_back(line);
  67. //使用opencv的dnn模块读取模型文件
  68. auto result = cv::dnn::readNet(config.modelWeights[config.id]);
  69. //设置运行方式
  70. std::cout << "Running on CPU\n";
  71. result.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
  72. result.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
  73. //将读取结果存入net
  74. this->net = result;
  75. }
  76. //yolo模型推理
  77. bool Recognizerv5::IdentifyTarget(cv::Mat &frame, Result &output)
  78. {
  79. std::vector<Detection> p;
  80. cv::Mat blob;
  81. auto input_image = format_yolov5(frame);
  82. //为推理模型设置参数
  83. cv::dnn::blobFromImage(input_image, blob, 1. / 255., cv::Size(this->inpWidth, this->inpHeight), cv::Scalar(), true, false);
  84. this->net.setInput(blob);
  85. //网络推理
  86. std::vector<cv::Mat> outputs;
  87. this->net.forward(outputs, net.getUnconnectedOutLayersNames());
  88. float x_factor = input_image.cols / this->inpWidth;
  89. float y_factor = input_image.rows / this->inpHeight;
  90. float *data = (float *)outputs[0].data;
  91. const int dimensions = 85;
  92. const int rows = 25200;
  93. std::vector<int> class_ids;
  94. std::vector<float> confidences;
  95. std::vector<cv::Rect> boxes;
  96. //对推理的结果进行检测
  97. for (int i = 0; i < rows; ++i)
  98. {
  99. float confidence = data[4];
  100. if (confidence >= this->confThreshold) //如果置信度大于设置的阙值说明是可信的
  101. {
  102. float *classes_scores = data + 5;
  103. cv::Mat scores(1, this->classes.size(), CV_32FC1, classes_scores);
  104. cv::Point class_id;
  105. double max_class_score;
  106. minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
  107. if (max_class_score > SCORE_THRESHOLD) //如果检测的分数大于阙值,则是可信的
  108. {
  109. confidences.push_back(confidence);
  110. class_ids.push_back(class_id.x);
  111. float x = data[0];
  112. float y = data[1];
  113. float w = data[2];
  114. float h = data[3];
  115. int left = int((x - 0.5 * w) * x_factor);
  116. int top = int((y - 0.5 * h) * y_factor);
  117. int width = int(w * x_factor);
  118. int height = int(h * y_factor);
  119. boxes.push_back(cv::Rect(left, top, width, height));
  120. }
  121. }
  122. data += 85;
  123. }
  124. std::vector<int> nms_result;
  125. //进行极大值抑制nms算法
  126. cv::dnn::NMSBoxes(boxes, confidences,SCORE_THRESHOLD,this->nmsThreshold, nms_result,0.8);//eta这个参数默认1.0,范围0.1-1.0,设置代表启用soft-nms算法,top_k表示保留框的个数
  127. //将结果存入output
  128. for (int i = 0; i < nms_result.size(); i++)
  129. {
  130. int idx = nms_result[i];
  131. Detection result;
  132. result.class_id = class_ids[idx];
  133. result.confidence = confidences[idx];
  134. result.box = boxes[idx];
  135. p.push_back(result);
  136. }
  137. int detections = p.size();
  138. for (int i = 0; i < detections; ++i)
  139. {
  140. auto detection = p[i];
  141. auto box = detection.box;
  142. auto classId = detection.class_id;
  143. output.name.push_back(this->classes[classId]);
  144. output.x.push_back(box.x);
  145. output.y.push_back(box.y);
  146. output.width.push_back(box.width);
  147. output.height.push_back(box.height);
  148. }
  149. return true;
  150. }
  151. //将识别结果画出来
  152. bool Recognizerv5::drawRect(cv::Mat &frame, Result &output)
  153. {
  154. for (int i = 0; i < output.name.size(); i++)
  155. {
  156. cv::Rect box(output.x[i], output.y[i], output.width[i], output.height[i]);
  157. cv::rectangle(frame, box, cv::Scalar(0, 255, 0), 3);
  158. cv::rectangle(frame, cv::Point(box.x, box.y - 20), cv::Point(box.x + box.width, box.y), cv::Scalar(0, 255, 0), cv::FILLED);
  159. cv::putText(frame, output.name[i].c_str(), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
  160. }
  161. return true;
  162. }

以上可以分装在namespcae里便于使用

main函数

  1. int main(int argc, char const *argv[]){
  2. cv::VideoCapture camera=cv::VideoCapture(0);
  3. if (camera.isOpened() == false)
  4. {
  5. std::cout<< "camera couldn't open" <<std::endl;
  6. return -1;
  7. }
  8. struct Net5_config yolov5_net;
  9. //这里可以自己写一个从文件读取配置信息的函数,或者直接赋值在结构体里
  10. Recognizerv5 recognizer(yolov5_net);
  11. Result yolo_result;
  12. while (true)
  13. {
  14. cv::Mat image;
  15. camera >> image;
  16. if (image.empty() == true)
  17. {
  18. break;
  19. }
  20. cv::namedWindow("test",cv::WINDOW_NORMAL);
  21. YOLO::Result_clear(yolo_result);
  22. recognizer.IdentifyTarget(image, yolo_result);
  23. recognizer.drawRect(image, yolo_result);
  24. cv::imshow("test", image);
  25. if (cv::waitKey(1) > 0)
  26. {
  27. break;
  28. }
  29. }
  30. camera.release();
  31. cv::destroyAllWindows();
  32. return 0;
  33. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/413436
推荐阅读
相关标签
  

闽ICP备14008679号