提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
关于yolov5+deepsort实现目标检测与跟踪中deepsort特征提取的一种折中方法C++
前言
提示:这里可以添加本文要记录的大概内容:
deepsort是一种基于深度学习的多目标跟踪算法,主要原理本文不再描述,网上内容较多,个人理解其主要思想是在传统的sort算法的基础上,添加一块待跟踪目标的特征信息,即目标的feature,这样在后续进行关联匹配的时候能提升准确率。目前网上较多的资源是基于https://github.com/RichardoMrMu/yolov5-deepsort-tensorrt这位大神提供开源程序,他的tensorrt为7的版本,最近由于项目中需要添加这个deepsort,但是开发的机器刚装完tensorrt8,实在不想捣鼓环境版本,又结合Tensorrt大佬提供的项目https://github.com/shouxieai/tensorRT_Pro/,其中关于人脸跟踪的程序,本文想出了一个比较折中的方案,借助OpenCV的DNN实现deepsort的feature抽取(主要是目前技术水平太菜了,对于Tensorrt的掌握还不够,只能用这种折中的方法先应付项目),最终效果还可以,关于借助Tensorrt部署yolov5,本文并不再描述,网上资源较多,本文只描述如何使用OpenCV的DNN实现deepsort的feature抽取。
提示:以下是本篇文章正文内容,下面案例可供参考
一、开发环境
Ubuntu18.04 + CUDA11.0 + cuDNN8.2 + TensorRT8.2 + OpenCV4.5.3 在安装OpenCV的过程中,需要将CUDA加速的部分编译进去,安装教程网上较多,可以先安装cmake-gui方便安装过程中配置,具体安装可以自行百度。
二、开始实战
1.将deepsort权重导出为.onnx
首先需要将deepsort算法中的权重文件导出为.onnx的格式 通过如下指令下载相关的开源程序
git clone https://github.com/RichardoMrMu/deepsort-tensorrt.git
然后进入到下载到的程序中,运行exportOnnx.py即可将deepsort的权重ckpt.t7转换为.onnx,在转换的过程中,请先看一下程序的内容,避免转换过程出错,转换完成之后,会生成一个deepsort.onnx的文件,将该文件复制到你的yolov5+deepsort工程文件夹中即可。
python3 exportOnnx.py
这个deepsort的权重ckpt.t7可以在下面链接中找到并下载 https://github.com/ZQPei/deep_sort_pytorch
2.主要程序
完成了上述权重的转换之后,即可通过如下的程序抽取到待跟踪目标的feature了,可以将此段程序添加进你的yolov5目标检测中,实现yolov5+deepsort目标检测与跟踪。
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/cuda.hpp>
......
int main(int argc, char** argv)
{
......
cv::String deepsort_onnx = "/home/xx/xx/xx/xx/xx/deepsort.onnx";
const int inpWidth = 64;
const int inpHeight = 128;
cv::dnn::Net net;
net = cv::dnn::readNet(deepsort_onnx);
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
......
std::vector<DeepSORT::Box> boxes;
DeepSORT::Box track_box;
cv::Rect feature_track;
cv::Mat feature_image;
.......
track_box.left = result.left;
track_box.top = result.top;
track_box.right = result.right;
track_box.bottom = result.bottom;
#ifdef DEBUG
printf("track_box.left=%.2f, track_box.top=%.2f, track_box.right=%.2f, track_box.bottom=%.2f", track_box.left, track_box.top, track_box.right, track_box.bottom);
#endif
if ((track_box.left > 0 && track_box.top > 0 && track_box.right > 0 && track_box.bottom > 0) &&
(track_box.left < frame.cols && track_box.top < frame.rows && track_box.right < frame.cols && track_box.bottom < frame.rows))
{
feature_track = cv::Rect(result.left, result.top, (result.right - result.left), (result.bottom - result.top));
feature_image = frame(feature_track);
cv::Mat blob;
cv::dnn::blobFromImage(feature_image, blob, 1 / 255.0, cv::Size(inpWidth, inpHeight), cv::Scalar(0, 0, 0), true, false);
net.setInput(blob);
std::vector<cv::Mat> outs;
net.forward(outs, net.getUnconnectedOutLayersNames());
#ifdef DEBUG
std::cout << "+++++ outs.size=" << outs.size() << "+++++" << std::endl;
#endif
track_box.feature = outs[0];
boxes.push_back(track_box);
}
......
tracker->update(boxes);
......
......
}
总结
第一次写CSDN的文章,有点生疏,难免有点错误,希望各位看到的时候能够在下方评论指正,谢谢!大家有什么想法也可以在评论区评论交流。其实,本文也只是记录一下本人在项目实际开发的过程中想到的一个想法,并且实际操作了一下,如果对你的项目开发能起到一丁点的帮助,我将无比荣幸!其实,从deepsort的权重中可以看出,最终输出的是一个1x512的特征矩阵,在实际跟踪的时候,获取到了这个特征矩阵,并将其做一个转置矩阵,得到一个512x1的矩阵,两个一乘就有了一个值,通过这个值就加强了目标跟踪中的匹配准确性。在上方,本文说了,这个方法是由于本人技术太菜,并未完全掌握TensorRT想出来的一个折中方法,结合deepsort的原理,这个目标的feature其实在yolo检测目标的时候已经获得过了,那么我们能不能在yolo检测目标的时候,顺带把这个feature一并输出,就是说在推理yolo的时候,除了获得一个boundingbox,顺带再获得一个跟这个boundingbox相匹配的feature,相当于在程序中我最终输出的result的结构体中还包含一个feature的成员,这个feature只要是个1xn的矩阵即可,反正后面会做一个转置运算,当然了,这只是本人的一个想法,也不知道行不行,等后续掌握了TensortRT之后,再魔改一下yolo的推理程序,试试看看,本文先到此为止,感谢阅读!
|