当前位置:   article > 正文

yolov8 实例分割 onnx runtime C++部署_opencv onnxruntime yolov8

opencv onnxruntime yolov8

如果第一次部署分割,建议先看这篇博客:

YOLOv5 实例分割 用 OPenCV DNN C++ 部署_爱钓鱼的歪猴的博客-CSDN博客

目录

Pre

一、OpenCV DNN C++ 部署

二、ONNX RUNTIME C++ 部署

yolov8_seg_utils.h

yolov8_seg_utils.cpp

yolov8_seg_onnx.h

yolov8_seg_onnx.cpp

main.cpp

CMakelist.txt


Pre

一定要知道,yolov8的输出与Yolov5 7.0 实例分割的输出不一样,

output0: float32[1,116,8400]。 116是4个box坐标信息+80个类别概率+32个mask系数

output1: float32[1,32,160,160]。一张图片一组mask原型。这个mask原型是相对于整个图像的。

一、OpenCV DNN C++ 部署

 所以output0需要装置一下,117->116,其他的与yolov5实例分割没啥区别:

  1. net.setInput(blob);
  2. std::vector<cv::Mat> net_output_img;
  3. vector<string> output_layer_names{ "output0","output1" };
  4. net.forward(net_output_img, output_layer_names); //get outputs
  5. std::vector<int> class_ids;// res-class_id
  6. std::vector<float> confidences;// res-conf
  7. std::vector<cv::Rect> boxes;// res-box
  8. std::vector<vector<float>> picked_proposals; //output0[:,:, 4 + _className.size():net_width]===> for mask
  9. int net_width = _className.size() + 4 + _segChannels;
  10. //转置
  11. Mat output0=Mat( Size(net_output_img[0].size[2], net_output_img[0].size[1]), CV_32F, (float*)net_output_img[0].data).t(); //[bs,116,8400]=>[bs,8400,116]
  12. int rows = output0.rows;
  13. float* pdata = (float*)output0.data;
  14. for (int r = 0; r < rows; ++r) {
  15. cv::Mat scores(1, _className.size(), CV_32FC1, pdata + 4);
  16. Point classIdPoint;
  17. double max_class_socre;
  18. minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
  19. max_class_socre = (float)max_class_socre;
  20. if (max_class_socre >= _classThreshold) {
  21. vector<float> temp_proto(pdata + 4 + _className.size(), pdata + net_width);
  22. picked_proposals.push_back(temp_proto);
  23. //rect [x,y,w,h]
  24. float x = (pdata[0] - params[2]) / params[0];
  25. float y = (pdata[1] - params[3]) / params[1];
  26. float w = pdata[2] / params[0];
  27. float h = pdata[3] / params[1];
  28. int left = MAX(int(x - 0.5 * w + 0.5), 0);
  29. int top = MAX(int(y - 0.5 * h + 0.5), 0);
  30. class_ids.push_back(classIdPoint.x);
  31. confidences.push_back(max_class_socre);
  32. boxes.push_back(Rect(left, top, int(w + 0.5), int(h + 0.5)));
  33. }
  34. pdata += net_width;//next line
  35. }
  36. //NMS
  37. vector<int> nms_result;
  38. NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
  39. std::vector<vector<float>> temp_mask_proposals;
  40. Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);
  41. for (int i = 0; i < nms_result.size(); ++i) {
  42. int idx = nms_result[i];
  43. OutputSeg result;
  44. result.id = class_ids[idx];
  45. result.confidence = confidences[idx];
  46. result.box = boxes[idx] & holeImgRect;
  47. temp_mask_proposals.push_back(picked_proposals[idx]);
  48. output.push_back(result);
  49. }
  50. MaskParams mask_params;
  51. mask_params.params = params;
  52. mask_params.srcImgShape = srcImg.size();
  53. for (int i = 0; i < temp_mask_proposals.size(); ++i) {
  54. GetMask2(Mat(temp_mask_proposals[i]).t(), net_output_img[1], output[i], mask_params);
  55. }

但是我read模型的时候报错:ERROR during processing node with 2 inputs and 1 outputs: [Reshape]:(/model.22/dfl/Reshape_output_0) from domain='ai.onnx'

应该是OpenCV版本需要升级到4.7。之前部署检测的时候也报这个错:yolov8 OpenCV DNN 部署 推理报错_爱钓鱼的歪猴的博客-CSDN博客

我不想升级OpenCV了,所以选择用ONNX RUNTIME 部署

二、ONNX RUNTIME C++ 部署

yolov8n-seg  CPU 推理耗时150ms左右, 速度比yolov5n-seg慢一点(100ms),但是检测效果好一些,具体来说,同样是我穿上这件外套,yolov8n-seg给出的置信度更高!

yolov8_seg_utils.h

  1. #pragma once
  2. #include<iostream>
  3. #include <numeric>
  4. #include<opencv2/opencv.hpp>
  5. #define YOLO_P6 false //是否使用P6模型
  6. #define ORT_OLD_VISON 12 //ort1.12.0 之前的版本为旧版本API
  7. struct OutputSeg {
  8. int id; //结果类别id
  9. float confidence; //结果置信度
  10. cv::Rect box; //矩形框
  11. cv::Mat boxMask; //矩形框内mask,节省内存空间和加快速度
  12. };
  13. struct MaskParams {
  14. int segChannels = 32;
  15. int segWidth = 160;
  16. int segHeight = 160;
  17. int netWidth = 640;
  18. int netHeight = 640;
  19. float maskThreshold = 0.5;
  20. cv::Size srcImgShape;
  21. cv::Vec4d params;
  22. };
  23. bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize);
  24. void DrawPred(cv::Mat& img, std::vector<OutputSeg> result, std::vector<std::string> classNames, std::vector<cv::Scalar> color);
  25. void LetterBox(const cv::Mat& image, cv::Mat& outImage,
  26. cv::Vec4d& params, //[ratio_x,ratio_y,dw,dh]
  27. const cv::Size& newShape = cv::Size(640, 640),
  28. bool autoShape = false,
  29. bool scaleFill = false,
  30. bool scaleUp = true,
  31. int stride = 32,
  32. const cv::Scalar& color = cv::Scalar(114, 114, 114));
  33. void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams);
  34. void GetMask2(const cv::Mat& maskProposals, const cv::Mat& maskProtos, OutputSeg& output, const MaskParams& maskParams);

yolov8_seg_utils.cpp

  1. #pragma once
  2. #include "yolov8_seg_utils.h"
  3. using namespace cv;
  4. using namespace std;
  5. bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize) {
  6. if (netHeight % netStride[strideSize - 1] != 0 || netWidth % netStride[strideSize - 1] != 0)
  7. {
  8. cout << "Error:_netHeight and _netWidth must be multiple of max stride " << netStride[strideSize - 1] << "!" << endl;
  9. return false;
  10. }
  11. return true;
  12. }
  13. void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,
  14. bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
  15. {
  16. if (false) {
  17. int maxLen = MAX(image.rows, image.cols);
  18. outImage = Mat::zeros(Size(maxLen, maxLen), CV_8UC3);
  19. image.copyTo(outImage(Rect(0, 0, image.cols, image.rows)));
  20. params[0] = 1;
  21. params[1] = 1;
  22. params[3] = 0;
  23. params[2] = 0;
  24. }
  25. cv::Size shape = image.size();
  26. float r = std::min((float)newShape.height / (float)shape.height,
  27. (float)newShape.width / (float)shape.width);
  28. if (!scaleUp)
  29. r = std::min(r, 1.0f);
  30. float ratio[2]{ r, r };
  31. int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };
  32. auto dw = (float)(newShape.width - new_un_pad[0]);
  33. auto dh = (float)(newShape.height - new_un_pad[1]);
  34. if (autoShape)
  35. {
  36. dw = (float)((int)dw % stride);
  37. dh = (float)((int)dh % stride);
  38. }
  39. else if (scaleFill)
  40. {
  41. dw = 0.0f;
  42. dh = 0.0f;
  43. new_un_pad[0] = newShape.width;
  44. new_un_pad[1] = newShape.height;
  45. ratio[0] = (float)newShape.width / (float)shape.width;
  46. ratio[1] = (float)newShape.height / (float)shape.height;
  47. }
  48. dw /= 2.0f;
  49. dh /= 2.0f;
  50. if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1])
  51. {
  52. cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));
  53. }
  54. else {
  55. outImage = image.clone();
  56. }
  57. int top = int(std::round(dh - 0.1f));
  58. int bottom = int(std::round(dh + 0.1f));
  59. int left = int(std::round(dw - 0.1f));
  60. int right = int(std::round(dw + 0.1f));
  61. params[0] = ratio[0];
  62. params[1] = ratio[1];
  63. params[2] = left;
  64. params[3] = top;
  65. cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
  66. }
  67. void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams) {
  68. //cout << maskProtos.size << endl;
  69. int seg_channels = maskParams.segChannels;
  70. int net_width = maskParams.netWidth;
  71. int seg_width = maskParams.segWidth;
  72. int net_height = maskParams.netHeight;
  73. int seg_height = maskParams.segHeight;
  74. float mask_threshold = maskParams.maskThreshold;
  75. Vec4f params = maskParams.params;
  76. Size src_img_shape = maskParams.srcImgShape;
  77. Mat protos = maskProtos.reshape(0, { seg_channels,seg_width * seg_height });
  78. Mat matmul_res = (maskProposals * protos).t();
  79. Mat masks = matmul_res.reshape(output.size(), { seg_width,seg_height });
  80. vector<Mat> maskChannels;
  81. split(masks, maskChannels);
  82. for (int i = 0; i < output.size(); ++i) {
  83. Mat dest, mask;
  84. //sigmoid
  85. cv::exp(-maskChannels[i], dest);
  86. dest = 1.0 / (1.0 + dest);
  87. 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));
  88. dest = dest(roi);
  89. resize(dest, mask, src_img_shape, INTER_NEAREST);
  90. //crop
  91. Rect temp_rect = output[i].box;
  92. mask = mask(temp_rect) > mask_threshold;
  93. output[i].boxMask = mask;
  94. }
  95. }
  96. void GetMask2(const Mat& maskProposals, const Mat& mask_protos, OutputSeg& output, const MaskParams& maskParams) {
  97. int seg_channels = maskParams.segChannels;
  98. int net_width = maskParams.netWidth;
  99. int seg_width = maskParams.segWidth;
  100. int net_height = maskParams.netHeight;
  101. int seg_height = maskParams.segHeight;
  102. float mask_threshold = maskParams.maskThreshold;
  103. Vec4f params = maskParams.params;
  104. Size src_img_shape = maskParams.srcImgShape;
  105. Rect temp_rect = output.box;
  106. //crop from mask_protos
  107. int rang_x = floor((temp_rect.x * params[0] + params[2]) / net_width * seg_width);
  108. int rang_y = floor((temp_rect.y * params[1] + params[3]) / net_height * seg_height);
  109. int rang_w = ceil(((temp_rect.x + temp_rect.width) * params[0] + params[2]) / net_width * seg_width) - rang_x;
  110. int rang_h = ceil(((temp_rect.y + temp_rect.height) * params[1] + params[3]) / net_height * seg_height) - rang_y;
  111. //如果下面的 mask_protos(roi_rangs).clone()位置报错,说明你的output.box数据不对,或者矩形框就1个像素的,开启下面的注释部分防止报错。
  112. rang_w = MAX(rang_w, 1);
  113. rang_h = MAX(rang_h, 1);
  114. if (rang_x + rang_w > seg_width) {
  115. if (seg_width - rang_x > 0)
  116. rang_w = seg_width - rang_x;
  117. else
  118. rang_x -= 1;
  119. }
  120. if (rang_y + rang_h > seg_height) {
  121. if (seg_height - rang_y > 0)
  122. rang_h = seg_height - rang_y;
  123. else
  124. rang_y -= 1;
  125. }
  126. vector<Range> roi_rangs;
  127. roi_rangs.push_back(Range(0, 1));
  128. roi_rangs.push_back(Range::all());
  129. roi_rangs.push_back(Range(rang_y, rang_h + rang_y));
  130. roi_rangs.push_back(Range(rang_x, rang_w + rang_x));
  131. //crop
  132. Mat temp_mask_protos = mask_protos(roi_rangs).clone();
  133. Mat protos = temp_mask_protos.reshape(0, { seg_channels,rang_w * rang_h });
  134. Mat matmul_res = (maskProposals * protos).t();
  135. Mat masks_feature = matmul_res.reshape(1, { rang_h,rang_w });
  136. Mat dest, mask;
  137. //sigmoid
  138. cv::exp(-masks_feature, dest);
  139. dest = 1.0 / (1.0 + dest);
  140. int left = floor((net_width / seg_width * rang_x - params[2]) / params[0]);
  141. int top = floor((net_height / seg_height * rang_y - params[3]) / params[1]);
  142. int width = ceil(net_width / seg_width * rang_w / params[0]);
  143. int height = ceil(net_height / seg_height * rang_h / params[1]);
  144. resize(dest, mask, Size(width, height), INTER_NEAREST);
  145. mask = mask(temp_rect - Point(left, top)) > mask_threshold;
  146. output.boxMask = mask;
  147. }
  148. void DrawPred(Mat& img, vector<OutputSeg> result, std::vector<std::string> classNames, vector<Scalar> color) {
  149. Mat mask = img.clone();
  150. for (int i = 0; i < result.size(); i++) {
  151. int left, top;
  152. left = result[i].box.x;
  153. top = result[i].box.y;
  154. int color_num = i;
  155. rectangle(img, result[i].box, color[result[i].id], 2, 8);
  156. if(result[i].boxMask.rows&& result[i].boxMask.cols>0)
  157. mask(result[i].box).setTo(color[result[i].id], result[i].boxMask);
  158. string label = classNames[result[i].id] + ":" + to_string(result[i].confidence);
  159. int baseLine;
  160. Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
  161. top = max(top, labelSize.height);
  162. //rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);
  163. putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
  164. }
  165. addWeighted(img, 0.5, mask, 0.5, 0, img); //add mask to src
  166. // imshow("1", img);
  167. //imwrite("out.bmp", img);
  168. // waitKey();
  169. //destroyAllWindows();
  170. }

yolov8_seg_onnx.h

  1. #pragma once
  2. #include <iostream>
  3. #include<memory>
  4. #include <opencv2/opencv.hpp>
  5. #include "yolov8_seg_utils.h"
  6. #include<onnxruntime_cxx_api.h>
  7. //#include <tensorrt_provider_factory.h> //if use OrtTensorRTProviderOptionsV2
  8. //#include <onnxruntime_c_api.h>
  9. class Yolov8SegOnnx {
  10. public:
  11. Yolov8SegOnnx() :_OrtMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
  12. ~Yolov8SegOnnx() {};// delete _OrtMemoryInfo;
  13. public:
  14. /** \brief Read onnx-model
  15. * \param[in] modelPath:onnx-model path
  16. * \param[in] isCuda:if true,use Ort-GPU,else run it on cpu.
  17. * \param[in] cudaID:if isCuda==true,run Ort-GPU on cudaID.
  18. * \param[in] warmUp:if isCuda==true,warm up GPU-model.
  19. */
  20. bool ReadModel(const std::string& modelPath, bool isCuda = false, int cudaID = 0, bool warmUp = true);
  21. /** \brief detect.
  22. * \param[in] srcImg:a 3-channels image.
  23. * \param[out] output:detection results of input image.
  24. */
  25. bool OnnxDetect(cv::Mat& srcImg, std::vector<OutputSeg>& output);
  26. /** \brief detect,batch size= _batchSize
  27. * \param[in] srcImg:A batch of images.
  28. * \param[out] output:detection results of input images.
  29. */
  30. bool OnnxBatchDetect(std::vector<cv::Mat>& srcImg, std::vector<std::vector<OutputSeg>>& output);
  31. private:
  32. template <typename T>
  33. T VectorProduct(const std::vector<T>& v)
  34. {
  35. return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
  36. };
  37. int Preprocessing(const std::vector<cv::Mat>& SrcImgs, std::vector<cv::Mat>& OutSrcImgs, std::vector<cv::Vec4d>& params);
  38. #if(defined YOLO_P6 && YOLO_P6==true)
  39. //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 } };
  40. const int _netWidth = 1280; //ONNX图片输入宽度
  41. const int _netHeight = 1280; //ONNX图片输入高度
  42. const int _segWidth = 320; //_segWidth=_netWidth/mask_ratio
  43. const int _segHeight = 320;
  44. const int _segChannels = 32;
  45. #else
  46. //const float _netAnchors[3][6] = { { 10,13, 16,30, 33,23 },{ 30,61, 62,45, 59,119 },{ 116,90, 156,198, 373,326 } };
  47. const int _netWidth = 640; //ONNX-net-input-width
  48. const int _netHeight = 640; //ONNX-net-input-height
  49. const int _segWidth = 160; //_segWidth=_netWidth/mask_ratio
  50. const int _segHeight = 160;
  51. const int _segChannels = 32;
  52. #endif // YOLO_P6
  53. int _batchSize = 1; //if multi-batch,set this
  54. bool _isDynamicShape = false;//onnx support dynamic shape
  55. float _classThreshold = 0.5;
  56. float _nmsThreshold = 0.45;
  57. float _maskThreshold = 0.5;
  58. //ONNXRUNTIME
  59. Ort::Env _OrtEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov5-Seg");
  60. Ort::SessionOptions _OrtSessionOptions = Ort::SessionOptions();
  61. Ort::Session* _OrtSession = nullptr;
  62. Ort::MemoryInfo _OrtMemoryInfo;
  63. #if ORT_API_VERSION < ORT_OLD_VISON
  64. char* _inputName, * _output_name0, * _output_name1;
  65. #else
  66. std::shared_ptr<char> _inputName, _output_name0,_output_name1;
  67. #endif
  68. std::vector<char*> _inputNodeNames; //输入节点名
  69. std::vector<char*> _outputNodeNames;//输出节点名
  70. size_t _inputNodesNum = 0; //输入节点数
  71. size_t _outputNodesNum = 0; //输出节点数
  72. ONNXTensorElementDataType _inputNodeDataType; //数据类型
  73. ONNXTensorElementDataType _outputNodeDataType;
  74. std::vector<int64_t> _inputTensorShape; //输入张量shape
  75. std::vector<int64_t> _outputTensorShape;
  76. std::vector<int64_t> _outputMaskTensorShape;
  77. public:
  78. std::vector<std::string> _className = {
  79. "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
  80. "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
  81. "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
  82. "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
  83. "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
  84. "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
  85. "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
  86. "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
  87. "hair drier", "toothbrush"
  88. };
  89. };

yolov8_seg_onnx.cpp

  1. #include "yolov8_seg_onnx.h"
  2. using namespace std;
  3. using namespace cv;
  4. using namespace cv::dnn;
  5. using namespace Ort;
  6. bool Yolov8SegOnnx::ReadModel(const std::string& modelPath, bool isCuda, int cudaID, bool warmUp) {
  7. if (_batchSize < 1) _batchSize = 1;
  8. try
  9. {
  10. std::vector<std::string> available_providers = GetAvailableProviders();
  11. auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");
  12. if (isCuda && (cuda_available == available_providers.end()))
  13. {
  14. std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
  15. std::cout << "************* Infer model on CPU! *************" << std::endl;
  16. }
  17. else if (isCuda && (cuda_available != available_providers.end()))
  18. {
  19. std::cout << "************* Infer model on GPU! *************" << std::endl;
  20. //#if ORT_API_VERSION < ORT_OLD_VISON
  21. // OrtCUDAProviderOptions cudaOption;
  22. // cudaOption.device_id = cudaID;
  23. // _OrtSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
  24. //#else
  25. // OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(_OrtSessionOptions, cudaID);
  26. //#endif
  27. }
  28. else
  29. {
  30. std::cout << "************* Infer model on CPU! *************" << std::endl;
  31. }
  32. //
  33. _OrtSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
  34. #ifdef _WIN32
  35. std::wstring model_path(modelPath.begin(), modelPath.end());
  36. _OrtSession = new Ort::Session(_OrtEnv, model_path.c_str(), _OrtSessionOptions);
  37. #else
  38. _OrtSession = new Ort::Session(_OrtEnv, modelPath.c_str(), _OrtSessionOptions);
  39. #endif
  40. Ort::AllocatorWithDefaultOptions allocator;
  41. //init input
  42. _inputNodesNum = _OrtSession->GetInputCount();
  43. #if ORT_API_VERSION < ORT_OLD_VISON
  44. _inputName = _OrtSession->GetInputName(0, allocator);
  45. _inputNodeNames.push_back(_inputName);
  46. #else
  47. _inputName = std::move(_OrtSession->GetInputNameAllocated(0, allocator));
  48. _inputNodeNames.push_back(_inputName.get());
  49. #endif
  50. Ort::TypeInfo inputTypeInfo = _OrtSession->GetInputTypeInfo(0);
  51. auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
  52. _inputNodeDataType = input_tensor_info.GetElementType();
  53. _inputTensorShape = input_tensor_info.GetShape();
  54. if (_inputTensorShape[0] == -1)
  55. {
  56. _isDynamicShape = true;
  57. _inputTensorShape[0] = _batchSize;
  58. }
  59. if (_inputTensorShape[2] == -1 || _inputTensorShape[3] == -1) {
  60. _isDynamicShape = true;
  61. _inputTensorShape[2] = _netHeight;
  62. _inputTensorShape[3] = _netWidth;
  63. }
  64. //init output
  65. _outputNodesNum = _OrtSession->GetOutputCount();
  66. if (_outputNodesNum != 2) {
  67. cout << "This model has " << _outputNodesNum << "output, which is not a segmentation model.Please check your model name or path!" << endl;
  68. return false;
  69. }
  70. #if ORT_API_VERSION < ORT_OLD_VISON
  71. _output_name0 = _OrtSession->GetOutputName(0, allocator);
  72. _output_name1 = _OrtSession->GetOutputName(1, allocator);
  73. #else
  74. _output_name0 = std::move(_OrtSession->GetOutputNameAllocated(0, allocator));
  75. _output_name1 = std::move(_OrtSession->GetOutputNameAllocated(1, allocator));
  76. #endif
  77. Ort::TypeInfo type_info_output0(nullptr);
  78. Ort::TypeInfo type_info_output1(nullptr);
  79. bool flag = false;
  80. #if ORT_API_VERSION < ORT_OLD_VISON
  81. flag = strcmp(_output_name0, _output_name1) < 0;
  82. #else
  83. flag = strcmp(_output_name0.get(), _output_name1.get()) < 0;
  84. #endif
  85. if (flag) //make sure "output0" is in front of "output1"
  86. {
  87. type_info_output0 = _OrtSession->GetOutputTypeInfo(0); //output0
  88. type_info_output1 = _OrtSession->GetOutputTypeInfo(1); //output1
  89. #if ORT_API_VERSION < ORT_OLD_VISON
  90. _outputNodeNames.push_back(_output_name0);
  91. _outputNodeNames.push_back(_output_name1);
  92. #else
  93. _outputNodeNames.push_back(_output_name0.get());
  94. _outputNodeNames.push_back(_output_name1.get());
  95. #endif
  96. }
  97. else {
  98. type_info_output0 = _OrtSession->GetOutputTypeInfo(1); //output0
  99. type_info_output1 = _OrtSession->GetOutputTypeInfo(0); //output1
  100. #if ORT_API_VERSION < ORT_OLD_VISON
  101. _outputNodeNames.push_back(_output_name1);
  102. _outputNodeNames.push_back(_output_name0);
  103. #else
  104. _outputNodeNames.push_back(_output_name1.get());
  105. _outputNodeNames.push_back(_output_name0.get());
  106. #endif
  107. }
  108. auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
  109. _outputNodeDataType = tensor_info_output0.GetElementType();
  110. _outputTensorShape = tensor_info_output0.GetShape();
  111. auto tensor_info_output1 = type_info_output1.GetTensorTypeAndShapeInfo();
  112. //_outputMaskNodeDataType = tensor_info_output1.GetElementType(); //the same as output0
  113. //_outputMaskTensorShape = tensor_info_output1.GetShape();
  114. //if (_outputTensorShape[0] == -1)
  115. //{
  116. // _outputTensorShape[0] = _batchSize;
  117. // _outputMaskTensorShape[0] = _batchSize;
  118. //}
  119. //if (_outputMaskTensorShape[2] == -1) {
  120. // //size_t ouput_rows = 0;
  121. // //for (int i = 0; i < _strideSize; ++i) {
  122. // // ouput_rows += 3 * (_netWidth / _netStride[i]) * _netHeight / _netStride[i];
  123. // //}
  124. // //_outputTensorShape[1] = ouput_rows;
  125. // _outputMaskTensorShape[2] = _segHeight;
  126. // _outputMaskTensorShape[3] = _segWidth;
  127. //}
  128. //warm up
  129. if (isCuda && warmUp) {
  130. //draw run
  131. cout << "Start warming up" << endl;
  132. size_t input_tensor_length = VectorProduct(_inputTensorShape);
  133. float* temp = new float[input_tensor_length];
  134. std::vector<Ort::Value> input_tensors;
  135. std::vector<Ort::Value> output_tensors;
  136. input_tensors.push_back(Ort::Value::CreateTensor<float>(
  137. _OrtMemoryInfo, temp, input_tensor_length, _inputTensorShape.data(),
  138. _inputTensorShape.size()));
  139. for (int i = 0; i < 3; ++i) {
  140. output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
  141. _inputNodeNames.data(),
  142. input_tensors.data(),
  143. _inputNodeNames.size(),
  144. _outputNodeNames.data(),
  145. _outputNodeNames.size());
  146. }
  147. delete[]temp;
  148. }
  149. }
  150. catch (const std::exception&) {
  151. return false;
  152. }
  153. }
  154. int Yolov8SegOnnx::Preprocessing(const std::vector<cv::Mat>& srcImgs, std::vector<cv::Mat>& outSrcImgs, std::vector<cv::Vec4d>& params) {
  155. outSrcImgs.clear();
  156. Size input_size = Size(_netWidth, _netHeight);
  157. for (int i = 0; i < srcImgs.size(); ++i) {
  158. Mat temp_img = srcImgs[i];
  159. Vec4d temp_param = { 1,1,0,0 };
  160. if (temp_img.size() != input_size) {
  161. Mat borderImg;
  162. LetterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
  163. //cout << borderImg.size() << endl;
  164. outSrcImgs.push_back(borderImg);
  165. params.push_back(temp_param);
  166. }
  167. else {
  168. outSrcImgs.push_back(temp_img);
  169. params.push_back(temp_param);
  170. }
  171. }
  172. int lack_num = srcImgs.size() % _batchSize;
  173. if (lack_num != 0) {
  174. for (int i = 0; i < lack_num; ++i) {
  175. Mat temp_img = Mat::zeros(input_size, CV_8UC3);
  176. Vec4d temp_param = { 1,1,0,0 };
  177. outSrcImgs.push_back(temp_img);
  178. params.push_back(temp_param);
  179. }
  180. }
  181. return 0;
  182. }
  183. bool Yolov8SegOnnx::OnnxDetect(cv::Mat& srcImg, std::vector<OutputSeg>& output) {
  184. std::vector<cv::Mat> input_data = { srcImg };
  185. std::vector<std::vector<OutputSeg>> tenp_output;
  186. if (OnnxBatchDetect(input_data, tenp_output)) {
  187. output = tenp_output[0];
  188. return true;
  189. }
  190. else return false;
  191. }
  192. bool Yolov8SegOnnx::OnnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<OutputSeg>>& output) {
  193. vector<Vec4d> params;
  194. vector<Mat> input_images;
  195. cv::Size input_size(_netWidth, _netHeight);
  196. //preprocessing
  197. Preprocessing(srcImgs, input_images, params);
  198. cv::Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, Scalar(0, 0, 0), true, false);
  199. int64_t input_tensor_length = VectorProduct(_inputTensorShape);
  200. std::vector<Ort::Value> input_tensors;
  201. std::vector<Ort::Value> output_tensors;
  202. input_tensors.push_back(Ort::Value::CreateTensor<float>(_OrtMemoryInfo, (float*)blob.data, input_tensor_length, _inputTensorShape.data(), _inputTensorShape.size()));
  203. output_tensors = _OrtSession->Run(Ort::RunOptions{ nullptr },
  204. _inputNodeNames.data(),
  205. input_tensors.data(),
  206. _inputNodeNames.size(),
  207. _outputNodeNames.data(),
  208. _outputNodeNames.size()
  209. );
  210. //post-process
  211. int net_width = _className.size() + 4 + _segChannels;
  212. float* all_data = output_tensors[0].GetTensorMutableData<float>();
  213. _outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();
  214. _outputMaskTensorShape = output_tensors[1].GetTensorTypeAndShapeInfo().GetShape();
  215. vector<int> mask_protos_shape = { 1,(int)_outputMaskTensorShape[1],(int)_outputMaskTensorShape[2],(int)_outputMaskTensorShape[3] };
  216. int mask_protos_length = VectorProduct(mask_protos_shape);
  217. int64_t one_output_length = VectorProduct(_outputTensorShape) / _outputTensorShape[0];
  218. for (int img_index = 0; img_index < srcImgs.size(); ++img_index) {
  219. Mat output0 = Mat(Size((int)_outputTensorShape[2], (int)_outputTensorShape[1]), CV_32F, all_data).t(); //[bs,116,8400]=>[bs,8400,116]
  220. all_data += one_output_length;
  221. float* pdata = (float*)output0.data;
  222. int rows = output0.rows;
  223. std::vector<int> class_ids;//\BD\E1\B9\FBid\CA\FD\D7\E9
  224. std::vector<float> confidences;//\BD\E1\B9\FBÿ\B8\F6id\B6\D4Ӧ\D6\C3\D0Ŷ\C8\CA\FD\D7\E9
  225. std::vector<cv::Rect> boxes;//ÿ\B8\F6id\BE\D8\D0ο\F2
  226. std::vector<vector<float>> picked_proposals; //output0[:,:, 5 + _className.size():net_width]===> for mask
  227. for (int r = 0; r < rows; ++r) { //stride
  228. cv::Mat scores(1, _className.size(), CV_32F, pdata +4);
  229. Point classIdPoint;
  230. double max_class_socre;
  231. minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
  232. max_class_socre = (float)max_class_socre;
  233. if (max_class_socre >= _classThreshold) {
  234. vector<float> temp_proto(pdata + 4 + _className.size(), pdata + net_width);
  235. picked_proposals.push_back(temp_proto);
  236. //rect [x,y,w,h]
  237. float x = (pdata[0] - params[img_index][2]) / params[img_index][0]; //x
  238. float y = (pdata[1] - params[img_index][3]) / params[img_index][1]; //y
  239. float w = pdata[2] / params[img_index][0]; //w
  240. float h = pdata[3] / params[img_index][1]; //h
  241. int left = MAX(int(x - 0.5 * w + 0.5), 0);
  242. int top = MAX(int(y - 0.5 * h + 0.5), 0);
  243. class_ids.push_back(classIdPoint.x);
  244. confidences.push_back(max_class_socre );
  245. boxes.push_back(Rect(left, top, int(w + 0.5), int(h + 0.5)));
  246. }
  247. pdata += net_width;//\CF\C2һ\D0\D0
  248. }
  249. vector<int> nms_result;
  250. cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);
  251. std::vector<vector<float>> temp_mask_proposals;
  252. cv::Rect holeImgRect(0, 0, srcImgs[img_index].cols, srcImgs[img_index].rows);
  253. std::vector<OutputSeg> temp_output;
  254. for (int i = 0; i < nms_result.size(); ++i) {
  255. int idx = nms_result[i];
  256. OutputSeg result;
  257. result.id = class_ids[idx];
  258. result.confidence = confidences[idx];
  259. result.box = boxes[idx] & holeImgRect;
  260. temp_mask_proposals.push_back(picked_proposals[idx]);
  261. temp_output.push_back(result);
  262. }
  263. MaskParams mask_params;
  264. mask_params.params = params[img_index];
  265. mask_params.srcImgShape = srcImgs[img_index].size();
  266. Mat mask_protos = Mat(mask_protos_shape, CV_32F, output_tensors[1].GetTensorMutableData<float>() + img_index * mask_protos_length);
  267. for (int i = 0; i < temp_mask_proposals.size(); ++i) {
  268. GetMask2(Mat(temp_mask_proposals[i]).t(), mask_protos, temp_output[i], mask_params);
  269. }
  270. //******************** ****************
  271. // \C0ϰ汾\B5ķ\BD\B0\B8\A3\AC\C8\E7\B9\FB\C9\CF\C3\E6\D4ڿ\AA\C6\F4\CE\D2ע\CA͵IJ\BF\B7\D6֮\BA\F3\BB\B9һֱ\B1\A8\B4\ED\A3\AC\BD\A8\D2\E9ʹ\D3\C3\D5\E2\B8\F6\A1\A3
  272. // If the GetMask2() still reports errors , it is recommended to use GetMask().
  273. // Mat mask_proposals;
  274. //for (int i = 0; i < temp_mask_proposals.size(); ++i)
  275. // mask_proposals.push_back(Mat(temp_mask_proposals[i]).t());
  276. //GetMask(mask_proposals, mask_protos, output, mask_params);
  277. //*****************************************************/
  278. output.push_back(temp_output);
  279. }
  280. if (output.size())
  281. return true;
  282. else
  283. return false;
  284. }

main.cpp

  1. #include <iostream>
  2. #include <opencv2/opencv.hpp>
  3. #include "yolov8_seg_onnx.h"
  4. #include "yolov8_seg_utils.h"
  5. #include <sys/time.h>
  6. using namespace std;
  7. using namespace cv;
  8. int main()
  9. {
  10. string model_path = "/home/jason/PycharmProjects/pytorch_learn/yolo/ultralytics-main-yolov8/yolov8n-seg.onnx";
  11. Yolov8SegOnnx test;
  12. if(test.ReadModel(model_path,false,0,false))
  13. cout << "read net ok!\n";
  14. else
  15. cout << "read net err!\n";
  16. vector<Scalar> color;
  17. srand(time(0));
  18. for (int i=0; i<80; i++){
  19. int b = rand() % 256;
  20. int g = rand() % 256;
  21. int r = rand() % 256;
  22. color.push_back(Scalar(b,g,r));
  23. }
  24. struct timeval t1, t2;
  25. double timeuse;
  26. VideoCapture capture(0);
  27. Mat frame;
  28. vector<OutputSeg> output;
  29. while(1){
  30. capture >> frame;
  31. output.clear();
  32. gettimeofday(&t1, NULL);
  33. bool find = test.OnnxDetect(frame, output);
  34. gettimeofday(&t2, NULL);
  35. if (find)
  36. DrawPred(frame, output, test._className, color);
  37. else
  38. cout << "not find!\n";
  39. timeuse = (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec)/1000000; // s
  40. timeuse *= 1000; // ms
  41. string label = "TimeUse: " + to_string(timeuse);
  42. putText(frame, label, Point(30,30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255), 2, 8);
  43. imshow("result", frame);
  44. if(waitKey(1)=='q') break;
  45. }
  46. return 0;
  47. }

CMakelist.txt

  1. find_package(OpenCV 4 REQUIRED)
  2. include_directories(/home/jason/下载/onnxruntime-linux-x64-1.14.1/include)
  3. include_directories(./include )
  4. aux_source_directory(./src SOURCES_LIST)
  5. add_executable(${PROJECT_NAME} ${SOURCES_LIST})
  6. target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} "/home/jason/下载/onnxruntime-linux-x64-1.14.1/lib/libonnxruntime.so")

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

闽ICP备14008679号