当前位置: 代码网 > it编程>编程语言>C/C++ > 在C++中使用YOLO的四种实现方式

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

2025年06月26日 C/C++ 我要评论
在c++中使用yolo进行目标检测主要有以下几种方式,每种方式都有其特点和适用场景:方式一:使用opencv dnn模块(最简单)特点:无需依赖darknet,仅需opencv库,支持onnx模型,跨

在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, false);
    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 `pkg-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/to/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模型,无需转换,支持动态图。

适用场景:需要与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.save("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模型内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com