YoloV5-LibTorch:C++中使用yolov5

前言

在c++中使用yolov5,这里借用YoloV5-LibTorch

https://www.icode9.com/content-3-1005434.html

https://zhuanlan.zhihu.com/p/376149679

https://www.codeleading.com/article/43474472475/

https://blog.csdn.net/Cleo_Gao/article/details/111606991

本地环境

  • Win 10
  • Visual Studio 2017(至少vs 2017)
  • OpenCV3.4.14
  • libtorch1.9.1 CPU

Visual Studio

  • At least Visual Studio 2017 version 15.6 with the toolset 14.13 and NVTX are needed.

    https://www.codeleading.com/article/43474472475/

  • VC++目录 >> 包含目录
    C:\Development\ThirdPartyLib\libtorch\include
    C:\Development\ThirdPartyLib\libtorch\include\torch\csrc\api\include
    C:\Development\ThirdPartyLib\Opencv3.4.14\include
    
  • VC++目录 >> 库目录
    C:\Development\ThirdPartyLib\Opencv3.4.14\x64\vc15\lib
    C:\Development\ThirdPartyLib\libtorch\lib
    
  • 链接器 >> 输入 >> 附加依赖项
    opencv_world3414.lib
    c10.lib
    torch.lib
    torch_cpu.lib
    

OpenCV

  • 注意选 vc15(VS 2017)

YoloV5-LibTorch

这里采用YoloV5-LibTorch,这个YoloV5的c++封装库,github地址:

https://github.com/ncdhz/YoloV5-LibTorch

具体用法有两种

  • 可以直接将其中 YoloV5.h、YoloV5.cpp 放到自己的项目中,这样比较简单。
  • 也可以用cmake编译出一个库来用。

https://zhuanlan.zhihu.com/p/376149679

直接使用

  • 将 YoloV5.h、YoloV5.cpp 放到自己的项目中就行。

Cmake编译

  • cmake的话麻烦一点,不是很推荐
  • 根据本地环境,编辑一下 CMakeLists.txt,主要是指定 pytorch 路径和 opencv 路径
cmake_minimum_required(VERSION 3.10)

# Windows 系统下指定 pytorch 路径和 opencv 路径
set(Torch_DIR C:/Development/ThirdPartyLib/libtorch/share/cmake/Torch)
set(OpenCV_DIR C:/Development/ThirdPartyLib/Opencv3.4.14/x64/vc15/lib)

project(YoloV5LibTorch)

include_directories(./include)

add_subdirectory(./src)
add_subdirectory(./test)

install(TARGETS test YoloV5
    RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/bin
    ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR}/lib
)
创建 一个build文件夹
  • 命令行下
cd build
cmake ..
cmake --build . --config Release
cmake --install . --config Release

模型转化

想要使用libtorch读取yolov5生成的pt模型需要先对模型进行序列化转换

Yolov5 Export

  • Yolov5里面有一个自带的转换函数export.py,它可以对已有的pt文件进行序列化转换。
  • 导出TorchScript、ONNX、CoreML,这里我们需要TorchScript这种。得到yolov5s.torchscript.pt 后,就可以在c++中使用
  • export.py 在models文件夹下,可以命令行如下执行,也可以拉出来执行
# yolov5s.pt ---> yolov5s.torchscript.pt 

python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1
  • 在执行之前,先对export.py进行修改,修改如下,如果不改,转换出来的yolov5s.torchscript.pt没法使用

参考了其他类似的封装库,https://github.com/yasenh/libtorch-yolov5

'''
# see https://github.com/yasenh/libtorch-yolov5
#
# Mandatory Update: developer needs to modify following code from the original export.py in yolov5
# model.model[-1].export = False
'''

# 去掉这行
#model.model[-1].export = not opt.grid  # set Detect() layer grid export
# 改成这个
model.model[-1].export = False

问题

  • 目前发现,同样的pt文件,python程序和c++预测出来的结果中,预测概率不一样。
  • 实际使用中发现,YoloV5-LibTorch,预测出的目标位置坐标值超出了图片长宽范围,应该是个小BUG。

报错

不明确的符号“std”

不明确的符号 | TorchForCPP

https://blog.csdn.net/juluwangriyue/article/details/117448485

  • 项目-》属性-》c/c+±》语言-》符合模式 改成否

at::Scalar不明确

  1. 这些报错一般出现在和OpenCV库联用的情况
  2. at::Scalar不明确at::Allocator不明确torch::Scalar不明确,因为使用 opencv 的Scalar类型,导致和Libtorch命名空间的Scalar冲突。可以根据提示在对应的文件位置添加命名空间说明
  • 在 \libtorch/include/ATen/detail/CUDAHooksInterface.h 第28行附近,增加
namespace at{
using c10::Allocator;  // 添加命名空间

at::Allocator不明确

  • 在 \libtorch/include/ATen/core/TensorBody.h 第35行附近,增加
namespace at{
using c10::Scalar;  //添加命名空间

torch::Scalar不明确

  • 在 \libtorch\include\torch\csrc\api\include\torch\linalg.h 第6行左右位置,增加
#pragma once

#include <ATen/ATen.h>

namespace torch {
using torch::Scalar;  //添加命名空间
namespace linalg {
  • 在 \libtorch\include\torch\csrc\api\include\torch\nn\init.h 第8行左右位置,增加
#pragma once

#include <torch/csrc/WindowsTorchApiMacro.h>
#include <torch/enum.h>
#include <torch/types.h>

namespace torch {
    using torch::Scalar;  //添加命名空间
namespace nn {
namespace init {

  • 在 \libtorch\include\torch\csrc\api\include\torch\special.h 第6行左右位置,增加
#pragma once

#include <ATen/ATen.h>

namespace torch {
    using torch::Scalar;  //添加命名空间
namespace special {

配置支持 cuda

  • 属性-链接器-命令行中添加如下字符串
/INCLUDE:?warp_size@cuda@at@@YAHXZ 

示例

  • 将YoloV5-LibTorch中的YoloV5.h、YoloV5.cpp放到自己的项目中
  • main函数示例如下

示例一

#include <opencv2/opencv.hpp>
#include <iostream>
#include "YoloV5.h"
int main()
{
    YoloV5 yolo(torch::cuda::is_available() ?   "C:/Users/Administrator/Desktop/TorchForCPP/materials/weights/holo2_600.torchscript.pt" : 
                                                "C:/Users/Administrator/Desktop/TorchForCPP/materials/weights/holo2_600.torchscript.pt", 
                                                torch::cuda::is_available());

    // 读取分类标签,其实这些代码无所谓,只是后面预测出来的框没有标签罢了
    std::ifstream f("C:/Users/Administrator/Desktop/TorchForCPP/materials/labels/holo.txt");
    std::string name = "";
    int i = 0;
    std::map<int, std::string> labels;
    while (std::getline(f, name))
    {
        labels.insert(std::pair<int, std::string>(i, name));
        i++;
    }

    // 读取图像
    cv::Mat img = cv::imread("C:/Users/Administrator/Desktop/TorchForCPP/materials/images/1.jpg");

    // 预测
    std::vector<torch::Tensor> r = yolo.prediction(img);

    std::cout << "图片左上为原点" <<   std::endl;
    std::cout << "左上X、左上Y、右下X、右下Y、概率、类别" <<     std::endl;
    std::cout << r[0] <<    std::endl;
    std::cout <<    std::endl;
    std::cout << r[0][0] <<     std::endl;
    std::cout <<    std::endl;
    std::cout << r[0][0][0] <<  std::endl;

    // 画框
    img = yolo.drawRectangle(img, r[0], labels);
    cv::imshow("", img);
    cv::waitKey(100000);

    return 0;
}

示例二

int main()
{
    string imgURL       = "C:/Users/Administrator/Desktop/TorchForCPP/materials/images/1.jpg";
    string weightPath   = "C:/Users/Administrator/Desktop/Holo/Materials/weights/";
    string weightGPU    = "holo2_600.torchscript.pt";           
    string weightCPU    = "holo2_600.torchscript.pt";           

    string labelsPath   = "C:/Users/Administrator/Desktop/Holo/Materials/labels/";
    string labels       = "holo.txt";               

    // 载入权重
    string weightUrlGPU = weightPath + weightGPU;
    string weightUrlCPU = weightPath + weightCPU;
    YoloV5 yolo(torch::cuda::is_available() ? weightUrlGPU : weightUrlCPU, torch::cuda::is_available());

    // 读取图像
    cv::Mat img = cv::imread(imgURL);

    // 预测
    vector<torch::Tensor> r = yolo.prediction(img);

    // 裁剪目标区
    vector<cv::Mat> imgROIs;
    for (int i = 0; i < r[0].sizes()[0]; i++)
    {
        // 左上 右下
        cv::Point leftUp(r[0][i][0].item().toDouble(), r[0][i][1].item().toDouble());
        cv::Point rightBotm(r[0][i][2].item().toDouble(), r[0][i][3].item().toDouble());

        cv::Rect rect(leftUp, rightBotm);
        imgROIs.push_back(img(rect));
    }

}
标题:YoloV5-LibTorch:C++中使用yolov5
链接:http://www.outblue.cc/209
来源:OutBlue Blog
说明:文章版权本站所有,欢迎转载分享,望能备注出处
THE END
分享
二维码
< <上一篇
下一篇>>