YOLOv7结合DeepSORT追踪时目标ID频繁变更问题求助
问题:YOLOv7+DeepSORT目标追踪时ID频繁变更
我使用YOLOv7和DeepSORT算法对特定区域内的目标进行检测追踪,但所有视频帧中的目标ID始终在变化,3帧截图示例如下:


可以看到每帧的目标ID都不相同。
我使用的代码如下:
#class base virtual zone tracking import random import torch import numpy as np from models.experimental import attempt_load from utils.torch_utils import TracedModel from utils.datasets import letterbox from utils.plots import plot_one_box, plot_one_box_center from utils.general import check_img_size, non_max_suppression, scale_coords import cv2 import time from google.colab.patches import cv2_imshow from shapely.geometry import Point from shapely.geometry.polygon import Polygon #deep sort import os import tensorflow as tf physical_devices = tf.config.experimental.list_physical_devices('GPU') if len(physical_devices) > 0: tf.config.experimental.set_memory_growth(physical_devices[0], True) from tensorflow.compat.v1 import ConfigProto from deep_sort.tracker import Tracker from deep_sort.detection import Detection import matplotlib.pyplot as plt from deep_sort import preprocessing, nn_matching from tracking_helpers import read_class_names, create_box_encoder from detection_helpers import * class YOLOv7: def __init__(self, weights: str, image_size:int,device:str): self.device = device self.weights = weights self.model = attempt_load(self.weights, map_location=self.device) # Model Load FP32 self.stride = int(self.model.stride.max()) self.image_size = check_img_size(image_size, self.stride) if self.device != 'cpu': self.half = True else: self.half = False if self.half: self.model.half() # FP16 self.names = self.model.module.names if hasattr(self.model , 'module') else self.model.names color_values = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(self.names))] self.colors = {i:color_values[i] for i in range(len(self.names))} def detect(self, raw_image: np.ndarray, conf_thresh =0.45, iou_thresh =0.45, classes = [0]): #default class people # Run inference if self.device != 'cpu': self.model(torch.zeros(1, 3, self.image_size, self.image_size).to(self.device).type_as(next(self.model.parameters()))) with torch.no_grad(): image = letterbox(raw_image, self.image_size, stride=self.stride)[0] image = image[:, :, ::-1].transpose(2, 0, 1) image = np.ascontiguousarray(image) image = torch.from_numpy(image).to(self.device) image = image.half() if self.half else image.float() image /= 255.0 if image.ndimension() == 3: image = image.unsqueeze(0) # Inference detections = self.model(image, augment=False)[0] # Apply NMS detections = non_max_suppression(detections, conf_thresh, iou_thresh, classes=classes, agnostic=False)[0] # Rescale boxes from img_size to raw image size detections[:, :4] = scale_coords(image.shape[2:], detections[:, :4], raw_image.shape).round() return detections def tracking(self, video_frame, yolo_dets, inside_poly = True, count_objects:bool=False,verbose=False, reID_model_path = "./deep_sort/model_weights/mars-small128.pb", nms_max_overlap:float=1.0, max_cosine_distance:float=0.4, nn_budget:float=None): class_names = read_class_names() encoder = create_box_encoder(reID_model_path, batch_size=1) nms_max_overlap = nms_max_overlap metric = nn_matching.NearestNeighborDistanceMetric("cosine", max_cosine_distance, nn_budget) tracker = Tracker(metric) *xyxy, conf, cls = yolo_dets frame = cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB) if yolo_dets is None: bboxes = [] scores = [] classes = [] num_objects = 0 else: bboxes = yolo_dets[:,:4] bboxes[:,2] = bboxes[:,2] - bboxes[:,0] # convert from xyxy to xywh bboxes[:,3] = bboxes[:,3] - bboxes[:,1] scores = yolo_dets[:,4] classes = yolo_dets[:,-1] num_objects = bboxes.shape[0] #how many object you track names = [] for i in range(num_objects): # loop through objects and use class index to get class name class_indx = int(classes[i]) class_name = class_names[class_indx] names.append(class_name) names = np.array(names) count = len(names) if count_objects: cv2.putText(frame, "both inside and outside the polygon detection: {}".format(count), (5, 35), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5, (0, 0, 0), 2) # DeepSORT tacker work starts here features = encoder(frame, bboxes) # encode detections and feed to tracker. [No of BB / detections per frame, embed_size] detections = [Detection(bbox, score, class_name, feature) for bbox, score, class_name, feature in zip(bboxes, scores, names, features)] # [No of BB per frame] deep_sort.detection.Detection object cmap = plt.get_cmap('tab20b') #initialize color map colors = [cmap(i)[:3] for i in np.linspace(0, 1, 20)] boxs = np.array([d.tlwh for d in detections]) # run non-maxima supression below scores = np.array([d.confidence for d in detections]) classes = np.array([d.class_name for d in detections]) indices = preprocessing.non_max_suppression(boxs, classes, nms_max_overlap, scores) detections = [detections[i] for i in indices] tracker.predict() # Call the tracker tracker.update(detections) # updtate using Kalman Gain for track in tracker.tracks: # update new findings AKA tracks #if not track.is_confirmed() or track.time_since_update > 1: #continue bbox = track.to_tlbr() class_name = track.get_class() color = colors[int(track.track_id) % len(colors)] # draw bbox on screen color = [i * 255 for i in color] #drawing poly #pts = np.array([[6,449], [1052, 2], [1914, 6], [1766, 1074], [2, 1076]]) #frame = cv2.polylines(frame, [pts], True, (0,0,255), 5) #creating poly #poli = Polygon([(6,449), (1052, 2), (1914, 6), (1766, 1074), (2, 1076)]) #center = (int((bbox[0] + bbox[2]) / 2), int((bbox[1] + bbox[3]) / 2)) #center point ( (x1 + x2) / 2, (y1 + y2) / 2 ) #point = Point(center) if inside_poly: #drawing poly pts = np.array([[6,449], [1052, 2], [1914, 6], [1766, 1074], [2, 1076]]) frame = cv2.polylines(frame, [pts], True, (0,0,255), 5) #creating poly poli = Polygon([(6,449), (1052, 2), (1914, 6), (1766, 1074), (2, 1076)]) center = (int((bbox[0] + bbox[2]) / 2), int((bbox[1] + bbox[3]) / 2)) #center point ( (x1 + x2) / 2, (y1 + y2) / 2 ) point = Point(center) if poli.contains(point): cv2.rectangle(frame, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), color, 2) cv2.rectangle(frame, (int(bbox[0]), int(bbox[1]-30)), (int(bbox[0])+(len(class_name)+len(str(track.track_id)))*17, int(bbox[1])), color, -1) cv2.putText(frame, class_name + " : " + str(track.track_id),(int(bbox[0]), int(bbox[1]-11)),0, 0.6, (255,255,255),1, lineType=cv2.LINE_AA) cv2.putText(frame, "0", center,0, 0.6, (255,255,255),1, lineType=cv2.LINE_AA) else: cv2.rectangle(frame, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), color, 2) cv2.rectangle(frame, (int(bbox[0]), int(bbox[1]-30)), (int(bbox[0])+(len(class_name)+len(str(track.track_id)))*17, int(bbox[1])), color, -1) cv2.putText(frame, class_name + " : " + str(track.track_id),(int(bbox[0]), int(bbox[1]-11)),0, 0.6, (255,255,255),1, lineType=cv2.LINE_AA) if verbose == 2: print("Tracker ID: {}, Class: {}, BBox Coords (xmin, ymin, xmax, ymax): {}".format(str(track.track_id), class_name, (int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])))) result = np.asarray(frame) result = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) return result if __name__=='__main__': yolov7=YOLOv7(weights='yolov7x.pt', device='cpu', image_size=800) cap = cv2.VideoCapture('street5sn.mp4') torch.cuda.empty_cache() #writer width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # by default VideoCapture returns float instead of int height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = int(cap.get(cv2.CAP_PROP_FPS)) codec = cv2.VideoWriter_fourcc(*"DIVX") out = cv2.VideoWriter("./output/video_out_track5sn-d2.mp4", codec, fps, (width, height)) while True: t1 = time.time() ret, frame = cap.read() if not ret: break detections=yolov7.detect(frame) vir = yolov7.tracking(frame, detections, count_objects = True, inside_poly = False) out.write(vir) cv2_imshow(vir) #colab imshow kodu print("add frame ...") if cv2.waitKey(1) & 0xFF == ord('q'): break out.release() cap.release() cv2.destroyAllWindows()
我使用的是公开仓库代码,未对其他文件做任何修改,请求解决目标ID频繁变更的问题。
问题根源与修复方案
1. 核心错误:每帧重新初始化追踪器
你的tracking方法里,每次调用都会重新创建encoder、metric和Tracker实例:
encoder = create_box_encoder(reID_model_path, batch_size=1) metric = nn_matching.NearestNeighborDistanceMetric("cosine", max_cosine_distance, nn_budget) tracker = Tracker(metric)
这会导致每帧的追踪状态完全重置,追踪器无法记住上一帧的目标信息,自然会给每个目标分配新ID。
修复方法:把这些初始化代码移到类的__init__方法里,让追踪器在整个视频处理过程中只初始化一次,持续保留追踪状态。
修改后的类初始化方法:
class YOLOv7: def __init__(self, weights: str, image_size:int,device:str, reID_model_path = "./deep_sort/model_weights/mars-small128.pb", nms_max_overlap:float=1.0, max_cosine_distance:float=0.4, nn_budget:float=None): self.device = device self.weights = weights self.model = attempt_load(self.weights, map_location=self.device) # Model Load FP32 self.stride = int(self.model.stride.max()) self.image_size = check_img_size(image_size, self.stride) if self.device != 'cpu': self.half = True else: self.half = False if self.half: self.model.half() # FP16 self.names = self.model.module.names if hasattr(self.model , 'module') else self.model.names color_values = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(self.names))] self.colors = {i:color_values[i] for i in range(len(self.names))} # 初始化DeepSORT相关组件,仅执行一次 self.class_names = read_class_names() self.encoder = create_box_encoder(reID_model_path, batch_size=1) self.nms_max_overlap = nms_max_overlap self.metric = nn_matching.NearestNeighborDistanceMetric("cosine", max_cosine_distance, nn_budget) self.tracker = Tracker(self.metric) # 初始化颜色映射 self.cmap = plt.get_cmap('tab20b') self.track_colors = [self.cmap(i)[:3] for i in np.linspace(0, 1, 20)]
修改后的tracking方法(移除重复初始化代码,使用类实例属性):
def tracking(self, video_frame, yolo_dets, inside_poly = True, count_objects:bool=False,verbose=False): frame = cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB) if yolo_dets is None or len(yolo_dets) == 0: bboxes = [] scores = [] classes = [] num_objects = 0 else: bboxes = yolo_dets[:,:4] bboxes[:,2] = bboxes[:,2] - bboxes[:,0] # convert from xyxy to xywh bboxes[:,3] = bboxes[:,3] - bboxes[:,1] scores = yolo_dets[:,4] classes = yolo_dets[:,-1] num_objects = bboxes.shape[0] # 生成目标类别名称 names = [] for i in range(num_objects): class_indx = int(classes[i]) class_name = self.class_names[class_indx] names.append(class_name) names = np.array(names) count = len(names) if count_objects: cv2.putText(frame, "both inside and outside the polygon detection: {}".format(count), (5, 35), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.5, (0, 0, 0), 2) # DeepSORT追踪流程 features = self.encoder(frame, bboxes) detections = [Detection(bbox, score, class_name, feature) for bbox, score, class_name, feature in zip(bboxes, scores, names, features)] boxs = np.array([d
相关产品推荐
相关产品推荐

