飞道的博客

【目标跟踪】pytorch实现DeepSORT+YOLOV5 YOLOFastestv2 含代码

371人阅读  评论(0)

目录

系列文章

一、非常简短的介绍

二、极其方便的上手

1.项目结构

2.执行demo

3.修改前置物体检测算法和特征提取模型 

4.修改deep_sort相关配置

三、明了清晰的代码

1.物体检测

2.提取特征

3.卡尔曼滤波predict

4.执行Matching

5.卡尔曼滤波update


 

系列文章

【目标跟踪】卡尔曼滤波器(Kalman Filter) 含源码

【目标跟踪】一图看懂DeepSORT大流程

【目标跟踪】pytorch YOLOV5 YOLOFastestv2 DeepSORT

一、非常简短的介绍

        项目链接:GitHub - oaifaye/dcmtracking

        效果演示:【目标跟踪】Pytorch实现YOLOV5+DeepSORT】 

        dcmtracking(dreams create miracles),中文:大聪明跟踪工具包。该项目构建的目的是集成当今SOTA的Tracking算法,提供算法工具箱,给出各种算法的实验数据,给算法落地带来便利。项目本着方便开发者的目的,开箱即用,直接将dcmtracking目录考到项目中,实例化一个类,然后调用即可。

        该项目现在实现了基于pytorch的YOLOV5+DeepSORT和YOLOFastestv2+DeepSORT,将持续更新,欢迎关注。

二、极其方便的上手

1.项目结构

dcmtracking                                    项目主目录

        — dcmtracking                       实现该项目所有核心功能,移植的时候直接考这个目录就可以

                — deep_sort                   deep_sort 的主目录

                        + deep                     图像提取特征的功能

                        + model_data          存放模型文件

                        + sort                      卡尔曼滤波等算法

                        + tracker                  暴露一些接口和实现类,供开发者使用

                        deep_sort.py           实现了deep_sort

                        deep_sort.yaml        deep_sort的配置文件

                — detection                     存放物体检测算法

                        yolo_fastestv2        yolo_fastestv2的主目录   

                        yolov5                     yolov5的注目录

                — utils                             工具

                demo.py                           提供可直接执行的demo

2.执行demo

        先下载一些模型问价和测试视频,网盘地址如下,目录结构已经排好,下载之后直接覆盖到项目根目录即可:

        链接:https://pan.baidu.com/s/1PjkiM2HNV20gQtCtT3oikg?pwd=902r 
        提取码:902r 

         然后,直接执行python demo.py

        如果想检测自己的视频,修改输入输出路径即可。


  
  1. if __name__ == '__main__':
  2. # 执行yolov5s+deepsort
  3. demo_yolov5_deep_sort_tracker( 'data/test5.mp4', 'data/out5.flv')
  4. # 执行yolovfastestv2+deepsort
  5. demo_yolo_fastestv2_deep_sort_tracker( 'data/test3.mp4', 'data/out3_f.flv')

3.修改前置物体检测算法和特征提取模型 

        要实现跟踪功能需要集成dcmtracking.deep_sort.tracker.base_tracker.BaseTracker.py,并实现init_extractor()和detect()方法,项目中已经提供了yolo_fastestv2_deep_sort_tracker.py和yolov5_deep_sort_tracker.py两种实现,如果不能满足要求,可以自行添加新的方法。

        detect()方法:前置的物体检测方法。一般情况下需要在实现类init方法中初始化检测模型实例。项目中默认实现了yolo_fastestv2和yolov5两种物体检测算法,并提供了基于coco数据集的预训模型,如果是检测人、车等常规任务,可以直接使用。

        init_extractor():初始化特征提取器,需要返回一个特征提取模型实例,项目中的使用一个简单的10层卷积的分类模型,推力时只取backbone,返回512的特征向量。项目提供了基于Market1501数据集的预训练模型,如果是执行人物跟踪人物,可以直接使用。

       示例代码如下:


  
  1. # coding=utf-8
  2. # ================================================================
  3. #
  4. # File name : yolov5_deep_sort_tracker.py
  5. # Author : Faye
  6. # E-mail : xiansheng14@sina.com
  7. # Created date: 2022/10/19 16:18
  8. # Description : Yolov5s+deepsort
  9. #
  10. # ================================================================
  11. from dcmtracking.deep_sort.tracker.base_tracker import BaseTracker
  12. from dcmtracking.detection.yolov5.yolo import YOLO
  13. from PIL import Image
  14. import cv2
  15. import torch
  16. from dcmtracking.deep_sort.deep.feature_extractor import Extractor
  17. class Yolov5DeepSortTracker( BaseTracker):
  18. def __init__( self, need_speed=False, need_angle=False):
  19. # 执行父类的init方法
  20. BaseTracker.__init__(self, need_speed=need_speed, need_angle=need_angle)
  21. # 初始化目标检测类
  22. self.yolo = YOLO()
  23. def init_extractor( self):
  24. """
  25. 实现父类的init_extractor方法,初始化特征提取器
  26. Parameters
  27. ----------
  28. im
  29. Returns
  30. -------
  31. """
  32. model_path = "dcmtracking/deep_sort/deep/checkpoint/ckpt.t7"
  33. return Extractor(model_path, use_cuda=torch.cuda.is_available())
  34. def detect( self, im):
  35. """
  36. 实现父类的detect方法
  37. Parameters
  38. ----------
  39. im
  40. Returns
  41. -------
  42. """
  43. im_h, im_w, _ = im.shape
  44. im_pil = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  45. im_pil = Image.fromarray(im_pil)
  46. pred_boxes = []
  47. top_label, top_boxes, top_conf = self.yolo.detect_image(im_pil)
  48. if top_label is not None:
  49. for (y1, x1, y2, x2), lbl, conf in zip(top_boxes, top_label, top_conf):
  50. if lbl != 0:
  51. continue
  52. pred_boxes.append(
  53. ( int(x1), int(y1), int(x2), int(y2), lbl, conf))
  54. return im, pred_boxes

4.修改deep_sort相关配置

        deep_sort的配置文件是dcmtracking/deep_sort/deep_sort.yaml,里面的配置如下:


  
  1. DEEPSORT:
  2. # 物体匹配的阈值。距离较大的样本被认为是无效匹配。
  3. MAX_DIST: 0.5
  4. # 最小置信度,小于这个值,认为是无效物体
  5. MIN_CONFIDENCE: 0.3
  6. # 执行nms时,最大重叠占比,两个bbox的iou大于这个值,将认为是同一物体
  7. NMS_MAX_OVERLAP: 0.5
  8. # 执行IOU匹配时,大于此值的关联被忽略。
  9. MAX_IOU_DISTANCE: 0.7
  10. # 在删除track之前的最大miss数。
  11. MAX_AGE: 70
  12. # 在一个track被确认之前的连续探测次数。如果在第一个n_init帧内发生miss,则track状态被设置为' Deleted '。
  13. N_INIT: 3
  14. # 是否需要在原图上画框
  15. NEED_DRAW_BBOXES: False
  16. # 是否需要标注速度,速度单位pix/s,只有need_draw_bboxes=True时起作用
  17. NEED_SPEED: True
  18. # 是否需要标注运动方向,只有need_draw_bboxes=True时起作用
  19. NEED_ANGLE: True

三、明了清晰的代码

为了更好地理解代码,推荐大家先看一下下面两篇文章:

文章一:卡尔曼滤波相关: 【五分钟会,半小时懂】卡尔曼滤波器(Kalman Filter)—目标跟踪(含源码)_小殊小殊的博客-CSDN博客_卡尔曼滤波多目标跟踪

文章二:DeepSORT整个大流程:

一图看懂DeepSORT整个大流程,多目标跟踪_小殊小殊的博客-CSDN博客_deepsort多目标跟踪

为了方便我把文章一中的公式和文章二中的流程图直接拿过来:

公式1:状态预测公式

       

公式2: 噪声协方差公式

 公式3:K卡尔曼系数公式

 公式4:最优估计公式

 公式5:噪声协方差矩阵更新公式

DeepSORT流程图

 

1.物体检测

        对视频每一帧执行物体检测,对应流程图中步骤3。

        代码位置:dcmtracking/deep_sort/tracker/base_tracker.py的deal_one_frame方法中,self.detect()返回图像本身和bbox信息,该方法需要在base_tracker.py的实现类中实现具体检测算法,代码如下:


  
  1. def deal_one_frame( self, image, speed_skip, need_detect=True):
  2. """
  3. 处理视频中的一帧
  4. Parameters
  5. ----------
  6. image:cv2读取的视频帧
  7. speed_skip:用于计算速度,一般传fps
  8. need_detect:知否需要执行目标检测,如果传False将使用上一次检测的结果,该参数主要用于加速
  9. Returns
  10. -------
  11. im: 返回画好框的图片
  12. ids: 这一帧出现的目标ids
  13. bboxes: 这一帧出现的目标框坐标,左上和右下
  14. """
  15. self.frames_count += 1
  16. if self.last_deepsort_outputs is None or need_detect:
  17. t1 = time.time()
  18. # 1.执行目标检测
  19. _, bboxes = self.detect(image)
  20. ......

2.提取特征

        提取bbox中图像的特征向量,并新建Detections。

        代码位置:dcmtracking/deep_sort/deep_sort.py的update方法:


  
  1. def update( self, bbox_xywh, confidences, ori_img):
  2. """
  3. 根据目标检测的结果,执行跟踪、更新DeepSort历史状态
  4. Parameters
  5. ----------
  6. extractor:图像特征提取器
  7. bbox_xywh:目标框的中心点和宽高
  8. confidences:置信度
  9. ori_img:图片
  10. Returns
  11. -------
  12. """
  13. self.height, self.width = ori_img.shape[: 2]
  14. # 将图片按照bbox切割 每块生成特征向量(特征向量默认长度512)
  15. features = self._get_features(bbox_xywh, ori_img)
  16. # 将左上右下的四个坐标 转换成中心点和宽高
  17. bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)
  18. # 根据features和bbox_tlwh生成detections 每个detection有features/tlwh/confidence 三个属性
  19. detections = [Detection(bbox_tlwh[i], conf, features[i]) for i,conf in enumerate(confidences) if conf > self.min_confidence]
  20. # 执行nms 去掉重复的detection 其实在目标检测阶段已经做了nms 这里不做也行
  21. boxes = np.array([d.tlwh for d in detections])
  22. scores = np.array([d.confidence for d in detections])
  23. indices = non_max_suppression(boxes, self.nms_max_overlap, scores)
  24. detections = [detections[i] for i in indices]
  25. ......

3.卡尔曼滤波predict

        执行卡尔曼滤波的predict操作,即使用上一轮次的结果计算本轮的预测值。

        代码位置:dcmtracking/deep_sort/sort/kalman_filter.py中的predict()方法,对应图中步骤1,实现了公式1和2,返回值mean为公式1的 、covariance为公式2的:


  
  1. def predict( self, mean, covariance):
  2. """执行卡尔曼滤波的predict步骤.
  3. Parameters
  4. ----------
  5. mean : ndarray
  6. 前一个轮次的物体状态的8维向量的期望(均值)。
  7. covariance : ndarray
  8. 前一个轮次的物体状态的8x8维协方差矩阵
  9. Returns
  10. -------
  11. (ndarray, ndarray)
  12. 返回预测状态的平均向量和协方差矩阵。未观测到的速度初始化为平均值0。
  13. """
  14. std_pos = [
  15. self._std_weight_position * mean[ 3],
  16. self._std_weight_position * mean[ 3],
  17. 1e-2,
  18. self._std_weight_position * mean[ 3]]
  19. std_vel = [
  20. self._std_weight_velocity * mean[ 3],
  21. self._std_weight_velocity * mean[ 3],
  22. 1e-5,
  23. self._std_weight_velocity * mean[ 3]]
  24. motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
  25. mean = np.dot(self._motion_mat, mean)
  26. covariance = np.linalg.multi_dot((
  27. self._motion_mat, covariance, self._motion_mat.T)) + motion_cov
  28. return mean, covariance

4.执行Matching

        Matching分为两步,一个matching_cascade和iou_matching(两种匹配的集体解释请看文章),对应图中步骤4567。

        代码位置:dcmtracking/deep_sort/sort/tracker.py的_match()方法:


  
  1. def _match( self, detections):
  2. def gated_metric( tracks, dets, track_indices, detection_indices):
  3. """
  4. 基于外观信息和马氏距离,计算卡尔曼滤波预测的tracks和当前时刻检测到的detections的代价矩阵
  5. Parameters
  6. ----------
  7. tracks
  8. dets
  9. track_indices
  10. detection_indices
  11. Returns
  12. -------
  13. cost_matrix 代价矩阵
  14. """
  15. features = np.array([dets[i].feature for i in detection_indices])
  16. targets = np.array([tracks[i].track_id for i in track_indices])
  17. # 基于外观的特征向量,计算tracks和detections的余弦距离代价矩阵
  18. cost_matrix = self.metric.distance(features, targets)
  19. # 基于马氏距离,过滤掉代价矩阵中一些不合适的项 (将其设置为一个较大的值)
  20. cost_matrix = linear_assignment.gate_cost_matrix(
  21. self.kf, cost_matrix, tracks, dets, track_indices,
  22. detection_indices)
  23. return cost_matrix
  24. # 将已经存在的tracks分成已确定和未确定,感觉这里可以优化
  25. confirmed_tracks = [
  26. i for i, t in enumerate(self.tracks) if t.is_confirmed()]
  27. unconfirmed_tracks = [
  28. i for i, t in enumerate(self.tracks) if not t.is_confirmed()]
  29. # 对confirmd tracks进行级联匹配
  30. matches_a, unmatched_tracks_a, unmatched_detections = \
  31. linear_assignment.matching_cascade(
  32. gated_metric, self.metric.matching_threshold, self.max_age,
  33. self.tracks, detections, confirmed_tracks)
  34. # 对级联匹配中未匹配的tracks和unconfirmed tracks中time_since_update为1的tracks进行IOU匹配
  35. iou_track_candidates = unconfirmed_tracks + [
  36. k for k in unmatched_tracks_a if
  37. self.tracks[k].time_since_update == 1]
  38. unmatched_tracks_a = [
  39. k for k in unmatched_tracks_a if
  40. self.tracks[k].time_since_update != 1]
  41. matches_b, unmatched_tracks_b, unmatched_detections = \
  42. linear_assignment.min_cost_matching(
  43. iou_matching.iou_cost, self.max_iou_distance, self.tracks,
  44. detections, iou_track_candidates, unmatched_detections)
  45. # 整合所有的匹配对和未匹配的tracks
  46. matches = matches_a + matches_b
  47. unmatched_tracks = list( set(unmatched_tracks_a + unmatched_tracks_b))
  48. return matches, unmatched_tracks, unmatched_detections

5.卡尔曼滤波update

         执行卡尔曼滤波的update步骤,对观测值进行校正,实现公式345,分别对应下方代码注释中的123;对应流程图中的步骤11、12、13。

        代码位置:dcmtracking/deep_sort/sort/kalman_filter.py的update方法:


  
  1. def update( self, mean, covariance, measurement):
  2. """卡尔曼滤波的update步骤,对观测值进行校正。
  3. Parameters
  4. ----------
  5. mean : ndarray
  6. 预测状态的平均向量(8维)。
  7. covariance : ndarray
  8. 状态的协方差矩阵(8x8维)。
  9. measurement : ndarray
  10. 4维测量向量(x, y, a, h),其中(x, y)是中心位置,a是纵横比,h是包围框的高度。
  11. Returns
  12. -------
  13. (ndarray, ndarray)
  14. 返回经过测量校正的状态分布。
  15. """
  16. # 1.计算卡尔曼增益K
  17. projected_mean, projected_cov = self.project(mean, covariance)
  18. chol_factor, lower = scipy.linalg.cho_factor(
  19. projected_cov, lower= True, check_finite= False)
  20. kalman_gain = scipy.linalg.cho_solve(
  21. (chol_factor, lower), np.dot(covariance, self._update_mat.T).T,
  22. check_finite= False).T
  23. innovation = measurement - projected_mean
  24. # 2.计算当前步最优估计
  25. new_mean = mean + np.dot(innovation, kalman_gain.T)
  26. # 3.更新过程噪声协方差矩阵
  27. new_covariance = covariance - np.linalg.multi_dot((
  28. kalman_gain, projected_cov, kalman_gain.T))
  29. return new_mean, new_covariance

        dcmtracking项目就简单介绍到这里,该项目会持续更新,相信会越来越完善。

 

 


转载:https://blog.csdn.net/xian0710830114/article/details/127586654
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场