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


    21cc9c54b34b4959b12a52e203f895de.gif

    目录

    系列文章

    一、非常简短的介绍

    二、极其方便的上手

    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:状态预测公式

           gif.latex?" role="presentation" style="position: relative;">gif.latex?

    公式2: 噪声协方差公式

    gif.latex?" role="presentation" style="position: relative;">gif.latex?

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

    gif.latex?" role="presentation" style="position: relative;">gif.latex?

     公式4:最优估计公式

    gif.latex?" role="presentation" style="position: relative;">gif.latex?

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

    gif.latex?" role="presentation" style="position: relative;">gif.latex?

    DeepSORT流程图

    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP5q6K5bCP5q6K,size_20,color_FFFFFF,t_70,g_se,x_16

    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的 gif.latex?%5Clarge%20%5Chat%7Bx%7D_%7Bt%7D%5E%7B-%7D、covariance为公式2的gif.latex?%5Clarge%20P_%7Bt%7D%5E%7B-%7D:

    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项目就简单介绍到这里,该项目会持续更新,相信会越来越完善。

     关注订阅号了解更多精品文章

     交流探讨、商务合作请加微信

  • 相关阅读:
    MobTech MobLink Web端快速集成指南
    java毕业生设计校园社团管理系统计算机源码+系统+mysql+调试部署+lw
    window隐私保护设置(win10)
    记录spring_boot 的web开发学习
    dask读取sql数据:MySQL
    平衡车的建模与控制
    解决python使用panda模块处理CSV文件出错:keyword error
    The IDE is running low on memory and this might affect performance.
    Azure DevOps 介绍
    Linux —— 线程
  • 原文地址:https://blog.csdn.net/xian0710830114/article/details/127586654