基于 YOLOv8 的多目标跟踪 BoxMOT 部署

1.  环境

Ubuntu 20.04,Python 3.10,torch1.13 + cuda 11.6,BoxMOT 11.0.8 + ultralytics 8.2.0代码 + ultralytics 8.3.86 + ultralytics-thop 2.0.14 ,代码选择更高版本也是可以的,只是我在检测部分的改进是基于8.2.0

2.  代码准备

2.1 BoxMOT 11.0.8
  1. git clone https://github.com/mikel-brostrom/boxmot.git  或者直接下载压缩包
  2. cd boxmot
  3. pip install poetry
  4. poetry install --with yolo  # installed boxmot + yolo dependencies
  5. poetry shell  # activates the newly created environment with the installed dependencies

注意:

  • 在第四步安装 boxmot 和 yolo 依赖的时候 ,会出现Runtime Error,通过更换源解决,设置清华源:poetry config repositories.pypi https://pypi.tuna.tsinghua.edu.cn/simple  ,再重新poetry install --with yolo 即可解决,或者 poetry install --with yolo --no-cache
  •  默认安装torch 2.2.2 + cuda12.x,可能与服务器的cuda环境冲突,重新安装版本即可,如我的是torch1.13 + cuda 11.6,pip install torch==1.13.0+cu116 torchvision==0.14.0+cu116 torchaudio==0.13.0 --extra-index-url https://download.pytorch.org/whl/cu116
  • 默认下载 ultralytics 最新版本,这个影响不是很大,如果需要指定版本,在安装所有依赖后,通过 pip install ultralytics == 8.2.0 指定版本
  • 官方的第五步 poetry shell 不是必须的,第四步安装完成就可以使用了
2.2 ultralytics 8.2.0或者其他版本
  1. git clone GitHub - ultralytics/ultralytics: Ultralytics YOLO11 🚀 或者直接下载压缩包
  2. 只需要准备 ultralytics 里面的 ultralytics 文件夹,即包含assets,cfg,nn等文件夹的ultralytics,这部分也是检测阶段可能涉及改进的代码部分
  3. 将这个 ultralytics 文件夹放在boxmot/tracking目录下,以便后续代码的调用

最终的文件目录结构是这样的

3. 修改代码

修改ultralytics-trackers-track.py代码,防止 reset() Attributor Error 和 Boxes 错误,找到函数def on_predict_postprocess_end(predictor: object, persist: bool = False) -> None:

具体的错误信息我也忘了,建议先运行track.py进行测试,如果出现相同的错误,可以修改和我一样的,注意:ultralytics不同版本的track.py代码可能不一样,我8.2.0是这样的

def on_predict_postprocess_end(predictor: object, persist: bool = False) -> None:
    """
    Postprocess detected boxes and update with object tracking.

    Args:
        predictor (object): The predictor object containing the predictions.
        persist (bool, optional): Whether to persist the trackers if they already exist. Defaults to False.
    """
    path, im0s = predictor.batch[:2]

    is_obb = predictor.args.task == "obb"
    is_stream = predictor.dataset.mode == "stream"
    for i in range(len(im0s)):
        tracker = predictor.trackers[i if is_stream else 0]
        vid_path = predictor.save_dir / Path(path[i]).name
        if not persist and predictor.vid_path[i if is_stream else 0] != vid_path:
		    # 添加判断
            if hasattr(tracker, "reset") and callable(tracker.reset):
                tracker.reset()
            predictor.vid_path[i if is_stream else 0] = vid_path

        # 获取检测结果,注释原有的
        # det = (predictor.results[i].obb if is_obb else predictor.results[i].boxes).cpu().numpy()
        det = predictor.results[i].obb if is_obb else predictor.results[i].boxes

        # 确保 det 是 numpy 数组,而不是 Boxes 对象
        if isinstance(det, torch.Tensor):
            det = det.cpu().numpy()
        elif hasattr(det, 'data') and isinstance(det.data, torch.Tensor):
            det = det.data.cpu().numpy()
        else:
            raise TypeError(f"Unsupported detection type: {type(det)}")

        if len(det) == 0:
            continue

        # 更新跟踪器
        tracks = tracker.update(det, im0s[i])
        if len(tracks) == 0:
            continue

        # 更新结果
        idx = tracks[:, -1].astype(int)
        predictor.results[i] = predictor.results[i][idx]

        update_args = dict()
        update_args["obb" if is_obb else "boxes"] = torch.as_tensor(tracks[:, :-1])
        predictor.results[i].update(**update_args)

4. 运行track.py进行测试

python tracking/track.py --scource xxx.mp4 --yolo-model weights/yolov8n.pt --reid-model weights/osnet_x0_25_msmt17.pt --tracking-method botsort --save

具体参数可以在 tracking/track.py 中修改,检测和跟踪的 pt 文件在运行时会默认下载放到 tracking/weights 文件夹下,建议先下载再运行防止运行过慢,跟踪模型pt下载地址:Model Zoo — torchreid 1.4.0 documentation

经过上面的修改后,应该可以运行除了 hybridsort 和 strongsort  的其他跟踪器

5. 运行 hybridsort 和 strongsort 跟踪器

5.1 解决 --tracking-method hybridsort 时,可能出现 ValueError: too many values to unpack (expected 4),修改 boxmot-motion-kalman_filters-aabb-xysr_kf.py 为如下:
def unfreeze(self):
        if self.attr_saved is not None:
            new_history = deepcopy(list(self.history_obs))
            self.__dict__ = self.attr_saved
            self.history_obs = deque(list(self.history_obs)[:-1], maxlen=self.max_obs)
            occur = [int(d is None) for d in new_history]
            indices = np.where(np.array(occur) == 0)[0]
            
            if len(indices) < 2:
                # 如果没有足够的观测值,提前返回
                return
                
            index1, index2 = indices[-2], indices[-1]
            box1, box2 = new_history[index1], new_history[index2]
            
            # 输出调试信息
            # print("box1:", box1)
            # print("box2:", box2)
            
            # 确保有正确数量的元素用于解包
            # 注意:需要保留所有5个元素用于update,但只使用前4个用于计算
            # 提取前4个元素用于计算
            x1, y1, s1, r1 = box1.flatten()[:4]
            x2, y2, s2, r2 = box2.flatten()[:4]
            
            # 如果有第5个元素,提取它
            conf1 = box1.flatten()[4] if box1.shape[0] >= 5 else 0
            conf2 = box2.flatten()[4] if box2.shape[0] >= 5 else 0
            
            w1, h1 = np.sqrt(s1 * r1), np.sqrt(s1 / r1)
            w2, h2 = np.sqrt(s2 * r2), np.sqrt(s2 / r2)
            time_gap = index2 - index1
            dx, dy = (x2 - x1) / time_gap, (y2 - y1) / time_gap
            dw, dh = (w2 - w1) / time_gap, (h2 - h1) / time_gap
            dconf = (conf2 - conf1) / time_gap if conf1 != 0 and conf2 != 0 else 0

            for i in range(index2 - index1):
                x, y = x1 + (i + 1) * dx, y1 + (i + 1) * dy
                w, h = w1 + (i + 1) * dw, h1 + (i + 1) * dh
                s, r = w * h, w / float(h)
                
                # 计算置信度(如果有的话)
                conf = conf1 + (i + 1) * dconf if conf1 != 0 and conf2 != 0 else 0
                
                # 创建包含所有必要元素的new_box
                if conf != 0:
                    new_box = np.array([x, y, s, r, conf]).reshape((5, 1))
                else:
                    new_box = np.array([x, y, s, r]).reshape((4, 1))
                    
                self.update(new_box)
                if not i == (index2 - index1 - 1):
                    self.predict()
                    self.history_obs.pop()
            self.history_obs.pop()
5.2 解决 --tracking-method strongsort 时,无法运行,原因是strongsort 没有添加可视化功能,修改track.py :
# for r in results:

    #     img = yolo.predictor.trackers[0].plot_results(r.orig_img, args.show_trajectories)

    #     if args.show is True:
    #         cv2.imshow('BoxMOT', img)     
    #         key = cv2.waitKey(1) & 0xFF
    #         if key == ord(' ') or key == ord('q'):
    #             break

for r in results:
        if hasattr(yolo.predictor.trackers[0], 'plot_results'):
            img = yolo.predictor.trackers[0].plot_results(r.orig_img, args.show_trajectories)
        else:
            # Use an alternative plotting method or skip plotting
            img = r.orig_img  # or r.plot() if available
            
        if args.show is True:
            cv2.imshow('BoxMOT', img)
            key = cv2.waitKey(1) & 0xFF
            if key == ord(' ') or key == ord('q'):
                break

6. BoxMOT 通过 TrackEval 库进行评估,得到MOT相关指标,如HOTA MOTA IDF1等,这部分在 val.py 文件中,有时间再更

### YOLOv9与BoxMOT的安装配置及使用 #### 关于YOLOv9 目前官方并没有发布名为YOLOv9的具体版本,可能是指基于YOLO系列模型(如YOLOv8)进行了改进或是社区开发的一个变种版本。对于此类最新或非官方发布的模型,在寻找具体教程时可能会遇到困难。建议关注GitHub上的开源项目以及相关论坛获取最前沿的信息和帮助。 #### BoxMOT介绍 BoxMOT是一个用于多目标跟踪的应用框架,能够接收来自不同检测器的结果作为输入并完成后续处理工作[^1]。该工具支持多种先进的物体检测算法集成,包括但不限于YOLO家族成员。 #### 安装环境准备 为了顺利运行上述两个组件,需先搭建好Python虚拟环境: ```bash python -m venv yolov9_boxmot_env source yolov9_boxmot_env/bin/activate # Linux/MacOS 或者 yolov9_boxmot_env\Scripts\activate.bat Windows下激活命令有所不同 pip install --upgrade pip setuptools wheel ``` #### 获取源码 考虑到可能存在理解偏差,“YOLOv9”的确切实现方式未知;而对于BoxMOT,则可以直接克隆其仓库来获得最新代码: ```bash git clone https://github.com/the-vision/boxmot.git cd boxmot/ pip install -r requirements.txt ``` #### 配置YOLO检测器 假设要将某个特定版本的YOLO(比如YOLOv8)作为BoxMOT中的检测模块,可以按照如下方式进行设置: - 下载预训练权重文件; - 修改`track.py`脚本内的参数设定以匹配所使用的YOLO版本路径等信息。 ```python from ultralytics import YOLO model = YOLO('path/to/yolov8n.pt') # 加载YOLOv8 nano模型为例 results = model(source='0', stream=True, show=False, save_txt=True) for result in results: boxes = result.boxes.cpu().numpy() ... ``` 请注意实际操作过程中应依据具体的YOLO版本调整导入语句和其他细节部分。 #### 运行实例 启动BoxMOT进行视频流或多对象追踪测试: ```bash python track.py --yolo_weights path_to_your_model.pt --source 0 # '0'代表摄像头实时捕获 ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值