• YOLOV8 C++ opecv_dnn模块部署


    废话不多说:opencv>=4.7.0

    opencv编译不做解释,需要的话翻看别的博主的编译教程

    代码饱含V5,V7,V8部署内容

    头文件yoloV8.h

    1. #pragma once
    2. #include
    3. #include
    4. using namespace std;
    5. using namespace cv;
    6. using namespace cv::dnn;
    7. struct Detection
    8. {
    9. int class_id{ 0 };//结果类别id
    10. float confidence{ 0.0 };//结果置信度
    11. cv::Rect box{};//矩形框
    12. };
    13. class Yolo {
    14. public:
    15. bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
    16. void drawPred(cv::Mat& img, std::vector result, std::vector color);
    17. virtual vector Detect(cv::Mat& SrcImg, cv::dnn::Net& net) = 0;
    18. float sigmoid_x(float x) { return static_cast<float>(1.f / (1.f + exp(-x))); }
    19. Mat formatToSquare(const cv::Mat& source)
    20. {
    21. int col = source.cols;
    22. int row = source.rows;
    23. int _max = MAX(col, row);
    24. cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
    25. source.copyTo(result(cv::Rect(0, 0, col, row)));
    26. return result;
    27. }
    28. const int netWidth = 640; //ONNX图片输入宽度
    29. const int netHeight = 640; //ONNX图片输入高度
    30. float modelConfidenceThreshold{ 0.0 };
    31. float modelScoreThreshold{ 0.0 };
    32. float modelNMSThreshold{ 0.0 };
    33. std::vector classes = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
    34. "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
    35. "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
    36. "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
    37. "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
    38. "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
    39. "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
    40. "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
    41. "hair drier", "toothbrush" };
    42. };
    43. class Yolov5 :public Yolo {
    44. public:
    45. vector Detect(Mat& SrcImg, Net& net);
    46. private:
    47. float confidenceThreshold{ 0.25 };
    48. float nmsIoUThreshold{ 0.45 };
    49. };
    50. class Yolov7 :public Yolo {
    51. public:
    52. vector Detect(Mat& SrcImg, Net& net);
    53. private:
    54. float confidenceThreshold{ 0.25 };
    55. float nmsIoUThreshold{ 0.45 };
    56. const int strideSize = 3; //stride size
    57. const float netStride[4] = { 8.0, 16.0, 32.0, 64.0 };
    58. const float netAnchors[3][6] = { {12, 16, 19, 36, 40, 28},{36, 75, 76, 55, 72, 146},{142, 110, 192, 243, 459, 401} }; //yolov7-P5 anchors
    59. };
    60. class Yolov8 :public Yolo {
    61. public:
    62. vector Detect(Mat& SrcImg, Net& net);
    63. private:
    64. float confidenceThreshold{ 0.25 };
    65. float nmsIoUThreshold{ 0.70 };
    66. };

    源文件yoloV8.cpp:

    1. #include"yoloV8.h"
    2. bool Yolo::readModel(Net& net, string& netPath, bool isCuda = false) {
    3. try {
    4. net = readNetFromONNX(netPath);
    5. }
    6. catch (const std::exception&) {
    7. return false;
    8. }
    9. if (isCuda) {
    10. net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
    11. net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
    12. }
    13. else {
    14. net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
    15. net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
    16. }
    17. return true;
    18. }
    19. void Yolo::drawPred(Mat& img, vector result, vector colors) {
    20. for (int i = 0; i < result.size(); ++i)
    21. {
    22. Detection detection = result[i];
    23. cv::Rect box = detection.box;
    24. cv::Scalar color = colors[detection.class_id];
    25. // Detection box
    26. cv::rectangle(img, box, color, 2);
    27. // Detection box text
    28. std::string classString = classes[detection.class_id] + ' ' + std::to_string(detection.confidence).substr(0, 4);
    29. cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
    30. cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);
    31. cv::rectangle(img, textBox, color, cv::FILLED);
    32. cv::putText(img, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
    33. }
    34. }
    35. //vector Yolov5::Detect(Mat& img, Net& net) {
    36. //
    37. // img = formatToSquare(img);
    38. // cv::Mat blob;
    39. // cv::dnn::blobFromImage(img, blob, 1.0 / 255.0, Size(netWidth, netHeight), cv::Scalar(), true, false);
    40. // net.setInput(blob);
    41. //
    42. // std::vector outputs;
    43. // net.forward(outputs, net.getUnconnectedOutLayersNames());
    44. //
    45. //
    46. //
    47. // float* pdata = (float*)outputs[0].data;
    48. // float x_factor = (float)img.cols / netWidth;
    49. // float y_factor = (float)img.rows / netHeight;
    50. //
    51. // std::vector class_ids;
    52. // std::vector confidences;
    53. // std::vector boxes;
    54. //
    55. // // yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c])
    56. // int rows = outputs[0].size[1];
    57. // int dimensions = outputs[0].size[2];
    58. //
    59. // for (int i = 0; i < rows; ++i)
    60. // {
    61. // float confidence = pdata[4];
    62. // if (confidence >= modelConfidenceThreshold)
    63. // {
    64. //
    65. // cv::Mat scores(1, classes.size(), CV_32FC1, pdata + 5);
    66. // cv::Point class_id;
    67. // double max_class_score;
    68. //
    69. // minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
    70. //
    71. // if (max_class_score > modelScoreThreshold)
    72. // {
    73. // confidences.push_back(confidence);
    74. // class_ids.push_back(class_id.x);
    75. //
    76. // float x = pdata[0];
    77. // float y = pdata[1];
    78. // float w = pdata[2];
    79. // float h = pdata[3];
    80. //
    81. // int left = int((x - 0.5 * w) * x_factor);
    82. // int top = int((y - 0.5 * h) * y_factor);
    83. //
    84. // int width = int(w * x_factor);
    85. // int height = int(h * y_factor);
    86. //
    87. // boxes.push_back(cv::Rect(left, top, width, height));
    88. // }
    89. // }
    90. // pdata += dimensions;
    91. // }
    92. //
    93. // vector nms_result;
    94. // NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
    95. // vector detections{};
    96. // for (unsigned long i = 0; i < nms_result.size(); ++i) {
    97. // int idx = nms_result[i];
    98. // Detection result;
    99. // result.class_id = class_ids[idx];
    100. // result.confidence = confidences[idx];
    101. // result.box = boxes[idx];
    102. // detections.push_back(result);
    103. // }
    104. // return detections;
    105. //}
    106. //
    107. //vector Yolov7::Detect(Mat& SrcImg, Net& net) {
    108. // Mat blob;
    109. // int col = SrcImg.cols;
    110. // int row = SrcImg.rows;
    111. // int maxLen = MAX(col, row);
    112. // Mat netInputImg = SrcImg.clone();
    113. // if (maxLen > 1.2 * col || maxLen > 1.2 * row) {
    114. // Mat resizeImg = Mat::zeros(maxLen, maxLen, CV_8UC3);
    115. // SrcImg.copyTo(resizeImg(Rect(0, 0, col, row)));
    116. // netInputImg = resizeImg;
    117. // }
    118. // vector > layer;
    119. // vector layer_names;
    120. // layer_names = net.getLayerNames();
    121. // blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0, 0), true, false);
    122. // net.setInput(blob);
    123. // std::vector netOutput;
    124. // net.forward(netOutput, net.getUnconnectedOutLayersNames());
    125. //#if CV_VERSION_MAJOR==4 && CV_VERSION_MINOR>6
    126. // std::sort(netOutput.begin(), netOutput.end(), [](Mat& A, Mat& B) {return A.size[2] > B.size[2]; });//opencv 4.6 三个output顺序为40 20 80,之前版本的顺序为80 40 20
    127. //#endif
    128. // std::vector class_ids;//结果id数组
    129. // std::vector confidences;//结果每个id对应置信度数组
    130. // std::vector boxes;//每个id矩形框
    131. // float ratio_h = (float)netInputImg.rows / netHeight;
    132. // float ratio_w = (float)netInputImg.cols / netWidth;
    133. // int net_width = classes.size() + 5; //输出的网络宽度是类别数+5
    134. // for (int stride = 0; stride < strideSize; stride++) { //stride
    135. // float* pdata = (float*)netOutput[stride].data;
    136. // int grid_x = (int)(netWidth / netStride[stride]);
    137. // int grid_y = (int)(netHeight / netStride[stride]);
    138. // // cv::Mat tmp(grid_x * grid_y * 3, classes.size() + 5, CV_32FC1, pdata);
    139. // for (int anchor = 0; anchor < 3; anchor++) { //anchors
    140. // const float anchor_w = netAnchors[stride][anchor * 2];
    141. // const float anchor_h = netAnchors[stride][anchor * 2 + 1];
    142. // for (int i = 0; i < grid_y; i++) {
    143. // for (int j = 0; j < grid_x; j++) {
    144. // float confidence = sigmoid_x(pdata[4]); ;//获取每一行的box框中含有物体的概率
    145. // cv::Mat scores(1, classes.size(), CV_32FC1, pdata + 5);
    146. // Point classIdPoint;
    147. // double max_class_socre;
    148. // minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
    149. // max_class_socre = sigmoid_x(max_class_socre);
    150. // if (max_class_socre * confidence >= confidenceThreshold) {
    151. // float x = (sigmoid_x(pdata[0]) * 2.f - 0.5f + j) * netStride[stride]; //x
    152. // float y = (sigmoid_x(pdata[1]) * 2.f - 0.5f + i) * netStride[stride]; //y
    153. // float w = powf(sigmoid_x(pdata[2]) * 2.f, 2.f) * anchor_w; //w
    154. // float h = powf(sigmoid_x(pdata[3]) * 2.f, 2.f) * anchor_h; //h
    155. // int left = (int)(x - 0.5 * w) * ratio_w + 0.5;
    156. // int top = (int)(y - 0.5 * h) * ratio_h + 0.5;
    157. // class_ids.push_back(classIdPoint.x);
    158. // confidences.push_back(max_class_socre * confidence);
    159. // boxes.push_back(Rect(left, top, int(w * ratio_w), int(h * ratio_h)));
    160. // }
    161. // pdata += net_width;//下一行
    162. // }
    163. // }
    164. // }
    165. // }
    166. //
    167. // //执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
    168. // vector nms_result;
    169. // NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
    170. // vector detections{};
    171. // for (unsigned long i = 0; i < nms_result.size(); ++i) {
    172. // int idx = nms_result[i];
    173. // Detection result;
    174. // result.class_id = class_ids[idx];
    175. // result.confidence = confidences[idx];
    176. // result.box = boxes[idx];
    177. // detections.push_back(result);
    178. // }
    179. // return detections;
    180. //}
    181. vector Yolov8::Detect(Mat& modelInput, Net& net) {
    182. modelInput = formatToSquare(modelInput);
    183. cv::Mat blob;
    184. cv::dnn::blobFromImage(modelInput, blob, 1.0 / 255.0, Size(netWidth, netHeight), cv::Scalar(), true, false);
    185. net.setInput(blob);
    186. std::vector outputs;
    187. net.forward(outputs, net.getUnconnectedOutLayersNames());
    188. // yolov8 has an output of shape (batchSize, 84, 8400) (Num classes + box[x,y,w,h])
    189. int rows = outputs[0].size[2];
    190. int dimensions = outputs[0].size[1];
    191. outputs[0] = outputs[0].reshape(1, dimensions);
    192. cv::transpose(outputs[0], outputs[0]);
    193. float* data = (float*)outputs[0].data;
    194. // Mat detect_output(8400, 84, CV_32FC1, data);// 8400 = 80*80+40*40+20*20
    195. float x_factor = (float)modelInput.cols / netWidth;
    196. float y_factor = (float)modelInput.rows / netHeight;
    197. std::vector<int> class_ids;
    198. std::vector<float> confidences;
    199. std::vector boxes;
    200. for (int i = 0; i < rows; ++i)
    201. {
    202. cv::Mat scores(1, classes.size(), CV_32FC1, data + 4);
    203. cv::Point class_id;
    204. double maxClassScore;
    205. minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
    206. if (maxClassScore > modelConfidenceThreshold)
    207. {
    208. confidences.push_back(maxClassScore);
    209. class_ids.push_back(class_id.x);
    210. float x = data[0];
    211. float y = data[1];
    212. float w = data[2];
    213. float h = data[3];
    214. int left = int((x - 0.5 * w) * x_factor);
    215. int top = int((y - 0.5 * h) * y_factor);
    216. int width = int(w * x_factor);
    217. int height = int(h * y_factor);
    218. boxes.push_back(cv::Rect(left, top, width, height));
    219. }
    220. data += dimensions;
    221. }
    222. //执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
    223. vector<int> nms_result;
    224. NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
    225. vector detections{};
    226. for (unsigned long i = 0; i < nms_result.size(); ++i) {
    227. int idx = nms_result[i];
    228. Detection result;
    229. result.class_id = class_ids[idx];
    230. result.confidence = confidences[idx];
    231. result.box = boxes[idx];
    232. detections.push_back(result);
    233. }
    234. return detections;
    235. }

    main.CPP

    1. #include "yoloV8.h"
    2. #include
    3. #include
    4. #include
    5. #define USE_CUDA false //use opencv-cuda
    6. using namespace std;
    7. using namespace cv;
    8. using namespace dnn;
    9. int main()
    10. {
    11. string img_path = "./bus.jpg";
    12. string model_path3 = "./yolov8n.onnx";
    13. Mat img = imread(img_path);
    14. vector color;
    15. srand(time(0));
    16. for (int i = 0; i < 80; i++) {
    17. int b = rand() % 256;
    18. int g = rand() % 256;
    19. int r = rand() % 256;
    20. color.push_back(Scalar(b, g, r));
    21. }
    22. /*Yolov5 yolov5; Net net1;
    23. Mat img1 = img.clone();
    24. bool isOK = yolov5.readModel(net1, model_path1, USE_CUDA);
    25. if (isOK) {
    26. cout << "read net ok!" << endl;
    27. }
    28. else {
    29. cout << "read onnx model failed!";
    30. return -1;
    31. }
    32. vector result1 = yolov5.Detect(img1, net1);
    33. yolov5.drawPred(img1, result1, color);
    34. Mat dst = img1({ 0, 0, img.cols, img.rows });
    35. imwrite("results/yolov5.jpg", dst);
    36. Yolov7 yolov7; Net net2;
    37. Mat img2 = img.clone();
    38. isOK = yolov7.readModel(net2, model_path2, USE_CUDA);
    39. if (isOK) {
    40. cout << "read net ok!" << endl;
    41. }
    42. else {
    43. cout << "read onnx model failed!";
    44. return -1;
    45. }
    46. vector result2 = yolov7.Detect(img2, net2);
    47. yolov7.drawPred(img2, result2, color);
    48. dst = img2({ 0, 0, img.cols, img.rows });
    49. imwrite("results/yolov7.jpg", dst);*/
    50. Yolov8 yolov8; Net net3;
    51. Mat img3 = img.clone();
    52. bool isOK = yolov8.readModel(net3, model_path3, USE_CUDA);
    53. if (isOK) {
    54. cout << "read net ok!" << endl;
    55. }
    56. else {
    57. cout << "read onnx model failed!";
    58. return -1;
    59. }
    60. vector result3 = yolov8.Detect(img3, net3);
    61. yolov8.drawPred(img3, result3, color);
    62. Mat dst = img3({ 0, 0, img.cols, img.rows });
    63. cv::imshow("aaa", dst);
    64. imwrite("./yolov8.jpg", dst);
    65. cv::waitKey(0);
    66. return 0;
    67. }

    opencv编译需要时间久,GPU版本可以达到实时,有问题先尝试解决,搞定不了私信留言。

  • 相关阅读:
    Vivado IP中Generate Output Products的设置说明
    PHP 初学 GO 学习笔记
    java split教程
    Scrapy第七篇:数据存储(ORM框架采用peewee)
    国产低功耗MCU芯片:Si24R03
    自动翻译软件-批量批量自动翻译软件推荐
    5种kafka消费端性能优化方法
    11.3 - 三级模式/两级映像 11.4 - 数据库管理系统 11.5 - 完整性约束 11.6 - 分布式数据库 11.7 - DBA
    ESP32-S3在VSCODE上编译烧录
    Hibernate:Caused by: java.lang.ClassNotFoundException: oracle.sql.BLOB
  • 原文地址:https://blog.csdn.net/qq_49627063/article/details/133124707