【动态slam】C++使用yolo模型核心代码学习

在动态SLAM中,只需要调用yolo训练好的模型就可以实现动态目标检测。本文用于总结使用yolo模型的基本逻辑。

(1)加载yolo模型

(2)获取模型输出

(3)后处理

(4)提取检测框

一类方法使用TorchScript, TorchScript允许在不依赖 Python 解释器的情况下运行模型,从而实现模型的跨平台部署和优化。这类方法使用的是.pt文件。

还有一类方法,使用opencv DNN模块调用YOLO模型。这类方法使用的是Darknet架构的YOLO,使用的是.cfg和.weights文件。对于slam调用yolo,我只在一些比较早的项目(与yolov3,yolov5结合)里看到有用这种方法的。

(1)加载yolo模型

在YoloDetect.h里,使用torch::jit::script::Module创建module对象用以加载模型。

torch::jit::script::Module mModule;

YoloDetect.cpp

构造函数: 

YoloDetection::YoloDetection()
{
    mModule = torch::jit::load("/home/slam/YOLO_ORB_SLAM3/yolov5s.torchscript.pt");

    std::ifstream f("/home/slam/YOLO_ORB_SLAM3/coco.names");
    std::string name = "";
    while (std::getline(f, name))
    {
        mClassnames.push_back(name);
    }
    mvDynamicNames = {"person", "car", "motorbike", "bus", "train", "truck", "boat", "bird", "cat",
                      "dog", "horse", "sheep", "crow", "bear"};
}

构造函数主要实现两个功能: 

①加载yolo模型.pt文件 

②读取包含分类名称的文件coco.names

 上述代码是用PyTorch C++ API(LibTorch)加载  .pt 文件,也有一些项目使用的是darknet架构的yolo,可以用opencv的dnn模块加载.weights和.cfg文件。

    String modelConfiguration = "src/yolo/yolov3.cfg";
    String modelWeights = "src/yolo/yolov3.weights";

    // Load the network
    net = readNetFromDarknet(modelConfiguration, modelWeights);

(2)获取模型输出

在 YoloDetect.cpp中

①将图片转换成张量

②调用forward函数,进行目标检测。

③将模型的输出转换为张量

②③用以下函数实现

torch::Tensor preds = mModule.forward({imgTensor}).toTuple()->elements()[0].toTensor();

(3)后处理

后处理多采用非极大值抑制的方法删除置信度低或者重叠的检测框。

std::vector<torch::Tensor> dets = YoloDetection::non_max_suppression(preds, 0.4, 0.5);

这时候操作的仍然是张量。 

(4)提取检测框

 在 YoloDetect.h中,定义一个存储cv::Rect2i对象的数组,用于存储动态物体检测框的坐标。

Opencv数据类型(二):Rect类和RotatedRect类_cv::rotatedrect-CSDN博客

 vector<cv::Rect2i> mvDynamicArea;

上面(2)(3)中,操作的都是张量。

在torch中,用封装好的Tensor类型表示:

torch::Tensor preds;

 在opencv中,用多层的矩阵模拟:

vector<Mat> outs;

其实,从OpenCV模拟张量的方式,我们就可以看出,张量,简单说,就是一个多维的信息(这里是三维)、多层的矩阵,如图所示。我们不需要深究,只需要知道每一维度在这里代表什么。

 对于一个Tensor张量dets[x][y][z];

  1. 第一维:批次维度,表示图像数量(通常为 1)。
  2. 第二维:预测框维度,表示模型生成的所有边界框(例如 15120 个预测框)。
  3. 第三维:每个预测框包含的值(例如坐标、置信度、类别)。

第一维无需在意,因为在这里只处理一张图片。我们需要的信息是:

①检测框的编号,也就是我们需要遍历图片中的每一个检测框。dets[x][y][z];

②检测框的坐标和类别信息,这个都存储在第三维里。dets[x][y][z];

知道了这些,如何提取检测框坐标和物体类别就变得很清晰了。

            float left = dets[0][i][0].item().toFloat() * mRGB.cols / 640;
            float top = dets[0][i][1].item().toFloat() * mRGB.rows / 384;
            float right = dets[0][i][2].item().toFloat() * mRGB.cols / 640;
            float bottom = dets[0][i][3].item().toFloat() * mRGB.rows / 384;
            int classID = dets[0][i][5].item().toInt();

知道了检测框的坐标,存储在对象DetectArea里。

cv::Rect2i DetectArea(left, top, (right - left), (bottom - top));

经过上述步骤,获取了yolo检测到的目标检测框,可以用于SLAM的目标检测。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值