import

sys.path.insert(0, './yolov5')

- sys.path=E:\Yolov5\DeepSort\Yolov5_DeepSort\Yolov5_DeepSort
- track.py是 YOLOv5 的目标跟踪脚本,通常需要调用 yolov5 目录下的模块。
串口

port_list = list(serial.tools.list_ports.comports())获取当前计算机上所有可用的串口设备列表,并转换为 Python 列表。if len(port_list) == 0:如果 port_list 为空(len(port_list) == 0),打印 'none',表示未检测到任何串口设备。
否则,遍历列表并逐个打印每个串口的详细信息(如名称、描述、制造商等)。
portName = "COM3" # 端口名
baudRate = 9600 # 波特率
timeOut = 3
portName:指定要使用的串口名称(如 COM3 是 Windows 下的典型串口名,Linux/Mac 下可能是 /dev/ttyUSB0)。
baudRate:设置通信波特率(常见值如 9600、115200 等),需与设备端配置一致。
timeOut:设置串口读取超时时间(秒),超过该时间未收到数据则抛出异常。- 作用:
硬件交互:与 Arduino、传感器或其他通过串口通信的设备连接。
调试:确认系统中可用的串口设备,避免手动输入错误端口名。
初始化配置:为后续的串口通信(如 serial.Serial(portName, baudRate, timeout=timeOut))提供参数。
palette
palette = (2 ** 11 - 1, 2 ** 15 - 1, 2 ** 20 - 1)生成一个包含三个整数的元组,用于表示某种颜色或ID的调色板(Palette)。
2 ** 11 - 1 = 2047
(二进制:11111111111,11位全1)
2 ** 15 - 1 = 32767
(二进制:111111111111111,15位全1)
2 ** 20 - 1 = 1048575
(二进制:11111111111111111111,20位全1)

datect

initialize deepsort

cfg = get_config()调用 get_config() 函数获取一个默认的配置对象(通常是一个 Config 或 EasyDict 类型的对象)。

cfg.merge_from_file(opt.config_deepsort)从文件 opt.config_deepsort(路径由命令行参数 opt 提供)加载 DeepSort 的配置文件,并合并到 cfg 中。

REID_CKPT:指定 ReID(重识别)模型的权重文件路径。
MAX_DIST: 特征匹配的最大余弦距离阈值。当两个目标的特征向量距离超过 0.2 时,认为它们不匹配。值越小,匹配越严格。
MIN_CONFIDENCE:检测结果的最小置信度阈值。忽略置信度低于 0.3 的检测框.
NMS_MAX_OVERLAP:非极大值抑制(NMS)的重叠阈值。若两个检测框的 IoU(交并比)超过 0.5,则保留置信度更高的框,抑制另一个。
MAX_IOU_DISTANCE:ioU 距离的最大阈值,用于关联检测框和跟踪轨迹。当检测框与预测轨迹的 IoU 距离 ≤ 0.7 时,认为它们可能属于同一目标。
MAX_AGE:轨迹的最大存活帧数,若轨迹连续 70 帧未被匹配到检测框,则删除该轨迹。
N_INIT:新检测目标需连续 3 帧成功匹配,才确认为有效轨迹
NN_BUDGET: 每个轨迹最多保留 100 个历史特征,用于后续匹配,平衡内存和跟踪精度。if os.path.exists(out):检查输出目录 out 是否已存在。如果目录存在,可能需要先删除旧数据以避免冲突。shutil.rmtree(out)递归删除输出目录 out 及其所有内容.确保每次运行时输出目录是空的,避免旧结果干扰新结果os.makedirs(out)重新创建输出目录 out。half = device.type != 'cpu'根据设备类型决定是否启用半精度(FP16)计算。
evice.type 是运行设备(如 'cuda' 或 'cpu')。
半精度(half=True)仅支持 GPU(CUDA),可加速计算并减少显存占用。
如果是 CPU 运行,则强制使用全精度(half=False)。
load model

model = attempt_load(yolo_weights, map_location=device)
加载预训练的 YOLO 模型。
yolo_weights:YOLO 模型权重文件的路径(如 yolov5s.pt)。
map_location=device:指定模型加载的设备(如 'cuda:0' 或 'cpu')。
默认加载全精度(FP32)模型。stride = int(model.stride.max())
获取模型的最大步长(stride)。stride 是 YOLO 模型下采样的倍数(如 8、16、32),影响输入图像的尺寸要求。YOLOv5 的 stride 通常是 32(最终特征图的缩放比例)。imgsz = check_img_size(imgsz, s=stride)check_img_size 确保 imgsz 是 stride 的整数倍(避免尺寸对齐问题)。
例如,若 stride=32,imgsz=640 会被接受,而 imgsz=641 会被调整为 640。names = model.module.names if hasattr(model, 'module') else model.names
获取模型训练的类别名称列表

if half: model.half()将模型转换为半精度(FP16)模式。vid_path, vid_writer = None, None初始化视频路径和视频写入器变量为 None。show_vid = check_imshow()检查当前环境是否支持图像显示
check_imshow():通常尝试创建一个测试窗口,验证是否支持 cv2.imshow()。
如果环境不支持(如无 GUI 的服务器),则 show_vid 会被设为 False,避免显示报错。cudnn.benchmark = True启用 cuDNN 的自动优化模式,加速固定尺寸图像的推理(适用于摄像头输入分辨率不变的情况)。
Run inference

model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters())))模型预热(Warm-up)。
生成一个全零的虚拟输入张量,形状为 (1, 3, imgsz, imgsz)(批大小 1,3 通道,尺寸 imgsz x imgsz)。
to(device):将张量移动到指定设备(GPU/CPU)。
type_as(...):确保张量数据类型与模型参数一致(如 FP16/FP32)。
执行一次前向推理(model(...))。
初始化 GPU 的 CUDA 上下文,避免首次正式推理时的延迟。
模型推理 NMS/process/detections

for frame_idx, (path, img, im0s, vid_cap) in enumerate(dataset):
从数据加载器 dataset 中逐帧读取数据,返回:
path:当前帧的路径(如视频文件路径或摄像头索引)。
img:预处理后的图像(尺寸调整、归一化等,形状为 [H, W, C] 或 [B, H, W, C])。
im0s:原始图像(未缩放的 OpenCV 格式,用于可视化或保存结果)。
vid_cap:视频捕获对象(仅视频文件有效)。img = torch.from_numpy(img).to(device)将 img 转换为 PyTorch 张量并移动到指定设备(GPU/CPU)。img = img.half() if half else img.float() # uint8 to fp16/32根据 half 参数选择半精度(FP16)或全精度(FP32)。img /= 255.0 # 0 - 255 to 0.0 - 1.0归一化像素值到 [0.0, 1.0] 范围。if img.ndimension() == 3:img = img.unsqueeze(0)如果输入是单张图像(ndimension() == 3),增加批次维度(unsqueeze(0))。t1 = time_synchronized()time_synchronized():同步 GPU 操作并记录时间戳 t1(用于计算推理耗时)。pred = model(img, augment=opt.augment)[0]
执行模型推理:augment:是否启用数据增强(如多尺度测试)。
pred:模型的原始输出(未处理的检测框,形状为 [N, 6],其中 6 为 [x1, y1, x2, y2, conf, cls])。non_max_suppression过滤冗余检测框:
opt.conf_thres:置信度阈值(低于此值的检测框被丢弃)。
opt.iou_thres:IoU 阈值(重叠高于此值的框会被合并)。
classes:指定保留的类别(如只检测行人)。
agnostic:是否跨类别进行 NMS(如合并不同类别的重叠框)。p, s, im0 = path[i], '%g: ' % i, im0s[i].copy()webcam 为 True 时,处理多路视频流(path[i] 和 im0s[i])。p, s, im0 = path, '', im0swebcam 为 False 时,处理单路输入(path 和 im0s)。s += '%gx%g ' % img.shape[2:] # print string构建日志字符串(如 "640x480 ")。
boxes

det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
将检测框坐标从模型输入尺寸(img.shape[2:],如 640x640)缩放到原始图像尺寸(im0.shape,如 1920x1080)。输出:det 的坐标变为 [x1, y1, x2, y2](原始图像尺度)。
scale_coords:线性缩放坐标(保持宽高比)。
.round():将坐标四舍五入为整数(便于后续绘制或处理)。s += '%g %ss, ' % (n, names[int(c)])
示例输出:若检测到 2 人和 1 车,s 变为 "2 persons, 1 cars, "。x_c, y_c, bbox_w, bbox_h = xyxy_to_xywh(*xyxy)将 YOLO 的 xyxy 格式转换为 DeepSort 所需的 [x_center, y_center, width, height] 格式。outputs = deepsort.update(xywhs, confss, im0)
输入:
xywhs:检测框的中心坐标和宽高。
confss:检测置信度。
im0:原始图像(用于视觉特征提取)。
输出:outputs 形状为 [M, 5],每行为 [x1, y1, x2, y2, track_id](跟踪后的目标框和 ID)


Stream results

xyxy to xywh

输入:*xyxy
可变参数,接受 4 个值(x1, y1, x2, y2),表示检测框的左上角和右下角坐标。
输出:返回 4 个值(x_c, y_c, w, h),即中心点坐标和宽高。
bbox_left = min([xyxy[0].item(), xyxy[2].item()])bbox_top = min([xyxy[1].item(), xyxy[3].item()])
确保 bbox_left 和 bbox_top 是左上角坐标bbox_w = abs(xyxy[0].item() - xyxy[2].item())bbox_h = abs(xyxy[1].item() - xyxy[3].item())- .item() 的作用:
如果输入是 PyTorch 张量,.item() 将其转换为 Python 标量(数值)。
使用绝对值保证宽高为正数。 x_c = (bbox_left + bbox_w / 2)y_c = (bbox_top + bbox_h / 2)
xyxy to tlwh

用于将目标检测框的坐标从 [x1, y1, x2, y2](左上角和右下角坐标)格式转换为 [top_left_x, top_left_y, width, height](左上角坐标 + 宽高)
for i, box in enumerate(bbox_xyxy):遍历每个检测框x1, y1, x2, y2 = [int(i) for i in box]将坐标值强制转换为整数(适用于浮点数输入或张量)。
label color

根据目标类别标签(label)生成一个固定的颜色值
def compute_color_for_labels(label):
输入:label
目标的类别标签(整数,如 0 表示 "person",1 表示 "car")。
输出:一个 RGB 颜色元组(如 (255, 128, 0)),用于可视化。color = [int((p * (label ** 2 - label + 1)) % 255) for p in palette]
公式 label ** 2 - label + 1 是一个简单的哈希函数,确保不同 label 映射到不同的颜色值。
% 255 保证结果在 [0, 255] 范围内(RGB 值的合法区间)。return tuple(color)
将列表 color 转换为元组(如 (R, G, B)),便于 OpenCV 等库使用。
draw boxes







id = int(identities[i]) if identities is not None else 0
若未提供 identities,默认 ID 为 0。color = compute_color_for_labels(id)
调用 compute_color_for_labels根据 ID 生成唯一颜色(用于框和文本)。