当前位置:   article > 正文

yolov5分割+检测c++ qt 中部署,以opencv方式(详细代码(全)+复制可用)_yolov5+qt+c++

yolov5+qt+c++

1:版本说明:

qt 5.12.10

opencv 4.5.3 (yolov5模型部署要求opencv>4.5.0)

2:检测的代码

yolo.h
  1. #pragma once
  2. #include<iostream>
  3. #include<cmath>
  4. #include<vector>
  5. #include <opencv2/opencv.hpp>
  6. #include<opencv2/dnn.hpp>
  7. class yolo
  8. {
  9. public:
  10. yolo() {}
  11. ~yolo(){}
  12. bool readModel(cv::dnn::Net &net,std::string &netpath, bool isCuda);
  13. struct Output
  14. {
  15. int id;//结果类别id
  16. float confidence;//结果置信度
  17. cv::Rect box;//矩形框
  18. int ship_id;//船的id
  19. int truck_id;//人的id
  20. int person_id;//人的id
  21. int staring_id;//车的id
  22. int forklift_id;//车的id
  23. int unload_car_id;//船的id
  24. int load_car_id;//人的id
  25. int private_car_id;//车的id
  26. };
  27. struct Output_max_confidence
  28. {
  29. int id;//结果类别id
  30. float confidence;//结果置信度
  31. cv::Rect box;//矩形框
  32. };
  33. int ship_num;//总人数
  34. int car_trucks_num;//总车数
  35. int person_num;//总船数
  36. int stacking_area_num;//总人数
  37. int car_forklift_num;//总车数
  38. int unload_car_num;//总船数
  39. int load_car_num;//总人数
  40. int car_private_num;//总车数
  41. bool Detect(cv::Mat &SrcImg, cv::dnn::Net &net, std::vector<Output> &output);
  42. void drawPred(cv::Mat &img, std::vector<Output> result, std::vector<cv::Scalar> color);
  43. //参数为私有参数,当然也可以是设置成公开或者保护。
  44. Output_max_confidence get_only_one_max_confidence(std::vector<Output> result);
  45. float findMax(std::vector<float> vec);
  46. int getPositionOfMax(std::vector<float> vec, int max);
  47. \
  48. void drawRect(cv::Mat &img, yolo::Output_max_confidence result);
  49. private:
  50. //计算归一化函数
  51. float Sigmoid(float x) {
  52. return static_cast<float>(1.f / (1.f + exp(-x)));
  53. }
  54. //anchors
  55. const float netAnchors[3][6] = { { 10.0, 13.0, 16.0, 30.0, 33.0, 23.0 },{ 30.0, 61.0, 62.0, 45.0, 59.0, 119.0 },{ 116.0, 90.0, 156.0, 198.0, 373.0, 326.0 } };
  56. //stride
  57. const float netStride[3] = { 8.0, 16.0, 32.0 };
  58. const int netWidth = 640; //网络模型输入大小
  59. const int netHeight = 640;
  60. float nmsThreshold = 0.02;
  61. float boxThreshold = 0.05;
  62. float classThreshold = 0.45;
  63. //类名
  64. // std::vector<std::string> className = { "car", "person"};
  65. // std::vector<std::string> className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
  66. // "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
  67. // "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
  68. // "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
  69. // "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
  70. // "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
  71. // "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
  72. // "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
  73. // "hair drier", "toothbrush"};
  74. std::vector<std::string> className = { "ship","car_trucks","person","stacking_area","car_forklift","unload_car","load_car","car_private"};//"car","person"
  75. };
yolo.cpp
  1. #include "yolo.h"
  2. #include<iostream>
  3. #include<cmath>
  4. #include<vector>
  5. #include <opencv2/opencv.hpp>
  6. #include<opencv2/dnn.hpp>
  7. using namespace std;
  8. using namespace cv;
  9. using namespace dnn;
  10. #pragma execution_character_set("utf-8");
  11. bool yolo::readModel(Net &net, string &netPath, bool isCuda = false) {
  12. try {
  13. net = readNetFromONNX(netPath);
  14. cout<<"load net successfull!"<<endl;
  15. }
  16. catch (const std::exception&) {
  17. return false;
  18. }
  19. //cuda
  20. if (isCuda) {
  21. net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
  22. net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
  23. }
  24. //cpu
  25. else {
  26. net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
  27. net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
  28. }
  29. return true;
  30. }
  31. bool yolo::Detect(Mat &SrcImg, Net &net, vector<Output> &output) {
  32. Mat blob;
  33. int col = SrcImg.cols;
  34. int row = SrcImg.rows;
  35. int maxLen = MAX(col, row);
  36. Mat netInputImg = SrcImg.clone();
  37. if (maxLen > 1.2*col || maxLen > 1.2*row) {
  38. Mat resizeImg = Mat::zeros(maxLen, maxLen, CV_8UC3);
  39. SrcImg.copyTo(resizeImg(Rect(0, 0, col, row)));
  40. netInputImg = resizeImg;
  41. }
  42. blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(104, 117, 123), true, false);
  43. blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0,0), true, false);//如果训练集未对图片进行减去均值操作,则需要设置为这句
  44. //blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(114, 114,114), true, false);
  45. net.setInput(blob);
  46. std::vector<cv::Mat> netOutputImg;
  47. //vector<string> outputLayerName{"345","403", "461","output" };
  48. //net.forward(netOutputImg, outputLayerName[3]); //获取output的输出
  49. net.forward(netOutputImg, net.getUnconnectedOutLayersNames());
  50. //接上面
  51. std::vector<int> classIds;//结果id数组
  52. std::vector<float> confidences;//结果每个id对应置信度数组
  53. std::vector<cv::Rect> boxes;//每个id矩形框
  54. std::vector<int> ship_id;//记录下人数的id号码----补充
  55. std::vector<int> trucks_id;//记录下车数的id号码----补充
  56. std::vector<int> person_id;//记录下人数的id号码----补充
  57. std::vector<int> stacking_id;//记录下车数的id号码----补充
  58. std::vector<int> forklift_id;//记录下人数的id号码----补充
  59. std::vector<int> unload_car_id;//记录下车数的id号码----补充
  60. std::vector<int> load_car_id;//记录下人数的id号码----补充
  61. std::vector<int> car_private_id;//记录下车数的id号码----补充
  62. float ratio_h = (float)netInputImg.rows / netHeight;
  63. float ratio_w = (float)netInputImg.cols / netWidth;
  64. int net_width = className.size() + 5; //输出的网络宽度是类别数+5
  65. float* pdata = (float*)netOutputImg[0].data;
  66. for (int stride = 0; stride < 3; stride++) { //stride
  67. int grid_x = (int)(netWidth / netStride[stride]);
  68. int grid_y = (int)(netHeight / netStride[stride]);
  69. for (int anchor = 0; anchor < 3; anchor++) { //anchors
  70. const float anchor_w = netAnchors[stride][anchor * 2];
  71. const float anchor_h = netAnchors[stride][anchor * 2 + 1];
  72. for (int i = 0; i < grid_y; i++) {
  73. for (int j = 0; j < grid_y; j++) {
  74. //float box_score = Sigmoid(pdata[4]);//获取每一行的box框中含有某个物体的概率 yolo5.0
  75. float box_score = pdata[4];//获取每一行的box框中含有某个物体的概率 yolo6.0
  76. if (box_score > boxThreshold) {
  77. //为了使用minMaxLoc(),将85长度数组变成Mat对象
  78. cv::Mat scores(1, className.size(), CV_32FC1, pdata + 5);
  79. Point classIdPoint;
  80. double max_class_socre;
  81. minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
  82. //max_class_socre = Sigmoid((float)max_class_socre); //yolo 5.0
  83. max_class_socre = (float)max_class_socre; //yolo 6.0
  84. if (max_class_socre > classThreshold) {
  85. //rect [x,y,w,h]
  86. //yolov5 5.0格式
  87. //float x = (Sigmoid(pdata[0]) * 2.f - 0.5f + j) * netStride[stride]; //x
  88. //float y = (Sigmoid(pdata[1]) * 2.f - 0.5f + i) * netStride[stride]; //y
  89. //float w = powf(Sigmoid(pdata[2]) * 2.f, 2.f) * anchor_w; //w
  90. //float h = powf(Sigmoid(pdata[3]) * 2.f, 2.f) * anchor_h; //h
  91. //yolov5 6.0格式:
  92. float x = pdata[0];// (Sigmoid(pdata[0]) * 2.f - 0.5f + j) * netStride[stride]; //x
  93. float y = pdata[1];// (Sigmoid(pdata[1]) * 2.f - 0.5f + i) * netStride[stride]; //y
  94. float w = pdata[2];// powf(Sigmoid(pdata[2]) * 2.f, 2.f) * anchor_w; //w
  95. float h = pdata[3];// powf(Sigmoid(pdata[3]) * 2.f, 2.f) * anchor_h; //h
  96. int left = (x - 0.5*w)*ratio_w;
  97. int top = (y - 0.5*h)*ratio_h;
  98. classIds.push_back(classIdPoint.x);
  99. confidences.push_back(max_class_socre*box_score);
  100. boxes.push_back(Rect(left, top, int(w*ratio_w), int(h*ratio_h)));
  101. }
  102. }
  103. pdata += net_width;//指针移到下一行
  104. }
  105. }
  106. }
  107. }
  108. //接上面执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
  109. vector<int> nms_result;
  110. int ship_id_ini=0;//初始化人数,
  111. int trucks_id_ini=0;//初始化人数,
  112. int person_id_ini=0;//初始化车辆数
  113. int stacking_id_ini=0;//初始化车辆数
  114. int forklift_id_ini=0;//初始化车辆数
  115. int unload_car_id_ini=0;//初始化车辆数
  116. int load_car_id_ini=0;//初始化车辆数
  117. int car_private_id_ini=0;//初始化车辆数
  118. NMSBoxes(boxes, confidences, classThreshold, nmsThreshold, nms_result);
  119. for (int i = 0; i < nms_result.size(); i++) {
  120. int idx = nms_result[i];
  121. Output result;
  122. result.id = classIds[idx];
  123. result.confidence = confidences[idx];
  124. result.box = boxes[idx];
  125. output.push_back(result);
  126. if(result.id==0)//当类别数等于船的时候
  127. {
  128. result.ship_id=ship_id_ini;//当船等于
  129. ship_id_ini=ship_id_ini+1;
  130. }
  131. if(result.id==1)//当类别数等于车的时候
  132. {
  133. result.truck_id=trucks_id_ini;//当车数等于
  134. trucks_id_ini=trucks_id_ini+1;
  135. }
  136. if(result.id==2)//当类别数等于人的时候
  137. {
  138. result.person_id=person_id_ini;//当人数等于
  139. person_id_ini=person_id_ini+1;
  140. }if(result.id==3)//当类别数等于人的时候
  141. {
  142. result.staring_id=stacking_id_ini;//当人数等于
  143. stacking_id_ini=stacking_id_ini+1;
  144. }
  145. if(result.id==4)//当类别数等于人的时候
  146. {
  147. result.forklift_id=forklift_id_ini;//当人数等于
  148. forklift_id_ini=forklift_id_ini+1;
  149. }
  150. if(result.id==5)//当类别数等于人的时候
  151. {
  152. result.unload_car_id=unload_car_id_ini;//当人数等于
  153. unload_car_id_ini=unload_car_id_ini+1;
  154. }
  155. if(result.id==6)//当类别数等于人的时候
  156. {
  157. result.load_car_id=load_car_id_ini;//当人数等于
  158. load_car_id_ini=load_car_id_ini+1;
  159. }
  160. if(result.id==7)//当类别数等于人的时候
  161. {
  162. result.private_car_id=car_private_id_ini;//当人数等于
  163. car_private_id_ini=car_private_id_ini+1;
  164. }
  165. }
  166. ship_num=ship_id_ini;
  167. car_trucks_num=trucks_id_ini;
  168. person_num=person_id_ini;
  169. stacking_area_num=stacking_id_ini;
  170. car_forklift_num=forklift_id_ini ;//总车数
  171. unload_car_num=unload_car_id_ini;//总船数
  172. load_car_num=load_car_id_ini;//总人数
  173. car_private_num=car_private_id_ini;//总车数
  174. if (output.size())
  175. return true;
  176. else
  177. return false;
  178. }//这个括号是最后
  179. void yolo::drawPred(Mat &img, vector<Output> result, vector<Scalar> color)
  180. {
  181. for (int i = 0; i < result.size(); i++)
  182. {
  183. int left, top;
  184. left = result[i].box.x;
  185. top = result[i].box.y;
  186. int color_num = i;
  187. rectangle(img, result[i].box, color[result[i].id], 2, 8);
  188. // string label = className[result[i].id] + ":" + to_string(result[i].confidence)+" id:"+to_string(result[i].person_id);
  189. string label;
  190. if(result[i].id==0)
  191. {
  192. label = className[result[i].id] ;
  193. }
  194. if(result[i].id==1)
  195. {
  196. label = className[result[i].id] ;
  197. }
  198. if(result[i].id==2)
  199. {
  200. label = className[result[i].id] ;
  201. }
  202. if(result[i].id==3)
  203. {
  204. label = className[result[i].id] ;
  205. }
  206. if(result[i].id==4)
  207. {
  208. label = className[result[i].id] ;
  209. }
  210. if(result[i].id==5)
  211. {
  212. label = className[result[i].id] ;
  213. }
  214. if(result[i].id==6)
  215. {
  216. label = className[result[i].id] ;
  217. }
  218. if(result[i].id==7)
  219. {
  220. label = className[result[i].id];
  221. }
  222. int baseLine;
  223. Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
  224. top = max(top, labelSize.height);
  225. //rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);
  226. putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
  227. }
  228. //imshow("res", img);
  229. //imwrite("./result.jpg", img);
  230. //waitKey();
  231. //destroyAllWindows();
  232. }
  233. //这个是针对悍马的画框
  234. void yolo::drawRect(cv::Mat &img, yolo::Output_max_confidence result)
  235. {
  236. int left, top;
  237. left = result.box.x;
  238. top = result.box.y;
  239. rectangle(img, result.box,Scalar(0,0,255) , 2, 8);
  240. // string label = className[result[i].id] + ":" + to_string(result[i].confidence)+" id:"+to_string(result[i].person_id);
  241. string label;
  242. if(result.id==0)
  243. {
  244. label = className[result.id];
  245. }
  246. int baseLine;
  247. Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
  248. top = max(top, labelSize.height);
  249. //rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);
  250. putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 2,Scalar(0,0,255), 2);
  251. }
  252. float yolo::findMax(std::vector<float> vec) {
  253. float max = -999;
  254. for (auto v : vec) {
  255. if (max < v) max = v;
  256. }
  257. return max;
  258. }
  259. int yolo::getPositionOfMax(std::vector<float> vec, int max) {
  260. auto distance = find(vec.begin(), vec.end(), max);
  261. return distance - vec.begin();
  262. }
  263. //返回一个最大置信度的框
  264. yolo::Output_max_confidence yolo::get_only_one_max_confidence(std::vector<Output> result)
  265. {
  266. std::vector<float>confidence;
  267. for (int i = 0; i < result.size(); i++)
  268. {
  269. confidence.push_back(result.at(i).confidence);
  270. // cout<<"result.at(i).confidence"<<result.at(i).confidence<<endl;
  271. }
  272. float maxConfidence=findMax(confidence);
  273. int position = result.size()-getPositionOfMax(confidence, maxConfidence);
  274. // cout<<"max_confidengce"<<maxConfidence<<"position:"<<position<<endl;
  275. Output_max_confidence o_m_c;
  276. o_m_c.confidence=maxConfidence;
  277. o_m_c.id=position;
  278. o_m_c.box=result.at(position).box;
  279. return o_m_c ;
  280. }
检测的调用代码测试案例

这段调用的例子,只要把frame 改成你们自己的图片即可

  1. yolo test; //创建yolo类
  2. cv::dnn::Net net; //创建yolo网络
  3. vector< cv::Scalar> color;//Bounding Box颜色
  4. QString Filename_onnx="quanjingbest.onnx";
  5. cv::String filename_onnx=Filename_onnx.toStdString();
  6. vector<yolo::Output>result_video;
  7. test.readModel(net,filename_onnx,false);
  8. for (int i = 0; i < 80; i++) {
  9. int b = rand() % 256;
  10. int g = rand() % 256;
  11. int r = rand() % 256;
  12. color.push_back( cv::Scalar(b, g, r));
  13. }
  14. cv::Mat frame=cv::imread("D://1.jpg");
  15. if(test.Detect(frame, net, result_video)) //调用YOLO模型检测
  16. test.drawPred(frame, result_video, color);
  17. cv::imshow("a",frame);
  18. cv::waitKey(1);

4:分割的主要代码

YoloSeg.h
  1. #ifndef YOLO_SEG_H
  2. #define YOLO_SEG_H
  3. #pragma once
  4. #include<iostream>
  5. #include<opencv2/opencv.hpp>
  6. #include "yolov5_seg_utils.h"
  7. class YoloSeg {
  8. public:
  9. YoloSeg() {
  10. }
  11. ~YoloSeg() {}
  12. /** \brief Read onnx-model
  13. * \param[out] read onnx file into cv::dnn::Net
  14. * \param[in] modelPath:onnx-model path
  15. * \param[in] isCuda:if true and opencv built with CUDA(cmake),use OpenCV-GPU,else run it on cpu.
  16. */
  17. bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
  18. /** \brief detect.
  19. * \param[in] srcImg:a 3-channels image.
  20. * \param[out] output:detection results of input image.
  21. */
  22. bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputSeg>& output);
  23. #if(defined YOLO_P6 && YOLO_P6==true)
  24. const int _netWidth = 1280; //ONNX图片输入宽度
  25. const int _netHeight = 1280; //ONNX图片输入高度
  26. const int _segWidth = 320; //_segWidth=_netWidth/mask_ratio
  27. const int _segHeight = 320;
  28. const int _segChannels = 32;
  29. #else
  30. const int _netWidth = 640; //ONNX图片输入宽度
  31. const int _netHeight = 640; //ONNX图片输入高度
  32. const int _segWidth = 160; //_segWidth=_netWidth/mask_ratio
  33. const int _segHeight = 160;
  34. const int _segChannels = 32;
  35. #endif // YOLO_P6
  36. float _classThreshold = 0.25;
  37. float _nmsThreshold = 0.45;
  38. float _maskThreshold = 0.5;
  39. public:
  40. std::vector<std::string> _className = { "steel"};//类别名,换成自己的模型需要修改此项
  41. };
  42. #endif // YOLO_SEG_H
YoloSeg.cpp
  1. #include "yolo_seg.h"
  2. #include"yolo_seg.h"
  3. using namespace std;
  4. using namespace cv;
  5. using namespace cv::dnn;
  6. bool YoloSeg::ReadModel(Net& net, string& netPath, bool isCuda = false) {
  7. try {
  8. net = readNet(netPath);
  9. #if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0
  10. net.enableWinograd(false); //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080
  11. //net.enableWinograd(true); //If your CPU supports AVX2, you can set it true to speed up
  12. #endif
  13. }
  14. catch (const std::exception&) {
  15. return false;
  16. }
  17. if (isCuda) {
  18. //cuda
  19. net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
  20. net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16
  21. }
  22. else {
  23. //cpu
  24. cout << "Inference device: CPU" << endl;
  25. net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
  26. net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
  27. }
  28. return true;
  29. }
  30. bool YoloSeg::Detect(Mat& srcImg, Net& net, vector<OutputSeg>& output) {
  31. Mat blob;
  32. output.clear();
  33. int col = srcImg.cols;
  34. int row = srcImg.rows;
  35. Mat netInputImg;
  36. Vec4d params;
  37. LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));
  38. blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);
  39. //**************************************************************************************************************************************************/
  40. //如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
  41. // If there is no problem with other settings, but results are a lot different from Python-onnx , you can try to use the following two sentences
  42. //
  43. //$ blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
  44. //$ blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
  45. //****************************************************************************************************************************************************/
  46. net.setInput(blob);
  47. std::vector<cv::Mat> net_output_img;
  48. //*********************************************************************************************************************************
  49. //net.forward(net_output_img, net.getUnconnectedOutLayersNames());
  50. //opencv4.5.x和4.6.x这里输出不一致,推荐使用下面的固定名称输出
  51. // 如果使用net.forward(net_output_img, net.getUnconnectedOutLayersNames()),需要确认下net.getUnconnectedOutLayersNames()返回值中output0在前,output1在后,否者出错
  52. //
  53. // The outputs of opencv4.5.x and 4.6.x are inconsistent.Please make sure "output0" is in front of "output1" if you use net.forward(net_output_img, net.getUnconnectedOutLayersNames())
  54. //*********************************************************************************************************************************
  55. vector<string> output_layer_names{ "output0","output1" };
  56. net.forward(net_output_img, output_layer_names); //获取output的输出
  57. std::vector<int> class_ids;//结果id数组
  58. std::vector<float> confidences;//结果每个id对应置信度数组
  59. std::vector<cv::Rect> boxes;//每个id矩形框
  60. std::vector<vector<float>> picked_proposals; //output0[:,:, 5 + _className.size():net_width]===> for mask
  61. int net_width = _className.size() + 5 + _segChannels;// 80 + 5 + 32 = 117
  62. int out0_width= net_output_img[0].size[2];
  63. // assert(net_width == out0_width, "Error Wrong number of _className or _segChannels"); //模型类别数目不对或者_segChannels设置错误
  64. int net_height = net_output_img[0].size[1];// 25200
  65. float* pdata = (float*)net_output_img[0].data;
  66. for (int r = 0; r < net_height; r++) { //lines
  67. float box_score = pdata[4];
  68. if (box_score >= _classThreshold) {
  69. cv::Mat scores(1, _className.size(), CV_32FC1, pdata + 5); // 可是 后面不只是有80个类别的概率;
  70. Point classIdPoint;
  71. double max_class_socre;
  72. minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
  73. max_class_socre = (float)max_class_socre;
  74. if (max_class_socre >= _classThreshold) {
  75. vector<float> temp_proto(pdata + 5 + _className.size(), pdata + net_width); // Mask Coeffcients,mask的掩码系数
  76. picked_proposals.push_back(temp_proto);
  77. //rect [x,y,w,h]
  78. float x = (pdata[0] - params[2]) / params[0]; //x
  79. float y = (pdata[1] - params[3]) / params[1]; //y
  80. float w = pdata[2] / params[0]; //w
  81. float h = pdata[3] / params[1]; //h
  82. int left = MAX(int(x - 0.5 * w + 0.5), 0);
  83. int top = MAX(int(y - 0.5 * h + 0.5), 0);
  84. class_ids.push_back(classIdPoint.x);
  85. confidences.push_back(max_class_socre * box_score);
  86. boxes.push_back(Rect(left, top, int(w + 0.5), int(h + 0.5)));
  87. }
  88. }
  89. pdata += net_width;//下一行
  90. }
  91. //NMS
  92. vector<int> nms_result;
  93. cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
  94. std::vector<vector<float>> temp_mask_proposals;
  95. Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
  96. for (int i = 0; i < nms_result.size(); ++i) {
  97. int idx = nms_result[i];
  98. OutputSeg result;
  99. result.id = class_ids[idx];
  100. result.confidence = confidences[idx];
  101. result.box = boxes[idx] & holeImgRect;
  102. temp_mask_proposals.push_back(picked_proposals[idx]);
  103. output.push_back(result);
  104. }
  105. MaskParams mask_params;
  106. mask_params.params = params;
  107. mask_params.srcImgShape = srcImg.size();
  108. for (int i = 0; i < temp_mask_proposals.size(); ++i) {
  109. GetMask2(Mat(temp_mask_proposals[i]).t(), net_output_img[1], output[i], mask_params); // 注意这里是net_output_img[1],为原型mask
  110. }
  111. //******************** ****************
  112. // 老版本的方案,如果上面GetMask2出错,建议使用这个。
  113. // If the GetMask2() still reports errors , it is recommended to use GetMask().
  114. // Mat mask_proposals;
  115. //for (int i = 0; i < temp_mask_proposals.size(); ++i)
  116. // mask_proposals.push_back(Mat(temp_mask_proposals[i]).t());
  117. //GetMask(mask_proposals, net_output_img[1], output, mask_params);
  118. //*****************************************************/
  119. if (output.size())
  120. return true;
  121. else
  122. return false;
  123. }
yolov5_seg_utils.h
  1. #ifndef YOLOV5_SEG_UTILS_H
  2. #define YOLOV5_SEG_UTILS_H
  3. #pragma once
  4. #include<iostream>
  5. #include <numeric>
  6. #include<opencv2/opencv.hpp>
  7. #define YOLO_P6 false //是否使用P6模型
  8. #define ORT_OLD_VISON 12 //ort1.12.0 之前的版本为旧版本API
  9. struct OutputSeg {
  10. int id; //结果类别id
  11. float confidence; //结果置信度
  12. cv::Rect box; //矩形框
  13. cv::Mat boxMask; //矩形框内mask,节省内存空间和加快速度
  14. };
  15. struct MaskParams {
  16. int segChannels = 32;
  17. int segWidth = 160;
  18. int segHeight = 160;
  19. int netWidth = 640;
  20. int netHeight = 640;
  21. float maskThreshold = 0.5;
  22. cv::Size srcImgShape;
  23. cv::Vec4d params;
  24. };
  25. bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize);
  26. void DrawPred(cv::Mat& img, std::vector<OutputSeg> result, std::vector<std::string> classNames, std::vector<cv::Scalar> color);
  27. void LetterBox(const cv::Mat& image, cv::Mat& outImage,
  28. cv::Vec4d& params, //[ratio_x,ratio_y,dw,dh]
  29. const cv::Size& newShape = cv::Size(640, 640),
  30. bool autoShape = false,
  31. bool scaleFill = false,
  32. bool scaleUp = true,
  33. int stride = 32,
  34. const cv::Scalar& color = cv::Scalar(114, 114, 114));
  35. void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams);
  36. void GetMask2(const cv::Mat& maskProposals, const cv::Mat& maskProtos, OutputSeg& output, const MaskParams& maskParams);
  37. #endif // YOLOV5_SEG_UTILS_H
 yolov5_seg_utils.cpp
  1. #include "yolov5_seg_utils.h"
  2. #pragma once
  3. #include "yolov5_seg_utils.h"
  4. using namespace cv;
  5. using namespace std;
  6. bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize) {
  7. if (netHeight % netStride[strideSize - 1] != 0 || netWidth % netStride[strideSize - 1] != 0)
  8. {
  9. cout << "Error:_netHeight and _netWidth must be multiple of max stride " << netStride[strideSize - 1] << "!" << endl;
  10. return false;
  11. }
  12. return true;
  13. }
  14. void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,
  15. bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
  16. {
  17. if (false) {
  18. int maxLen = MAX(image.rows, image.cols);
  19. outImage = Mat::zeros(Size(maxLen, maxLen), CV_8UC3);
  20. image.copyTo(outImage(Rect(0, 0, image.cols, image.rows)));
  21. params[0] = 1;
  22. params[1] = 1;
  23. params[3] = 0;
  24. params[2] = 0;
  25. }
  26. cv::Size shape = image.size();
  27. float r = std::min((float)newShape.height / (float)shape.height,
  28. (float)newShape.width / (float)shape.width);
  29. if (!scaleUp)
  30. r = std::min(r, 1.0f);
  31. float ratio[2]{ r, r };
  32. int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };
  33. auto dw = (float)(newShape.width - new_un_pad[0]);
  34. auto dh = (float)(newShape.height - new_un_pad[1]);
  35. if (autoShape)
  36. {
  37. dw = (float)((int)dw % stride);
  38. dh = (float)((int)dh % stride);
  39. }
  40. else if (scaleFill)
  41. {
  42. dw = 0.0f;
  43. dh = 0.0f;
  44. new_un_pad[0] = newShape.width;
  45. new_un_pad[1] = newShape.height;
  46. ratio[0] = (float)newShape.width / (float)shape.width;
  47. ratio[1] = (float)newShape.height / (float)shape.height;
  48. }
  49. dw /= 2.0f;
  50. dh /= 2.0f;
  51. if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1])
  52. {
  53. cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));
  54. }
  55. else {
  56. outImage = image.clone();
  57. }
  58. int top = int(std::round(dh - 0.1f));
  59. int bottom = int(std::round(dh + 0.1f));
  60. int left = int(std::round(dw - 0.1f));
  61. int right = int(std::round(dw + 0.1f));
  62. params[0] = ratio[0];
  63. params[1] = ratio[1];
  64. params[2] = left;
  65. params[3] = top;
  66. cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
  67. }
  68. void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams) {
  69. //cout << maskProtos.size << endl;
  70. int seg_channels = maskParams.segChannels;
  71. int net_width = maskParams.netWidth;
  72. int seg_width = maskParams.segWidth;
  73. int net_height = maskParams.netHeight;
  74. int seg_height = maskParams.segHeight;
  75. float mask_threshold = maskParams.maskThreshold;
  76. Vec4f params = maskParams.params;
  77. Size src_img_shape = maskParams.srcImgShape;
  78. Mat protos = maskProtos.reshape(0, { seg_channels,seg_width * seg_height });
  79. Mat matmul_res = (maskProposals * protos).t();
  80. Mat masks = matmul_res.reshape(output.size(), { seg_width,seg_height });
  81. vector<Mat> maskChannels;
  82. split(masks, maskChannels);
  83. for (int i = 0; i < output.size(); ++i) {
  84. Mat dest, mask;
  85. //sigmoid
  86. cv::exp(-maskChannels[i], dest);
  87. dest = 1.0 / (1.0 + dest);
  88. Rect roi(int(params[2] / net_width * seg_width), int(params[3] / net_height * seg_height), int(seg_width - params[2] / 2), int(seg_height - params[3] / 2));
  89. dest = dest(roi);
  90. resize(dest, mask, src_img_shape, INTER_NEAREST);
  91. //crop
  92. Rect temp_rect = output[i].box;
  93. mask = mask(temp_rect) > mask_threshold;
  94. output[i].boxMask = mask;
  95. }
  96. }
  97. void GetMask2(const Mat& maskProposals, const Mat& mask_protos, OutputSeg& output, const MaskParams& maskParams) {
  98. int seg_channels = maskParams.segChannels;
  99. int net_width = maskParams.netWidth;
  100. int seg_width = maskParams.segWidth;
  101. int net_height = maskParams.netHeight;
  102. int seg_height = maskParams.segHeight;
  103. float mask_threshold = maskParams.maskThreshold;
  104. Vec4f params = maskParams.params;
  105. Size src_img_shape = maskParams.srcImgShape;
  106. Rect temp_rect = output.box;
  107. // 把已经到原图的检测框坐标信息 映射到 获得mask原型分支的输入尺寸上【160, 160
  108. int rang_x = floor((temp_rect.x * params[0] + params[2]) / net_width * seg_width);
  109. int rang_y = floor((temp_rect.y * params[1] + params[3]) / net_height * seg_height);
  110. int rang_w = ceil(((temp_rect.x + temp_rect.width) * params[0] + params[2]) / net_width * seg_width) - rang_x;
  111. int rang_h = ceil(((temp_rect.y + temp_rect.height) * params[0] + params[3]) / net_width * seg_height) - rang_y;
  112. //
  113. rang_w = MAX(rang_w, 1);
  114. rang_h = MAX(rang_h, 1);
  115. if (rang_x + rang_w > seg_width){
  116. if (seg_width - rang_x > 0)
  117. rang_w =seg_width -rang_x;
  118. else
  119. rang_x -= 1;
  120. }
  121. if (rang_y + rang_h > seg_height) {
  122. if (seg_height - rang_y > 0)
  123. rang_h = seg_height - rang_y;
  124. else
  125. rang_y -= 1;
  126. }
  127. vector<Range> roi_ranges;
  128. roi_ranges.push_back(Range(0,1));
  129. roi_ranges.push_back(Range::all());
  130. roi_ranges.push_back(Range(rang_y, rang_h+rang_y));
  131. roi_ranges.push_back(Range(rang_x, rang_w+rang_x));
  132. // 裁剪mask原型
  133. Mat temp_mask_protos = mask_protos(roi_ranges).clone(); // 剪裁原型,保存检测框内部的原型,其余位置清零, 以此来获得感兴趣区域(roi)
  134. Mat protos = temp_mask_protos.reshape(0, { seg_channels, rang_w*rang_h});// 检测至检测框大小?
  135. // mask系数与mask原型做矩阵乘法
  136. Mat matmul_res = (maskProposals * protos).t(); // mask系数【1,32】 与 mask原型【32, h*w】进行矩阵相称
  137. Mat masks_feature = matmul_res.reshape(1,{rang_h, rang_w}); //1,h,w】
  138. Mat dest, mask;
  139. // sigmod
  140. cv::exp(-masks_feature, dest);
  141. dest = 1.0 / (1.0 + dest);
  142. // 检测框坐标 映射到 原图尺寸
  143. int left = floor((net_width / seg_width * rang_x - params[2]) / params[0]);
  144. int top = floor((net_width / seg_height * rang_y - params[3]) / params[1]);
  145. int width = ceil(net_width / seg_height * rang_w / params[0]);
  146. int height = ceil(net_height / seg_height * rang_h / params[1]);
  147. // 检测框mask缩放到原图尺寸
  148. resize(dest, mask, Size(width, height), INTER_NEAREST);
  149. // 阈值化
  150. mask = mask(temp_rect - Point(left, top)) > mask_threshold;
  151. output.boxMask = mask;
  152. }
  153. void DrawPred(Mat& img, vector<OutputSeg> result, std::vector<std::string> classNames, vector<Scalar> color) {
  154. Mat mask = img.clone();
  155. for (int i=0; i< result.size(); i++){
  156. int left, top;
  157. left = result[i].box.x;
  158. top = result[i].box.y;
  159. int color_num =i;
  160. // 目标画框
  161. rectangle(img, result[i].box, color[result[i].id], 2, 8);
  162. // 目标mask,这里非目标像素值为0
  163. mask(result[i].box).setTo(color[result[i].id], result[i].boxMask);
  164. string label = classNames[result[i].id] + ":" + to_string(result[i].confidence);
  165. // 框左上角打印信息
  166. int baseLine;
  167. Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
  168. top = max(top, labelSize.height);
  169. putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, color[result[i].id], 2);
  170. }
  171. addWeighted(img, 0.5, mask, 0.5, 0, img);
  172. }
分割的调用代码测试案例
  1. void frmMain::test_yoloseg()
  2. {
  3. string model_path = "20231001segquanjing.onnx";
  4. YoloSeg test;
  5. Net net;
  6. if (test.ReadModel(net, model_path, true)) {
  7. cout << "read net ok!" << endl;
  8. }
  9. else {
  10. return ;
  11. }
  12. vector<OutputSeg> result;
  13. cv::Mat img_seg_test=cv::imread("E:/data_seg/quanjingCameraPicture2/1/segdata2278.jpg");
  14. bool find = test.Detect(img_seg_test, net, result);
  15. if (find) {
  16. DrawPred(img_seg_test, result, test._className, color);
  17. }
  18. else {
  19. cout << "Detect Failed!"<<endl;
  20. }
  21. string label = "steel:" ; //ms
  22. putText(img_seg_test, label, Point(30,30), FONT_HERSHEY_SIMPLEX,0.5, Scalar(0,0,255), 2, 8);
  23. QPixmap img_test_xmap= my_publiction.cvMatToQPixmap(img_seg_test);
  24. // 设置QLabel的最小尺寸
  25. ui->lab1->setMinimumSize(600, 600);
  26. ui->lab1->setScaledContents(true);
  27. img_test_xmap = img_test_xmap.scaled( ui->lab1->width(), ui->lab1->height(), Qt::KeepAspectRatio,Qt::SmoothTransformation); // 将图像缩放到QLabel的大小
  28. ui->lab1->setPixmap(img_test_xmap);
  29. // imshow("result", img_seg_test);
  30. }

 分割的效果图如下:

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

闽ICP备14008679号