开发者

在C++中使用YOLO的四种实现方式

目录
  • 方式一:使用OpenCV DNN模块(最简单)
    • 步骤:
  • 方式二:使用Darknet框架(原生支持)
    • 步骤:
  • 方式三:使用TensorRT加速(高性能)
    • 步骤:
  • 方式四:使用libtorch(PyTorch C++前端)
    • 步骤:
  • 性能对比
    • 选择建议

      在C++中使用YOLO进行目标检测主要有以下几种方式,每种方式都有其特点和适用场景:

      方式一:使用OpenCV DNN模块(最简单)

      特点:无需依赖Darknet,仅需OpenCV库,支持ONNX模型,跨平台兼容。

      适用场景:快速原型开发、CPU/GPU通用部署。

      步骤:

      转换模型:将YOLOv5/YOLOv8导出为ONNX格式。

      # YOLOv5
      python export.py --weights yolov5s.pt --include onnx
      
      # YOLOv8
      yolo export model=yolov8n.pt format=onnx
      

      C++代码实现

      #include <opencv2/opencv.hpp>
      #include <opencv2/dnn.hpp>
      #include <IOStream>
      #include <vector>
      
      using namespace cv;
      using namespace dnn;
      using namespace std;
      
      struct Detection {
          int classId;
          float confidence;
          Rect box;
      };
      
      int main() {
          // 加载模型
          Net net = readNet("yolov5s.onnx");
          net.setPreferableBackend(DNN_BACKEND_OPENCV);
          net.setPreferableTarget(DNN_TARGET_CPU);  // 或 DNN_TARGET_CUDA
      
          // 读取图像
          Mat image = imread("test.jpg");
          Mat blob;
          blobFromImage(image, blob, 1/255.0, Size(640, 640), Scalar(), true, faphplse);
          net.setInput(blob);
      
          // 前向传播
          vector<Mat> outputs;
          net.forward(outputs, net.getUnconnectedOutLayersNames());
      
          // 解析输出
          vector<int> classIds;
          vector<float> confidences;
          vector<Rect> boxes;
          float* data = (float*)outputs[0].data;
          
          for (int i = 0; i < outputs[0].rows; ++i) {
              Mat scores = outputs[0].row(i).colRange(5, outputs[0].cols);
              Point classIdPoint;
              double confidence;
              minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
              
              if (confidence > 0.4) {
                  int centerX = (int)(data[i * 85 + 0] * image.cols);
                  int centerY = (int)(data[i * 85 + 1] * image.rows);
                  int width = (int)(data[i * 85 + 2] * image.cols);
                  int height = (int)(data[i * 85 + 3] * image.rows);
                  int left = centerX - width / 2;
                  int top = centerY - height / 2;
                  
                  classIds.push_back(classIdPoint.x);
                  confidences.push_back((float)confidence);
                  boxes.push_back(Rect(left, top, width, height));
              }
          }
      
          // 非极大值抑制
          vector<int> indices;
          NMSBoxes(boxes, confidences, 0.4, 0.5, indices);
          
          // 绘制结果
          for (int idx : indices) {
              rectangle(image, boxes[idx], Scalar(0, 255, 0), 2);
              string label = format("class: %d, conf: %.2f", classIds[idx], confidences[idx]);
              putText(image, label, Point(boxes[idx].x, boxes[idx].y - 10), 
                      FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 2);
          }
      
          imshow("Detection", image);
          waitKey(0);
          return 0;
      }
      

      编译命令

      g++ yolo_opencv.cpp -o yolo `ppythonkg-config --cflags --libs opencv4`
      

      方式二:使用Darknet框架(原生支持)

      特点:YOLO官方框架,支持C/C++接口,性能优化好,但依赖复杂。

      适用场景:需要完整复现YOLO训练和推理流程。

      步骤:

      编译Darknet

      git clone https://github.com/AlexeyAB/darknet
      cd darknet
      make  # 修改Makefile以启用CUDA/CUDNN
      

      C++代码实现

      #include "darknet.h"
      #include <iostream>
      
      using namespace std;
      
      int main() {
          // 加载网络
          network* net = load_network("cfg/yolov4.cfg", "yolov4.weights", 0);
          set_BATch_network(net, 1);
          
          // 加载图像
          image im = load_image_color("test.jpg", 0, 0);
          image sized = letterbox_image(im, net->w, net->h);
          
          // 前向传播
          layer l = net->layers[net->n - 1];
          float* X = sized.data;
          network_predict(net, X);
          
          // 解析结果
          int nboxes = 0;
          detection* dets = get_network_boxes(net, im.w, im.h, 0.5, 0.5, 0, 1, &nboxes);
          do_nms_sort(dets, nboxes, l.classes, 0.45);
          
          // 绘制结果
          // ...
          
          // 释放资源
          free_detections(dets, nboxes);
          free_image(im);
          free_image(sized);
          free_network(net);
          
          return 0;
      }
      

      编译命令

      g++ yolo_darknet.cpp -o yolo -I/path/to/darknet/include -L/path/www.devze.comto/darknet/lib -ldarknet -lpthread -lcuda -lcudnn -lopencv_core -lopencv_imgproc -lopencv_imgcodecs
      

      方式三:使用TensorRT加速(高性能)

      特点:NVIDIA官方推理优化工具,专为GPU设计,速度最快。

      适用场景:嵌入式设备(Jetson)或GPU服务器上的高性能部署。

      步骤:

      转换模型:将ONNX转换为TensorRT引擎:

      import tensorrt as trt
      
      def build_engine(onnx_path, engine_path):
          logger = trt.Logger(trt.Logger.WARNING)
          builder = trt.Builder(logger)
          network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
          parser = trt.OnnxParser(network, logger)
          
          with open(onnx_path, 'rb') as model:
              parser.parse(model.read())
          
          config = builder.create_builder_config()
          config.max_workspace_size = 1 << 30  # 1GB
          config.set_flag(trt.BuilderFlag.FP16)  # 启用FP16
          
          engine = builder.build_engine(network, config)
          with open(engine_path, 'wb') as f:
              f.write(engine.serialize())
          return engine
      
      build_engine("yolov5s.onnx", "yolov5s.engine")
      

      C++代码实现

      #include <NvInfer.h>
      #include <NvOnnxParser.h>
      #include <opencv2/opencv.hpp>
      #include <cuda_runtime_api.h>
      
      // TensorRT Logger
      class Logger : public nvinfer1::ILogger {
          void log(Severity severity, const char* msg) noexcept override {
              if (severity != Severity::kINFO) std::cerr << "TensorRT: " << msg << std::endl;
          }
      };
      
      int main() {
          // 加载引擎
          Logger logger;
          std::ifstream file("yolov5s.engine", std::ios::binary);
          std::vector<char> engineData((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
          
          nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
          nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(engineData.data(), engineData.size());
          nvinfer1::IExecutionContext* context = engine->createExecutionContext();
          
          // 准备输入数据
          cv::Mat image = cv::imread("test.jpg");
          cv::Mat input = preprocess(image, 640, 640);  // 自定义预处理函数
          
          // 分配GPU内存
          void* buffers[2];
          cudaMalloc(&buffers[0], 3 * 640 * 640 * sizeof(float));
          cudaMalloc(&buffers[1], 25200 * 85 * sizeof(float));
          
          // 拷贝数据到GPU
          cudaMemcpy(buffers[0], input.data, 3 * 640 * 640 * sizeof(float), cudaMemcpyHostToDevice);
          
          // 执行推理
          context->executeV2(buffers);
          
          // 拷贝结果回CPU
          std::vector<float> output(25200 * 85);
          cudaMemcpy(output.data(), buffers[1], 25200 * 85 * sizeof(float), cudaMemcpyDeviceToHost);
          
          // 解析结果
          // ...
          
          // 释放资源
          cudaFree(buffers[0]);
          cudaFree(buffers[1]);
          context->destroy();
          engine->destroy();
          runtime->destroy();
          
          return 0;
      }
      

      方式四:使用libtorch(PyTorch C++前端)

      特点:直接加载PyTorch模型,无需转换,支持动态图。

      python

      适用场景:需要与PyTorch训练代码无缝衔接的场景。

      步骤:

      导出TorchScript模型

      import torch
      model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)
      model.eval()
      traced_script_module = torch.jit.trace(model, torch.rand(1, 3, 640, 640))
      traced_script_module.s编程客栈ave("yolov5s_scripted.pt")
      

      C++代码实现

      #include <torch/script.h>
      #include <opencv2/opencv.hpp>
      
      int main() {
          // 加载模型
          torch::jit::script::Module module = torch::jit::load("yolov5s_scripted.pt");
          module.to(at::kCUDA);  // 若有GPU
          
          // 准备输入
          cv::Mat image = cv::imread("test.jpg");
          cv::Mat input = preprocess(image, 640, 640);  // 转换为[0,1]的浮点数
          
          // 转换为Tensor
          torch::Tensor tensor = torch::from_blob(input.data, {1, 3, 640, 640}, torch::kFloat32);
          tensor = tensor.to(at::kCUDA);  // 若有GPU
          
          // 前向传播
          std::vector<torch::jit::IValue> inputs;
          inputs.push_back(tensor);
          torch::Tensor output = module.forward(inputs).toTensor();
          
          // 解析结果
          // ...
          
          return 0;
      }
      

      性能对比

      方式速度(FPS)依赖复杂度部署难度灵活性
      OpenCV DNN简单
      Darknet中等
      TensorRT极高复杂
      libtorch中高中等

      选择建议

      • 快速开发:选OpenCV DNN。
      • 极致性能:选TensorRT。
      • 完整功能:选Darknet。
      • PyTorch生态:选libtorch。

      到此这篇关于在C++中使用YOLO的四种实现方式的文章就介绍到这了,更多相关C++使用YOLO模型内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜