yolov5s+deepsort检测多个视频并保存结果

yolov5s+deepsort检测追踪已经设置了读取文件夹里头的所有视频并依次检测追踪,保存的txt文件以输入视频的名字命名。但多个txt里头的信息是连续的,ID和帧号等,怎样让它依次读取多个视频,互不干扰,保存各自的信息到txt?
这是deepsort类下的update函数
def update(self, bbox_xywh, confidences, class_labels, ori_img):
        self.height, self.width = ori_img.shape[:2]
        # generate detections
        features = self._get_features(bbox_xywh, ori_img)
        bbox_tlwh = self._xywh_to_tlwh(bbox_xywh)
        detections = [Detection(bbox_tlwh[i], conf, features[i], class_labels[i]) for i, conf in enumerate(
            confidences) if conf > self.min_confidence]

        # run on non-maximum supression
        boxes = np.array([d.tlwh for d in detections])
        scores = np.array([d.confidence for d in detections])
        indices = non_max_suppression(boxes, self.nms_max_overlap, scores)
        detections = [detections[i] for i in indices]

        # update tracker
        self.tracker.predict()
        self.tracker.update(detections)

        # output bbox identities
        outputs = []
        for track in self.tracker.tracks:
            if not track.is_confirmed() or track.time_since_update > 1:
                continue
            box = track.to_tlwh()
            x1, y1, x2, y2 = self._tlwh_to_xyxy(box)
            track_id = track.track_id
            class_label = track.class_label
            outputs.append(np.array([x1, y1, x2, y2, track_id, class_label], dtype=np.int))
        if len(outputs) > 0:
            outputs = np.stack(outputs, axis=0)
        return np.array(outputs)
这是track.py的一部分
outputs = deepsort.update(xywhs, confss, leibies, im0)
                if len(outputs) > 0:
                    bbox_xyxy = outputs[:, :4]  # 提取前四列  坐标
                    identities = outputs[:, -1]  # 提取最后一列 ID
                    box_xywh = xyxy2tlwh(bbox_xyxy)
                    # xyxy2tlwh是坐标格式转换,从x1, y1, x2, y2转为top left x ,top left y, w, h 
                    for j in range(len(box_xywh)):
                        x_center = box_xywh[j][0] + box_xywh[j][2] / 2  # 求框的中心x坐标
                        y_center = box_xywh[j][1] + box_xywh[j][3] / 2  # 求框的中心y坐标
                        id = outputs[j][-1]
                        center = [x_center, y_center]
                        dict_box.setdefault(id, []).append(center)
                    COLORS_10 = (188, 143, 143)
                if len(outputs) > 0:
                    # outputs = np.append(outputs,leibie,axis=1)
                    bbox_xyxy = outputs[:, :4]
                    identities = outputs[:, -1]
                    draw_boxes(im0, bbox_xyxy, identities)
                bbox_cen = 0
                if save_txt and len(outputs) != 0:
                    video_name = os.path.splitext(os.path.basename(vid_path))[0]
                    txt_path = os.path.join(out, video_name + '.txt')
                    targets = []
                    with open(txt_path, 'a') as f:
                        for j, output in enumerate(outputs):
                            bbox_left = output[0]
                            bbox_top = output[1]
                            bbox_w = output[2]
                            bbox_h = output[3]
                            identity = output[-2]
                            car_class = output[-1]
                            a = bbox_left + (bbox_w - bbox_left) / 2
                            b = bbox_top + (bbox_h - bbox_top) / 2

                            with open(txt_path, 'a') as f:
                                f.write(('%g ' * 9 + '\n') % (identity, car_class, bbox_left,
                                                              bbox_top, bbox_w, bbox_h, a, b, frame_idx))  # label format
class DeepSort(object):
    def __init__(self, model_path, max_dist=0.2, min_confidence=0.3, nms_max_overlap=1.0, max_iou_distance=0.7, max_age=70, n_init=3, nn_budget=100, use_cuda=True, video_folder=None):
        self.min_confidence = min_confidence
        self.nms_max_overlap = nms_max_overlap

        self.extractor = Extractor(model_path, use_cuda=use_cuda)

        max_cosine_distance = max_dist
        nn_budget = 100
        metric = NearestNeighborDistanceMetric(
            "cosine", max_cosine_distance, nn_budget)
        self.tracker = Tracker(
            metric, max_iou_distance=max_iou_distance, max_age=max_age, n_init=n_init)
        self.video_folder = video_folder

# initialize deepsort
    cfg = get_config()
    cfg.merge_from_file(opt.config_deepsort)
    deepsort = DeepSort(cfg.DEEPSORT.REID_CKPT,
                        max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE,
                        nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE,
                        max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET,
                        use_cuda=True)

大致思路:
在程序开头添加一个变量来跟踪当前处理的视频文件名,可以命名为current_video_name
在读取视频帧的循环中,在每次处理帧之前,将current_video_name设置为当前视频文件的名称
在update函数中,添加一个条件判断,根据current_video_name来保存检测结果,示例:
if current_video_name not in outputs:  
    outputs[current_video_name] = np.array([x1, y1, x2, y2, track_id, class_label], dtype=np.int)
这将确保每个视频的检测结果将保存在各自对应的输出txt文件中,而不是连续保存在一个txt文件中

来自GPT的回答:

要实现多个视频的检测和追踪,并将结果保存到各自的文本文件中,可以对代码进行如下修改:

在保存文本文件时,使用视频文件的名称作为文本文件的命名。你可以通过将视频文件的基本名称与 ".txt" 扩展名结合来实现。例如,将 video_name 与 ".txt" 拼接在一起。

python
Copy code
video_name = os.path.splitext(os.path.basename(vid_path))[0]
txt_path = os.path.join(out, video_name + '.txt')
在每个视频处理的循环内,使用一个新的字典来存储每个视频的结果。可以在循环的开头使用 dict_box = {} 来创建一个空的字典。

在追踪和绘制边界框之后,将结果保存到各自的视频字典中,而不是全局的 dict_box 中。这可以通过将 dict_box 替换为视频特定的字典来实现。这样,每个视频的结果将被保存在它们自己的字典中,互不干扰。

python
Copy code
# 创建视频特定的字典
video_dict_box = {}
...
# 将结果保存到视频特定的字典中
video_dict_box.setdefault(id, []).append(center)
...
# 在绘制边界框之后,将结果保存到视频特定的字典中
if save_txt and len(outputs) != 0:
    ...
    with open(txt_path, 'a') as f:
        for j, output in enumerate(outputs):
            ...
            video_dict_box.setdefault(identity, []).append((bbox_left, bbox_top, bbox_w, bbox_h, a, b, frame_idx))
在处理完每个视频后,将视频字典中的结果保存到对应的文本文件中。这可以通过在视频循环的末尾添加保存到文本文件的代码来实现。

python
Copy code
# 保存视频字典中的结果到文本文件
with open(txt_path, 'a') as f:
    for id, bbox_list in video_dict_box.items():
        for bbox in bbox_list:
            f.write(('%g ' * 9 + '\n') % (id, bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], frame_idx))
通过上述修改,你将能够实现多个视频的检测和追踪,每个视频的结果将保存在各自的文本文件中,而且彼此之间不会产生干扰。请注意,你需要根据实际情况进行适当的调整和修改,以确保代码在你的环境中能够正常运行。

  • 这篇博客: 目标检测与跟踪 yolov5 + deepsort中的 数据集均标注txt格式 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 烟火数据集 10000+
    安全帽数据集 11000+
    口罩数据集 8000+
    抽烟数据集 7000+
    打电话数据集 10000+
    电动车数据集 未知
    睡觉数据集 未知

利用 yolov5 的高效目标检测和 deepsort 的运动和外观信息来跟踪视频中的不同对象,并为每个对象分配一个唯一的 ID
参考 https://blog.csdn.net/qq_42722197/article/details/130256915

OLOv5+DeepSORT多目标跟踪深入解读
可以参考下

https://blog.csdn.net/yohnyang/article/details/127458513
https://cloud.tencent.com/developer/article/2121746

定义一个全局的标识变量,用于记录当前跟踪的视频是哪一个,然后在记录保存信息到txt的代码中,根据这个变量的值,就可以知道当前是在跟踪哪一个视频,然后用这个变量的值,或者另取一个名称,作为文件名称作为存储txt信息的名称。

检测到视频切换后,重新保存txt

依次保存到不同的txt



import os
import threading
from yolov5s import YOLOv5S, DeepSort

# 定义检测函数
def detect_video(video_path):
    # 加载模型和配置文件
    yolo = YOLOv5S()
    config = yolo.get_config()
    model = yolo.load_model(config)
    
    # 加载跟踪器
    tracker = DeepSort()
    
    # 读取视频文件
    cap = cv2.VideoCapture(video_path)
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    # 初始化跟踪器
    track_ids = []
    tracks = []
    
    for i in range(num_frames):
        ret, frame = cap.read()
        if not ret:
            break
        
        # 对每一帧进行目标检测和跟踪
        detections, tracking_ids = model.detect(frame)
        tracked_objects = tracker.update(detections, tracking_ids)
        
        # 将跟踪结果添加到tracks列表中
        for obj in tracked_objects:
            tlbr = obj['bbox']
            track_id = obj['track_id']
            track_ids.append(track_id)
            tracks.append((tlbr[0], tlbr[1], track_id))
        
        # 将当前帧写入输出文件中
        output_path = os.path.splitext(video_path)[0] + '-frame{}.jpg'.format(i)
        cv2.imwrite(output_path, frame)
    
    # 将跟踪结果保存到txt文件中
    with open('{}-tracks.txt'.format(os.path.splitext(video_path)[0]), 'w') as f:
        for track in tracks:
            tlbr = track[0:3]
            track_id = track[3]
            f.write('{} {} {} \n'.format(tlbr[0], tlbr[1], track_id))
    
    cap.release()
    yolo.destroy()
    
# 在主函数中调用检测函数,并使用多线程处理多个视频文件
if __name__ == '__main__':
    video_folder = 'path/to/video/folder'
    os.chdir(video_folder)
    num_threads = 4 # 根据需要调整线程数
    tlist = [] # 用列表存储所有线程对象,用于启动和停止它们
    
    for video_name in os.listdir(): # 对于每个视频文件执行以下操作:
        video_path = os.path.join(video_folder, video_name) # 获取视频路径
        t = threading.Thread(target=detect_video, args=(video_path,)) # 为每个视频创建一个线程对象,并将其添加到列表中
        tlist.append(t) # 将线程对象添加到列表中以便启动和停止它们
        t.start() # 启动线程对象,开始处理视频文件
    
    for i in range(len(tlist)): # 确保所有线程都已启动后,等待它们完成任务:
        tlist[i].join() # 加入此行以防止程序退出之前未完成所有任务。如果不需要等待所有线程完成,请删除此行。

TechWhizKid参考GPT回答:

两个方法:

  1. 在处理每个新视频时重置DeepSORT跟踪器,调用DeepSORT实例的reset()方法来完成这一操作。但是你的代码中没有显示如何创建DeepSORT的实例。如果你的DeepSORT实例的名称是deepsort,可以在处理每个新视频之前,用下面的代码来重置DeepSORT:

    deepsort.tracker.reset()
    

    只重置DeepSORT的跟踪器部分,而不会影响其它部分(例如特征提取器)。如果DeepSORT的其他部分也需要被重置,可能要创建一个新的DeepSORT实例。

  2. 另一种方法是在每个视频开始时创建一个新的DeepSORT实例。将确保所有的状态都被重置,但可能会导致更高的计算开销。如果选择这种方式,可以在处理每个新视频之前使用下面的代码来创建新的DeepSORT实例:

deepsort = DeepSort(...)


以下答案参考newbing,回答由博主波罗歌编写:
根据你的描述,你想实现使用yolov5s+deepsort对多个视频进行检测和追踪,并将每个视频的结果保存到不同的txt文件中。

首先,你需要获取视频文件夹中的所有视频文件路径。你可以使用Python的os模块来实现这个功能。以下是一个示例代码:

import os

video_folder = '/path/to/video/folder'
video_files = [os.path.join(video_folder, file) for file in os.listdir(video_folder) if file.endswith('.mp4')]

接下来,你需要遍历每个视频文件,并在每个视频上运行yolov5s+deepsort。在这个过程中,你可以将每个视频的结果保存到不同的txt文件中。你可以使用视频文件的名称作为txt文件的名称。以下是一个示例代码:

for video_file in video_files:
    # 运行yolov5s+deepsort,并获取结果outputs
    
    # 保存输出到txt文件
    video_name = os.path.splitext(os.path.basename(video_file))[0]
    txt_path = os.path.join(out, video_name + '.txt')
    with open(txt_path, 'a') as f:
        # 将outputs写入txt文件
        for j, output in enumerate(outputs):
            # 写入output到txt文件
            f.write(('%g ' * 9 + '\n') % (identity, car_class, bbox_left, bbox_top, bbox_w, bbox_h, a, b, frame_idx))

在这段代码中,video_file是当前处理的视频文件路径,outputs是yolov5s+deepsort的输出结果。你需要将输出结果写入到对应的txt文件中,使用视频文件名作为txt文件名。

请记住,在你的代码中要正确导入所需的库,并将变量和参数调整到适当的位置。希望这个回答能对你有帮助!如果还有其他问题,请随时提问。
如果我的回答解决了您的问题,请采纳!