人工智能混合编程实践:C++调用Python ONNX进行YOLOv8推理

在这里插入图片描述

前言

相关介绍

Python简介

Python 是一种高级编程语言,因其代码的可读性和简洁性而广受欢迎。它支持多种编程范式,包括面向对象、命令式和函数式编程或过程式编程。Python的设计哲学强调代码的可读性,并且其语法允许程序员用比C++或Java等语言更少的代码行表达概念。Python拥有一个庞大的标准库,涵盖了诸如文件I/O、系统调用、网络接口等众多领域,极大地提升了开发效率。

C++简介

C++ 是一种广泛使用的编程语言,最初由丹麦计算机科学家Bjarne Stroustrup于1979年在贝尔实验室开发,作为C语言的扩展。C++的设计目标是提供一种能够高效利用硬件资源,同时支持面向对象编程(OOP)特性的语言。随着时间的发展,C++也引入了泛型编程和函数式编程的支持,使其成为一种多范式编程语言。

ONNX简介

ONNX(Open Neural Network Exchange) 是一个开放的生态系统,旨在促进不同框架之间深度学习模型的互操作性。通过ONNX,开发者可以更容易地在不同的深度学习框架(如PyTorch、TensorFlow等)间共享和部署模型。ONNX定义了一种通用的模型文件格式,使得训练好的模型可以在各种硬件平台上高效运行,无论是服务器端还是边缘设备。这有助于加速机器学习技术的研发和应用。

YOLOv8简介

YOLOv8 实际上是基于YOLO(You Only Look Once)系列目标检测算法的一个版本,YOLO系列算法以其快速、准确的目标检测能力著称,广泛应用于实时物体识别场景中。
[1] YOLOv8 源代码地址:https://github.com/ultralytics/ultralytics.git.
[2] YOLOv8 官方文档:https://docs.ultralytics.com/

前提条件

  • 熟悉Python
  • 熟悉C++
  • 熟悉VS2019

实验环境

Package             Version
------------------- -----------
colorama            0.4.6
coloredlogs         15.0.1
contourpy           1.1.1
cycler              0.12.1
flatbuffers         24.3.25
fonttools           4.55.3
humanfriendly       10.0
imageio             2.35.1
importlib_resources 6.4.5
kiwisolver          1.4.7
lazy_loader         0.4
matplotlib          3.7.5
mpmath              1.3.0
networkx            3.1
numpy               1.24.4
onnxruntime-gpu     1.15.0
open2d              5.2.21
opencv-python       4.10.0.84
packaging           24.2
pillow              10.4.0
pip                 24.3.1
protobuf            5.29.1
pyparsing           3.1.4
pyreadline3         3.5.4
python-dateutil     2.9.0.post0
PyWavelets          1.4.1
scikit-image        0.21.0
scipy               1.10.1
setuptools          41.2.0
six                 1.17.0
sympy               1.13.3
tifffile            2023.7.10
tqdm                4.67.1
zipp                3.20.2

项目结构

cxx_py_infer_yolov8
├─Cxx_PythonModule
│  └─x64
│      └─Release
│          └─Cxx_PythonModule.tlog
├─cxx_py_infer_call
│  └─x64
│      └─Release
│          └─cxx_py_i.f08a3daa.tlog
├─cxx_py_infer.sln
└─x64
    └─Release
        ├─dst
        ├─Python38
        ├─src
        │  └─1.png
        ├─weights
        │  └─yolov8s.onnx
        └─yolov8_py_infer.py

在这里插入图片描述

注:yolov8_py_infer.py的代码,请查阅人工智能混合编程实践:Python ONNX进行YOLOv8推理

C++调用Python ONNX进行YOLOv8推理

在这里插入图片描述

C++调用Python的相关dll代码

framework.h

#pragma once

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

pch.h

// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"
#include "cxx_pythonModule.h"


cxx_pythonModule cxx_python_module;

extern "C" _declspec(dllexport) bool algorithmPythonInit(const std::string yolo_model_path);

extern "C" __declspec(dllexport) bool algorithmPyDetectYOLO(const cv::Mat image, const std::string image_name, std::vector<int>&classID, std::vector<float>&confidenceVal, std::vector<cv::Rect>&rectangles);


#endif //PCH_H

cxx_pythonModule.h

#pragma once
#include <Python.h>
#include <numpy/arrayobject.h>
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <tuple>
#include <opencv2/core/utils/filesystem.hpp> // For cv::glob
#include <chrono> // For measuring time


using namespace cv;

class cxx_pythonModule
{
public:
	cxx_pythonModule();
	~cxx_pythonModule();

	//整体初始化
	void PythonInitialize(const std::string yolo_model_path);
	
	void YOLOPyDetection(const cv::Mat image, const std::string image_name, std::vector<int>& classID, std::vector<float>& confidenceVals, std::vector<cv::Rect>& rectangles);
	

private:
	// 全局或静态变量来存储Python模块和函数
	PyObject* g_pONNXInferencer = nullptr;
	PyObject* g_pModule = nullptr;
	//PyObject* pyArray = nullptr;

	PyObject* g_pONNXInferencer_YOLO = nullptr;
	PyObject* g_pModule_YOLO = nullptr;
	//PyObject* pyArray_YOLO = nullptr;

	std::string model_path ;
	std::string metadata_path;
	int input_width;
	int input_height;


	
	std::tuple<std::vector<int>, std::vector<float>, std::vector<cv::Rect>> yolo_infer_and_parse(const cv::Mat& image, const std::string& image_name);
	
	PyObject* mat_to_numpy(const cv::Mat& mat);
	void check_python_error();
	std::vector<int> parse_numpy_array_to_int_vector(PyObject* pArray);
	std::vector<float> parse_numpy_array_to_float_vector(PyObject* pArray);
	std::vector<cv::Rect>parse_numpy_array_to_rectangles(PyObject* pValue);
	cv::Mat parse_numpy_to_mat(PyObject* pReturnValue);
	void print_rectangles(const std::vector<cv::Rect>& rectangles);
	void print_classids(const std::vector<int>& classID);
	void print_scores(const std::vector<float>& confidenceVals);
	void cleanup_python();
};
#pragma once

dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

pch.cpp

// pch.cpp: 与预编译标头对应的源文件

#include "pch.h"

// 当使用预编译的头时,需要使用此源文件,编译才能成功。


bool algorithmPythonInit(const std::string yolo_model_path)
{
	cxx_python_module.PythonInitialize(yolo_model_path);
	
	return true;
}

bool algorithmPyDetectYOLO(const cv::Mat image, const std::string image_name, std::vector<int>& classID, std::vector<float>& confidenceVals, std::vector<cv::Rect>& rectangles)
{
	cxx_python_module.YOLOPyDetection(image, image_name, classID, confidenceVals, rectangles);

	return true;
}

cxx_pythonModule.cpp

// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#include "pch.h"
#include "cxx_pythonModule.h"


cxx_pythonModule::cxx_pythonModule()
{

}


cxx_pythonModule::~cxx_pythonModule()
{
    cleanup_python();
}

void cxx_pythonModule::PythonInitialize(const std::string yolo_model_path)
{
    Py_SetPythonHome((wchar_t*)L"./Python38");


    if (Py_IsInitialized()) return;

    Py_Initialize();
    // 初始化 NumPy C API
    import_array();

    // 设置Python路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('.')");

    //获取当前 Python 环境信息
    PyRun_SimpleString(
        "print('Python version:', sys.version)\n"
        "print('Python executable:', sys.executable)\n"
        "print('Python path:', sys.path)"
    );

    //YOLOv8
    // 导入Python模块
    g_pModule_YOLO = PyImport_ImportModule("yolov8_py_infer"); // python脚本
    if (g_pModule_YOLO == NULL) {
        check_python_error();
        throw std::runtime_error("Failed to import Python module 'yolov8_py_infer'");
    }

    // 获取Python类
    PyObject* g_pClassInferencer_YOLO = PyObject_GetAttrString(g_pModule_YOLO, "YOLOv8ObjectDetector");
    if (g_pClassInferencer_YOLO == NULL || !PyType_Check(g_pClassInferencer_YOLO)) {
        check_python_error();
        Py_DECREF(g_pClassInferencer_YOLO);
        Py_DECREF(g_pModule_YOLO);
        throw std::runtime_error("Failed to get class 'YOLOv8ObjectDetector'");
    }

    // 构建参数
    PyObject* pArgs_YOLO = PyTuple_New(1);
    PyTuple_SetItem(pArgs_YOLO, 0, PyUnicode_FromString(yolo_model_path.c_str()));

    // 创建 ONNXInferencer 实例
    g_pONNXInferencer_YOLO = PyObject_CallObject(g_pClassInferencer_YOLO, pArgs_YOLO);
    if (g_pONNXInferencer_YOLO == NULL) {
        check_python_error();
        Py_DECREF(pArgs_YOLO);
        //Py_DECREF(g_pClassInferencer_YOLO);
        Py_DECREF(g_pModule_YOLO);
        throw std::runtime_error("Failed to create instance of 'YOLOv8'");
    }
}

void cxx_pythonModule::YOLOPyDetection(const cv::Mat image, const std::string image_name, std::vector<int>& classID, std::vector<float>& confidenceVals, std::vector<cv::Rect>& rectangles)
{

    // 调用 infer_and_parse 函数
    std::tie(classID, confidenceVals, rectangles) = yolo_infer_and_parse(image, image_name);
    // 返回的框大小需要重新映射会原图大小 
    std::cout << "YOLOPyDetection" << std::endl;

    /*cxx_pythonModule::print_classids(classID);
    cxx_pythonModule::print_scores(confidenceVal);
    cxx_pythonModule::print_rectangles(rectangles);*/
    // 打印结果
    for (size_t i = 0; i < classID.size(); ++i) {
        std::cout << "Class ID: " << classID[i]
            << ", Score: " << confidenceVals[i]
            << ", Box: (" << rectangles[i].x << ", " << rectangles[i].y
            << ", " << rectangles[i].width << ", " << rectangles[i].height << ")" << std::endl;
    }

}

// 调用 Python 的 yolo 方法并解析结果
std::tuple<std::vector<int>, std::vector<float>, std::vector<cv::Rect>> cxx_pythonModule::yolo_infer_and_parse(const cv::Mat& image, const std::string& image_name) {
    // 构建参数
    PyObject* pArgsInfer_YOLO = PyTuple_New(2);
    PyTuple_SetItem(pArgsInfer_YOLO, 0, mat_to_numpy(image)); // 传递图像的 NumPy 表示
    PyTuple_SetItem(pArgsInfer_YOLO, 1, PyUnicode_FromString(image_name.c_str()));

    // 确保获取 GIL
    PyGILState_STATE gstate = PyGILState_Ensure();

    // 获取 detect_object 方法
    PyObject* pMethodInfer_YOLO = PyObject_GetAttrString(g_pONNXInferencer_YOLO, "detect_object");
    if (pMethodInfer_YOLO && !PyCallable_Check(pMethodInfer_YOLO)) {
        check_python_error();
        Py_DECREF(pMethodInfer_YOLO);
        Py_DECREF(pArgsInfer_YOLO);
        PyGILState_Release(gstate);  // 释放 GIL
        throw std::runtime_error("Method 'detect_object' is not callable");
    }

    // 调用 Python 方法
    PyObject* pReturnValueInfer_YOLO = PyObject_CallObject(pMethodInfer_YOLO, pArgsInfer_YOLO);
    if (pReturnValueInfer_YOLO == NULL) {
        check_python_error();  // 打印 Python 错误信息
        PyErr_Clear();  // 清除 Python 异常状态
        Py_DECREF(pMethodInfer_YOLO);
        Py_DECREF(pArgsInfer_YOLO);
        PyGILState_Release(gstate);  // 释放 GIL
        throw std::runtime_error("Failed to call Python method 'detect_object'");
    }

    // 检查返回值是否为元组且包含三个元素
    if (!PyTuple_Check(pReturnValueInfer_YOLO) || PyTuple_Size(pReturnValueInfer_YOLO) != 3) {
        check_python_error();
        Py_DECREF(pReturnValueInfer_YOLO);
        Py_DECREF(pMethodInfer_YOLO);
        Py_DECREF(pArgsInfer_YOLO);
        PyGILState_Release(gstate);  // 释放 GIL
        throw std::runtime_error("Invalid return value from Python method 'detect_object'");
    }

    // 获取元组中的第一个元素(类别ID)
    PyObject* pClassIds_YOLO = PyTuple_GetItem(pReturnValueInfer_YOLO, 0);
    std::vector<int> class_ids_YOLO = parse_numpy_array_to_int_vector(pClassIds_YOLO);

    // 获取元组中的第二个元素(置信度)
    PyObject* pScores_YOLO = PyTuple_GetItem(pReturnValueInfer_YOLO, 1);
    std::vector<float> scores_YOLO = parse_numpy_array_to_float_vector(pScores_YOLO);

    // 获取元组中的第三个元素(检测框)
    PyObject* pBoxes_YOLO = PyTuple_GetItem(pReturnValueInfer_YOLO, 2);
    std::vector<cv::Rect> boxes_YOLO = parse_numpy_array_to_rectangles(pBoxes_YOLO);

    // 释放 Python 对象
    Py_DECREF(pReturnValueInfer_YOLO);
    Py_DECREF(pMethodInfer_YOLO);
    Py_DECREF(pArgsInfer_YOLO);
    PyGILState_Release(gstate);  // 释放 GIL

    return std::make_tuple(class_ids_YOLO, scores_YOLO, boxes_YOLO);
}

// 解析 Python 返回值并转换为 cv::Mat
cv::Mat cxx_pythonModule::parse_numpy_to_mat(PyObject* pReturnValue) {
    if (!PyArray_Check(pReturnValue)) {
        throw std::runtime_error("Return value from Python is not a NumPy array.");
    }

    // 获取 NumPy 数组的指针和信息
    PyArrayObject* pArray = reinterpret_cast<PyArrayObject*>(pReturnValue);
    void* data = PyArray_DATA(pArray);
    int ndims = PyArray_NDIM(pArray);
    npy_intp* shape = PyArray_SHAPE(pArray);
    int type = PyArray_TYPE(pArray);

     检查维度是否正确
    //if (ndims != 3) {
    //    throw std::runtime_error("NumPy array must have 3 dimensions (height, width, channels).");
    //}

    // 获取图像的高度、宽度和通道数
    int rows = shape[0];
    int cols = shape[1];
    int channels;
    if (ndims != 3) {
        channels = 1;
    }
    else {
        channels = shape[2];
    }
    

    // 根据数据类型创建 cv::Mat
    cv::Mat result;
    if (type == NPY_UINT8) {
        result = cv::Mat(rows, cols, CV_8UC(channels), data).clone();
    }
    else if (type == NPY_UINT16) {
        result = cv::Mat(rows, cols, CV_16UC(channels), data).clone();
    }
    else {
        throw std::runtime_error("Unsupported NumPy array data type.");
    }

    return result;
}

// 将 cv::Mat 转换为 PyArrayObject * ,支持 8 位和 16 位图像
PyObject * cxx_pythonModule::mat_to_numpy(const cv::Mat & mat) {
    if (mat.empty()) {
        throw std::runtime_error("Input cv::Mat is empty.");
    }

    // 确保 Mat 是连续的
    cv::Mat continuous_mat;
    if (!mat.isContinuous()) {
        continuous_mat = mat.clone();
    }
    else {
        continuous_mat = mat;
    }

    // 获取 Mat 的尺寸和类型
    int dims[] = { continuous_mat.rows, continuous_mat.cols, continuous_mat.channels() };
    npy_intp shape[3] = { dims[0], dims[1], dims[2] };

    // 根据 cv::Mat 的数据类型选择 NumPy 数据类型
    int numpy_type;
    switch (continuous_mat.depth()) {
    case CV_8U:  numpy_type = NPY_UINT8;  break;
    case CV_16U: numpy_type = NPY_UINT16; break;
    default:
        throw std::runtime_error("Unsupported cv::Mat data type.");
    }

    // 创建 NumPy 数组,不设置 NPY_ARRAY_OWNDATA
    PyObject* pArray = PyArray_SimpleNewFromData(3, shape, numpy_type, continuous_mat.data);

    // 确保 NumPy 不会释放数据
    Py_INCREF(pArray);  // 增加引用计数,防止 NumPy 销毁数据

    return pArray;
}

// 辅助函数:检查Python错误并打印
void cxx_pythonModule::check_python_error() {
    if (PyErr_Occurred()) {
        PyErr_Print();
        std::cerr << "Python error occurred." << std::endl;
    }
}

// 解析 NumPy 数组为 std::vector<int>(类别ID)
std::vector<int> cxx_pythonModule::parse_numpy_array_to_int_vector(PyObject* pArray) {
    if (!PyArray_Check(pArray)) {
        throw std::runtime_error("Invalid NumPy array for class IDs");
    }
    PyArrayObject* np_array = (PyArrayObject*)pArray;
    int length = PyArray_SIZE(np_array);
    std::vector<int> result(length);
    memcpy(result.data(), PyArray_DATA(np_array), length * sizeof(int));
    return result;
}

// 解析 NumPy 数组为 std::vector<float>(置信度)
std::vector<float> cxx_pythonModule::parse_numpy_array_to_float_vector(PyObject* pArray) {
    if (!PyArray_Check(pArray)) {
        throw std::runtime_error("Invalid NumPy array for scores");
    }
    PyArrayObject* np_array = (PyArrayObject*)pArray;
    int length = PyArray_SIZE(np_array);
    std::vector<float> result(length);
    memcpy(result.data(), PyArray_DATA(np_array), length * sizeof(float));
    return result;
}

// 解析 NumPy 数组为 std::vector<cv::Rect>(检测框)
std::vector<cv::Rect> cxx_pythonModule::parse_numpy_array_to_rectangles(PyObject* pArray) {
    if (!PyArray_Check(pArray)) {
        throw std::runtime_error("Invalid NumPy array for boxes");
    }
    PyArrayObject* np_array = (PyArrayObject*)pArray;
    int num_boxes = PyArray_DIMS(np_array)[0];
    std::vector<cv::Rect> result(num_boxes);
    for (int i = 0; i < num_boxes; ++i) {
        int x = ((int*)PyArray_GETPTR2(np_array, i, 0))[0];
        int y = ((int*)PyArray_GETPTR2(np_array, i, 1))[0];
        int w = ((int*)PyArray_GETPTR2(np_array, i, 2))[0];
        int h = ((int*)PyArray_GETPTR2(np_array, i, 3))[0];
        result[i] = cv::Rect(x, y, w, h);
    }
    return result;
}


// 打印矩形框信息
void cxx_pythonModule::print_rectangles(const std::vector<cv::Rect>& rectangles) {
    for (size_t i = 0; i < rectangles.size(); ++i) {
        const cv::Rect& rect = rectangles[i];
        std::cout << "Rectangle " << i + 1 << ": "
            << "x=" << rect.x << ", "
            << "y=" << rect.y << ", "
            << "width=" << rect.width << ", "
            << "height=" << rect.height << std::endl;
    }
}

void cxx_pythonModule::print_classids(const std::vector<int>& classID) {
    for (size_t i = 0; i < classID.size(); ++i) {
        const int id = classID[i];
        std::cout << "id=" << id << std::endl;
    }
}

void cxx_pythonModule::print_scores(const std::vector<float>& confidenceVals) {
    for (size_t i = 0; i < confidenceVals.size(); ++i) {
        const float score = confidenceVals[i];
        std::cout << "score=" << confidenceVals[i] << std::endl;
    }
}

// 清理Python环境
void cxx_pythonModule::cleanup_python() {
    if (g_pONNXInferencer != NULL) {
        Py_DECREF(g_pONNXInferencer);
        g_pONNXInferencer = NULL;
    }
    if (g_pModule != NULL) {
        Py_DECREF(g_pModule);
        g_pModule = NULL;
    }
    if (Py_IsInitialized()) {
        Py_Finalize();
    }
}

C++调用Python代码的主函数

main.cpp

#include <iostream>
#include <windows.h>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

// 定义函数指针类型
//python模块初始化
typedef bool(*algorithmPythonInit)(const std::string yolo_model_path);

//yolov8模块
typedef bool (*algorithmPyDetectYOLO)(const cv::Mat image, const std::string image_name, std::vector<int>& classID, std::vector<float>& confidenceVal, std::vector<cv::Rect>& rectangles);


algorithmPythonInit alg_PythonInit;
algorithmPyDetectYOLO alg_PyDetectYOLO;



int main() {
    //load dll
    HINSTANCE hdll1 = LoadLibrary(L"Cxx_PythonModule.dll");
    std::cout << GetLastError() << endl;
    if (hdll1 == NULL)
    {
        FreeLibrary(hdll1);
        printf("dll  miss  %d \n", __LINE__);

        return -1;
    }
    //环境初始化
    alg_PythonInit = (algorithmPythonInit)GetProcAddress(hdll1, "algorithmPythonInit");
    //yolov8检测
    alg_PyDetectYOLO = (algorithmPyDetectYOLO)GetProcAddress(hdll1, "algorithmPyDetectYOLO");

    string yolo_model_path = "./weights/yolov8s.onnx";

    //初始化python模块相关环境
    alg_PythonInit(yolo_model_path);

    clock_t start = clock();

    // 图片路径
    string dataPath = "./src";

    //结果路径
    string DesPath = "./dst/";

    //glob
    std::string pattern = dataPath + "/*.png";
    vector<cv::String> fileNames;
    cv::glob(pattern, fileNames, true);

    cout << "fileNames.size=" << fileNames.size() << endl;


    for (int i = 0; i < fileNames.size(); i++)
    {
        
        String ImgName = fileNames[i];
        //-1 在OpenCV中对应的是 cv::IMREAD_UNCHANGED 标志,表示以原始格式读取图像,包括其原有的色彩通道和深度。
        cv::Mat image = cv::imread(fileNames[i], -1);


        //1.获取不带路径的文件名
        string::size_type iPos = fileNames[i].find_last_of('\\') + 1;
        string filename = fileNames[i].substr(iPos, fileNames[i].length() - iPos);
        cout << "filename:" << filename << endl;
        cout << " line " << __LINE__ << "  file " << __FILE__ << endl;
        //2.获取不带后缀的文件名
        string name = filename.substr(0, filename.rfind("."));
        cout << "name:" << name << endl;


        string image_name = name;

        if (image.empty())
            continue;
        clock_t start = clock();

        int result = 0;

        cv::Mat img = image.clone();

        vector<cv::Rect> rectangles;
        std::vector<int> classID;
        std::vector<float> confidenceVals;

        result = alg_PyDetectYOLO(img, filename, classID, confidenceVals, rectangles);

        clock_t end = clock();
        cout << "result = " << result << " , time = " << end - start << " ms" << endl;
        
        cout << " line " << __LINE__ << " file " << __FILE__ << std::endl;

    }
    cout << "===============================" << endl;
    cout << " 遍历结束 " << endl;
    cout << "===============================" << endl;


    return 0;
}
YOLOv8模型预热完成
fileNames.size=1
filename:1.png
 line 83  file E:\6875\mytest\cxx_py_infer_yolov8\cxx_py_infer_call\main.cpp
name:1
YOLOPyDetection
Class ID: 2, Score: 0.913807, Box: (309, 332, 119, 100)
Class ID: 2, Score: 0.776528, Box: (208, 331, 40, 49)
Class ID: 2, Score: 0.636771, Box: (68, 313, 161, 122)
Class ID: 2, Score: 0.618292, Box: (302, 337, 23, 24)
Class ID: 7, Score: 0.572172, Box: (241, 318, 44, 53)
result = 1 , time = 36 ms

在这里插入图片描述

在这里插入图片描述

参考文献

[1] YOLOv8 源代码地址:https://github.com/ultralytics/ultralytics.git.
[2] YOLOv8 官方文档:https://docs.ultralytics.com/
[3] YOLO11 源代码地址:https://github.com/ultralytics/ultralytics.git
[4] YOLO11 官方文档:https://docs.ultralytics.com/models/yolo11/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FriendshipT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值