Vehicle-Detection-and-Tracking

GitHub
556 192 中等 2 次阅读 1周前插件开发框架图像
AI 解读 由 AI 自动生成,仅供参考

Vehicle-Detection-and-Tracking 是一个基于计算机视觉的开源项目,专注于在视频流中实时检测并追踪多辆车辆。它能模拟车载摄像头视角,自动识别画面中的汽车、公交车和卡车,并在每一帧上精准标注目标位置。这一方案主要解决了传统检测仅关注单帧图像、难以维持目标连续性的痛点,通过算法让系统不仅能“看见”车辆,还能理解其运动轨迹,实现稳定跟踪。

项目代码结构清晰且注重可读性,非常适合自动驾驶开发者、计算机视觉研究人员以及希望快速搭建原型的工程师使用。在这里,用户可以轻松迭代不同的检测器和追踪算法。技术层面,它集成了 TensorFlow Object Detection API 与轻量级 SSD MobileNet 模型,在检测精度与推理速度之间取得了良好平衡;同时引入卡尔曼滤波算法优化追踪逻辑,有效提升了多目标跟踪的鲁棒性。整体流程从初始化到结果展示简单直接,为相关领域的学习与实践提供了便捷的框架支持。

使用场景

某智慧交通研发团队正在开发路口车流量监测系统,需要实时统计经过摄像头的车辆数量及轨迹。

没有 Vehicle-Detection-and-Tracking 时

  • 依赖人工逐帧标注视频数据,效率极低且容易产生漏检。
  • 传统 OpenCV 算法难以处理车辆被遮挡时的跟踪丢失问题。
  • 从零搭建检测与跟踪框架,代码耦合度高,调试周期漫长。
  • 通用大模型推理速度慢,无法满足实时路口的监控延迟要求。

使用 Vehicle-Detection-and-Tracking 后

  • 直接调用内置的 SSD MobileNet 预训练模型,秒级完成车辆定位与分类。
  • 集成卡尔曼滤波算法,有效解决车辆短暂遮挡后的轨迹连续性问题。
  • 模块化代码结构清晰,开发者可快速替换不同检测器进行性能对比测试。
  • 轻量化设计平衡了精度与速度,确保系统在普通硬件上也能流畅运行。

Vehicle-Detection-and-Tracking 通过简化视觉流水线,显著降低了智能交通系统的开发门槛并提升了实时监测的稳定性。

运行环境要求

操作系统
  • 未说明
GPU

未说明

内存

未说明

依赖
notes基于 TensorFlow Object Detection API 构建,使用预训练的 SSD MobileNet V1 模型(COCO 数据集);追踪算法采用卡尔曼滤波;检测与追踪匹配使用匈牙利算法(scikit-learn);需准备 frozen_inference_graph.pb 模型文件;代码设计注重简洁性和可读性。
python未说明
tensorflow
numpy
scikit-learn
Vehicle-Detection-and-Tracking hero image

快速开始

车辆检测与跟踪

概述

本仓库展示了如何使用安装在自动驾驶汽车内的摄像头进行多辆车的检测和跟踪。旨在为开发者、研究人员和工程师提供一个简单的框架,以便快速迭代不同的检测器和跟踪算法。在此过程中,我注重代码的简洁性和可读性。检测和跟踪流程相对直接。它首先初始化一个检测器和一个跟踪器。接下来,检测器定位每一帧视频中的车辆。然后使用检测结果更新跟踪器。最后将跟踪结果标注并显示在视频帧中。

本仓库中的关键文件

  • detector.py -- 实现 CarDetector 类以输出车辆检测结果
  • tracker.py -- 实现基于卡尔曼滤波器(Kalman Filter)的预测和更新用于跟踪
  • main.py -- 实现检测和跟踪流程,包括检测 - 跟踪分配和跟踪管理
  • helpers.py -- 辅助函数
  • ssd_mobilenet_v1_coco_11_06_2017/frozen_inference_graph.pb -- 预训练的 mobilenet-coco 模型

检测

在流程中,车辆(汽车)检测接收捕获的图像作为输入,并产生边界框(bounding boxes)作为输出。我们使用 TensorFlow Object Detection API(TensorFlow 目标检测 API),这是一个构建在 TensorFlow 之上的开源框架,用于构建、训练和部署目标检测模型。Object Detection API 还附带了一系列在 COCO 数据集上预训练的检测模型集合,非常适合快速原型设计。具体来说,我们使用一个轻量级模型:ssd_mobilenet_v1_coco,它基于单 Shot 多框检测(Single Shot Multibox Detection, SSD)框架,修改极少。虽然这是一个通用检测模型(并非专门针对车辆检测优化),但我们发现该模型在边界框精度和推理时间(inference time)之间取得了平衡。

检测器实现在 detector.py 中的 CarDetector 类中。输出是所有检测到的车辆的边界框坐标(格式为 [y_up, x_left, y_down, x_right])。

COCO 数据集包含 90 个类别的图像,前 14 个类别都与交通相关,包括自行车、汽车和公共汽车等。汽车的 ID 是 3。

category_index={1: {'id': 1, 'name': u'person'},
                        2: {'id': 2, 'name': u'bicycle'},
                        3: {'id': 3, 'name': u'car'},
                        4: {'id': 4, 'name': u'motorcycle'},
                        5: {'id': 5, 'name': u'airplane'},
                        6: {'id': 6, 'name': u'bus'},
                        7: {'id': 7, 'name': u'train'},
                        8: {'id': 8, 'name': u'truck'},
                        9: {'id': 9, 'name': u'boat'},
                        10: {'id': 10, 'name': u'traffic light'},
                        11: {'id': 11, 'name': u'fire hydrant'},
                        13: {'id': 13, 'name': u'stop sign'},
                        14: {'id': 14, 'name': u'parking meter'}} 

以下代码片段实现了使用 TensorFlow API 的实际检测。

(boxes, scores, classes, num_detections) = self.sess.run(
                  [self.boxes, self.scores, self.classes, self.num_detections],
                  feed_dict={self.image_tensor: image_expanded})

这里 boxesscoresclasses 分别代表每个检测对应的边界框、置信度和类别名称。接下来,我们选择那些是汽车且置信度大于阈值(例如本例中的 0.3)的检测。

idx_vec = [i for i, v in enumerate(cls) if ((v==3) and (scores[i]>0.3))]

为了检测各种类型的车辆,我们还包含了公共汽车和卡车的索引。

idx_vec = [i for i, v in enumerate(cls) if (((v==3) or (v==6) or (v==8)) and (scores[i]>0.3))]

为了进一步减少可能的误报(false positives),我们包括了边界框宽度、高度和高宽比的阈值。

if ((ratio < 0.8) and (box_h>20) and (box_w>20)):
    tmp_car_boxes.append(box)
    print(box, ', confidence: ', scores[idx], 'ratio:', ratio)
else:
     print('wrong ratio or wrong size, ', box, ', confidence: ', scores[idx], 'ratio:', ratio)

用于边界框测量的卡尔曼滤波器

我们使用卡尔曼滤波器(Kalman filter)来跟踪对象。卡尔曼滤波器具有以下跟踪可以受益的重要特性:

  • 预测对象的未来位置
  • 根据新测量值修正预测
  • 减少由不准确检测引入的噪声
  • 促进多个对象与其轨迹关联的过程

卡尔曼滤波器由两个步骤组成:预测和更新。第一步使用之前的状态来预测当前状态。第二步使用当前的测量值,例如检测边界框位置,来修正状态。公式如下所示:

卡尔曼滤波器方程:

预测阶段:符号说明

Drawing #### 预测阶段:方程 Drawing #### 更新阶段:符号说明 Drawing #### 更新阶段:方程 Drawing

卡尔曼滤波器实现

在本节中,我们将详细描述卡尔曼滤波器(Kalman Filter)的实现。

状态向量包含以下八个元素:

[up, up_dot, left, left_dot, down, down_dot, right, right_dot]

即,我们使用边界框(Bounding Box)左上角和右下角的坐标及其一阶导数。

过程矩阵(Process Matrix),假设速度恒定(因此无加速度),如下所示:

self.F = np.array([[1, self.dt, 0,  0,  0,  0,  0, 0],
                    [0, 1,  0,  0,  0,  0,  0, 0],
                    [0, 0,  1,  self.dt, 0,  0,  0, 0],
                    [0, 0,  0,  1,  0,  0,  0, 0],
                    [0, 0,  0,  0,  1,  self.dt, 0, 0],
                    [0, 0,  0,  0,  0,  1,  0, 0],
                    [0, 0,  0,  0,  0,  0,  1, self.dt],
                    [0, 0,  0,  0,  0,  0,  0,  1]])

测量矩阵(Measurement Matrix),鉴于检测器仅输出坐标(而非速度),如下所示:

self.H = np.array([[1, 0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 1, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 1, 0, 0, 0], 
                   [0, 0, 0, 0, 0, 0, 1, 0]])

状态、过程和测量噪声定义如下:

 # Initialize the state covariance
 self.L = 100.0
 self.P = np.diag(self.L*np.ones(8))
        
        
 # Initialize the process covariance
 self.Q_comp_mat = np.array([[self.dt**4/2., self.dt**3/2.],
                                    [self.dt**3/2., self.dt**2]])
 self.Q = block_diag(self.Q_comp_mat, self.Q_comp_mat, 
                            self.Q_comp_mat, self.Q_comp_mat)
        
# Initialize the measurement covariance
self.R_scaler = 1.0/16.0
self.R_diag_array = self.R_ratio * np.array([self.L, self.L, self.L, self.L])
self.R = np.diag(self.R_diag_array)

此处 self.R_scaler 表示相对于状态噪声的测量噪声“幅度”。较低的 self.R_scaler 表示测量更可靠。下图可视化了测量噪声对卡尔曼滤波过程的影响。绿色边界框代表预测(初始)状态。红色边界框代表测量值。 如果测量噪声较低,更新后的状态(青色边界框)非常接近测量值(青色边界框完全覆盖在红色边界框上)。

Drawing

相反,如果测量噪声较高,更新后的状态非常接近初始预测(青色边界框完全覆盖在绿色边界框上)。

Drawing

检测与跟踪器分配

模块 assign_detections_to_trackers(trackers, detections, iou_thrd = 0.3) 接收当前的跟踪器列表和新检测,输出匹配的检测、未匹配的跟踪器以及未匹配的检测。

Drawing

线性分配与匈牙利(Munkres)算法

如果有多个检测,我们需要将每个检测匹配(分配)到一个跟踪器。我们使用跟踪器边界框和检测边界框的交并比(Intersection Over Union, IOU)作为度量标准。我们使用匈牙利算法(也称为 Munkres 算法)来解决最大化 IOU 分配总和的问题。机器学习库 scikit-learn 有一个内置的工具函数实现了匈牙利算法。

matched_idx = linear_assignment(-IOU_mat)   

注意,linear_assignment 默认最小化目标函数。因此,为了最大化,我们需要反转 IOU_mat 的符号。

未匹配的检测与跟踪器

基于线性分配结果,我们分别保留两个列表用于存储未匹配的检测和未匹配的跟踪器。当一辆车进入画面并被首次检测到时,它不会与任何现有轨迹匹配,因此这种特定的检测被称为未匹配检测,如下图所示。此外,任何重叠小于 iou_thrd 的匹配都意味着存在未被跟踪的对象。当车辆离开画面时,之前建立的轨迹不再有可关联的检测。在这种情况下,该轨迹被称为未匹配轨迹。因此,匹配中关联的跟踪器和检测分别被添加到未匹配跟踪器列表和未匹配检测列表中。

Drawing

流水线

我们在流水线中包含了两个重要的设计参数,即 min_hitsmax_age。参数 min_hits 是建立一条轨迹 (track) 所需的连续匹配次数。参数 max_age 是在删除一条轨迹之前允许的连续未匹配检测 (detection) 的数量。这两个参数都需要进行调整,以提高跟踪 (tracking) 和检测 (detection) 性能。

流水线依次处理匹配的检测 (matched detection)、未匹配的检测 (unmatched detection) 以及未匹配的跟踪器 (unmatched trackers)。我们标注满足 min_hitsmax_age 条件的轨迹 (tracks)。还需要适当的维护工作来删除过时的轨迹。

以下示例展示了流水线的过程。当汽车在第一个视频帧中首次被检测到时,运行以下代码行将分别返回空列表、一个元素的列表和空列表,对应于 matchedunmatched_detsunmatched_trks

matched, unmatched_dets, unmatched_trks \
    = assign_detections_to_trackers(x_box, z_box, iou_thrd = 0.3) 

因此我们面临的是未匹配检测的情况。未匹配的检测由以下代码块处理:

if len(unmatched_dets)>0:
        for idx in unmatched_dets:
            z = z_box[idx]
            z = np.expand_dims(z, axis=0).T
            tmp_trk = Tracker() # Create a new tracker
            x = np.array([[z[0], 0, z[1], 0, z[2], 0, z[3], 0]]).T
            tmp_trk.x_state = x
            tmp_trk.predict_only()
            xx = tmp_trk.x_state
            xx = xx.T[0].tolist()
            xx =[xx[0], xx[2], xx[4], xx[6]]
            tmp_trk.box = xx
            tmp_trk.id = track_id_list.popleft() # assign an ID for the tracker
            tracker_list.append(tmp_trk)
            x_box.append(xx)

此代码块执行两项重要任务:1) 为检测创建一个新的跟踪器 (tracker) tmp_trk;2) 执行卡尔曼滤波器 (Kalman filter) 的预测阶段 tmp_trk.predict_only()。请注意,这个新创建的轨迹仍处于试用期,即 trk.hits =0,因此在流水线结束时该轨迹尚未确立。输出图像与输入图像相同——检测边界框 (bounding box) 未被标注。 Drawing

当汽车在第二个视频帧中再次被检测到时,运行以下 assign_detections_to_trackers 将分别返回一个元素的列表、空列表和空列表,对应于 matched、unmatched_dets 和 unmatched_trks。如下图所示,我们有一个匹配的检测,它将由以下代码块处理:

if matched.size >0:
        for trk_idx, det_idx in matched:
            z = z_box[det_idx]
            z = np.expand_dims(z, axis=0).T
            tmp_trk= tracker_list[trk_idx]
            tmp_trk.kalman_filter(z)
            xx = tmp_trk.x_state.T[0].tolist()
            xx =[xx[0], xx[2], xx[4], xx[6]]
            x_box[trk_idx] = xx
            tmp_trk.box =xx
            tmp_trk.hits += 1

此代码块执行两项重要任务:1) 执行卡尔曼滤波器 (Kalman filter) 的预测和更新阶段 tmp_trk.kalman_filter();2) 将轨迹的命中次数加一 tmp_trk.hits +=1。通过此更新,条件 if ((trk.hits >= min_hits) and (trk.no_losses <=max_age)) 得到满足,因此该轨迹完全确立。结果,边界框 (bounding box) 在输出图像中被标注,如下图所示。 Drawing

问题

主要问题是遮挡 (occlusion)。例如,当一辆车经过另一辆车时,两辆车可能非常接近。这可能会欺骗检测器输出单个(且可能更大的边界)框,而不是两个独立的边界框 (bounding box)。此外,跟踪算法可能会将此检测视为新的检测并建立新的轨迹。当其中一辆经过的车驶离另一辆车时,跟踪算法可能会再次失败。

常见问题

相似工具推荐

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|今天
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

139k|★★☆☆☆|今天
开发框架Agent语言模型

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

107.7k|★★☆☆☆|2天前
开发框架图像Agent

NextChat

NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。

87.6k|★★☆☆☆|今天
开发框架语言模型

ML-For-Beginners

ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。

85k|★★☆☆☆|今天
图像数据工具视频

ragflow

RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。

77.1k|★★★☆☆|昨天
Agent图像开发框架