KPourgourides/UAVTrafficPy

GitHub: KPourgourides/UAVTrafficPy

UAVTrafficPy 是一个用于在微观、中观和宏观多尺度上分析及可视化基于无人机的交通数据的 Python 工具包。

Stars: 2 | Forks: 2

# UAVTrafficPy:用于分析和可视化基于 UAV 的交通数据的 Python 包

       

## 引言 在交通研究中引入基于 UAV 的数据收集方法,开启了以往因传统传感器方法(如线圈检测器、固定摄像头和配备跟踪技术的探测车辆)的局限性而无法实现的新可能。这些传统方法存在各种缺点,例如数据稀疏、交通网络覆盖有限、安装和维护成本高昂,以及无法捕获和存储针对单辆车的高质量时空信息。通常,必须将它们结合在一起以弥补各自的不足,从而提供可靠的结果。 另一方面,在交通网络上方快速部署协同且配备摄像头的 UAV,使研究人员能够克服这些限制,因为它们可以针对潜在广阔区域内的所有独立车辆,获取具有高时空分辨率的海量数据。只要开发出适当的工具,这就能改变交通运输领域的交通分析格局。 UAVTrafficPy 提供了用于在多个分析尺度上提取、重构和可视化基于 UAV 的交通数据的工具,具体如下。 **(a) 微观:*关注单个车辆的行为和运动。*** 用户可以重构和可视化轨迹,计算随时间变化的速度和加速度曲线,计算累计行驶距离,可视化时空图,并检测车道变更。 **(b) 中观:*检查连续车辆之间的交互。*** 用户可以计算连续车辆之间的相对动态间距和速度差,这两个量通常被用作跟驰模型标定中的变量。 **(c) 宏观:*在交叉口层面分析交通动态***。用户可以计算转向比例,提取有关交通信号灯相位和周期的信息,并计算排队相关信息,例如排队车辆数、排队长度,以及最终的排队消散时间。 `UAVTrafficPy` 是在 Windows 上使用 Python >=3.12 开发和测试的,作为一个独立的软件包,用于分析和可视化基于 UAV 的交通数据。它不是任何现有软件的扩展。 ## 致谢 这项工作得到了欧洲联盟(i. ERC, URANUS, No. 101088124 和, ii. Horizon 2020 Teaming, [KIOS CoE](https://www.kios.ucy.ac.cy/), No. 739551)以及塞浦路斯共和国政府通过研究、创新和数字战略副部的支持。但表达的观点和意见仅为作者本人的观点和意见,不一定反映欧洲联盟或欧洲研究委员会执行机构的观点。无论是欧洲联盟还是资助机构都不对此负责。 [URANUS](https://uranus.ucy.ac.cy/)(通过基于 UAV 的智能感知进行实时城市移动性管理)专注于通过无人机 (UAV) 对车辆和行人交通进行实时、动态和智能的感知,并将收集到的信息用于城市移动性管理。 ## 目录 - [安装与使用](#installation--usage) - [对 UAVTrafficPy 的社区贡献](#community-contributions-to-uavtrafficpy) - [你有问题吗?](#do-you-have-a-question?) - [你想做出贡献吗?](#do-you-want-to-contribute) - [你想报告一个 bug 吗?](#do-you-want-to-report-a-bug) - [如何将 UAVTrafficPy 用于信号交叉口](#how-to-use-UAVTrafficPy-for-signalized-intersections) - [以正确的格式获取数据](#acquiring-the-data-in-the-correct-format) - [设置分析](#setting-up-the-analysis) - [分析与可视化](#analysis--visualization) ## 安装与使用 要安装 `UAVTrafficPy`,你可以克隆代码仓库,并在 `UAVTrafficPy` 文件夹下的终端中运行 `pip install -r requirements.txt`,以从 `requirements.txt` 安装所有必需的包。 ## 如何将 UAVTrafficPy 用于信号交叉口 本节提供了一个详细的操作指南,说明如何正确使用 `UAVTrafficPy`,以便根据基于 UAV 的交通数据提取有价值的信息,并制作有关城市信号交叉口的深入可视化。在这里,我们紧密遵循[此使用示例](https://github.com/KPourgourides/UAVTrafficPy/blob/main/usage%20example/intersection_pipeline_example.ipynb)中提供的代码。当然,下面展示的工具以及此处未显示的其余工具,在针对交通网络中非交叉口部分(例如简单的道路路段)进行分析时同样可以使用。 ### 以正确的格式获取数据 为了在后续阶段正确使用该工具,第一个也是最重要的任务是获取我们想要分析的基于 UAV 的数据,并且必须是**正确的格式**。不同的开源数据集使用不同的格式,为了紧凑起见,这些格式通常不太清晰。正因为如此,该工具被设计为**仅接受一种格式**的输入数据。因此,在能够成功将该工具部署到我们的研究之前,我们可能需要进行一些数据预处理。 基于 UAV 的交通数据集通常包含有关录像中不同个体车辆的信息,例如 **ID**(唯一编号)和**类型**(例如,汽车、摩托车、公共汽车)。此外,它们还包含按**时间**标记的**位置**。一些数据集可能还提供按时间标记的速度和加速度信息,但由于这些都可以通过位置提取出来,因此它们不是该工具的强制输入。 `UAVTrafficPy` 将上述数据作为输入,以执行分析和可视化任务。将数据传递给 `UAVTrafficPy` 的正确方法是创建一个**字典**,其中每个键对应不同的信息(例如,ID、类型、位置、时间)。例如, ``` data = {'id':id, 'vtype':vtype, 'x':X, 'y':Y, 'time':T} ``` 此字典的每个键对应一个列表。对于 **id** 和 **vtype**,列表包含整数和字符串元素,分别对应每辆车的唯一编号和类型。例如, ``` data.get('id') = [0,1,...,N] data.get('vtype') = ['Car','Motorcycle',...,'Bus'] ``` 其中车辆总数为 N+1。字典的其余键对应包含嵌套列表的列表,数据集中的每辆车都有一个嵌套列表。每个嵌套列表的元素对应不同的时间戳,其长度根据相应车辆在录像中停留的时间而变化。例如, `data.get('time')` = $[T^0,T^1,...,T^N]$ `data.get('x')` = $[X^0,X^1,...,X^N]$ `data.get('y')` = $[Y^0,Y^1,...,Y^N]$ 为了理解嵌套列表的内容,我们在下面看到了对于 ID 为 $i$ 的车辆它们看起来是什么样子 $T^i$ = $[t_0,...,t_k]^i$ $X^i$ = $[x(t_0),...,x(t_k)]^i$ $Y^i$ = $[y(t_0),...,y(t_k)]^i$ 其中车辆在录像中的总时间步数 *(或测量次数)* 为 k+1。时间步的频率 *(1 秒内有多少个)* 等于无人机摄像头的刷新率。 当我们把基于 UAV 的交通数据集转换为上述格式时,我们就可以使用 `UAVTrafficPy` 来对我们选择的交叉口进行分析和可视化任务。关于如何在 pNEUMA 数据集上进行上述数据转换的示例存在于代码仓库的[此位置](https://github.com/KPourgourides/UAVTrafficPy/blob/main/tests/dataload_example.py)。 ### 设置分析 #### 定义研究中的交叉口 首先,我们必须通过卫星图像软件(例如 GoogleMaps)识别我们想要研究的交叉口,并找出重要信息,例如不同的可能路线。在本指南中,我们研究了 2018 年 10 月 24 日上午时段一段 15 分钟的录像,地点为希腊雅典 Panepistimiou 大道和 Omirou 街的信号交叉口。

对于 Panepistimiou 大道,总共有 4 条车道 *(3 条普通车道 + 1 条公交车道)*,驾驶员可以向前行驶或向左转进入 Omirou 街。对于 Omirou 街,只有 1 条车道,驾驶员可以向前行驶或向右转进入 Panepistimiou 大道。 #### 获取交叉口的重要时空信息 在进一步进行之前,我们必须获取我们想要研究的交叉口的一些重要时空信息,这将作为后续步骤的基础。我们需要收集的第一条信息是 `bbox ` *(bounding box)*,它本质上是一组包含四组空间坐标的列表,这些坐标定义了 *(即作为顶点)* 包围该交叉口的框。框的边缘垂直相交于交叉口的道路,这一点非常重要。 该工具稍后将使用 `bbox` 仅保留在录像中某个时刻穿过它的车辆数据,并丢弃与交叉口无关的其余数据,从而缩减原始数据集,使未来的分析和可视化步骤更快捷、更高效。`bbox` 具有以下形式 ``` bbox = [(ll_y,ll_x),(lr_y,lr_x),(ur_y,ur_x),(ul_y,ul_x)] ``` 其中 ll、lr、ur 和 ul 分别对应于左下、右下、右上和左上,我们可以从 GoogleMaps 中获取这些坐标。此外,我们必须提供一个包含交叉口中心坐标的元组,这将用于稍后的某些特定任务。 ``` intersection_center = (y_center,x_center) ``` 我们需要收集的最后一条信息是录像的 `time_axis`。它是一个包含录像所有时间步的列表,与各个车辆何时进入或离开交叉口无关。在数学上,不同车辆的各个时间轴 $[T^0,...,T^N]$ 是全局 `time_axis` 的子集。其定义为 `time_axis` = $[t^{\text{start}},...,t^{\text{end}}]$ `time_axis` 的长度等于无人机摄像头的刷新率乘以以秒为单位的录像持续时间。例如,如果录像使用 60 FPS 的摄像头进行了 10 分钟,`time_axis` 将包含 60 $sec^{-1}$ $\times$ 10 $\times$ 60 $sec$ = 36000 个时间步。一旦我们收集了上述所有信息,我们就会将其以下面的方式存储在一个字典中 ``` spatio_temporal_info = {'bbox':bbox, 'intersection center':intersection_center', 'time axis':time_axis} ``` ### 分析与可视化 #### 加载工具 要在 Python 环境中加载该工具,我们运行以下命令 ``` from UAVTrafficPy.tool import uavtrafficpy tool = uavtrafficpy.Master() ``` 要设置分析和可视化类,我们只需运行以下命令 ``` analysis = tool.analysis(raw_data,spatio_temporal_info) visualization = tool.visualization(raw_data,spatio_temporal_info) ``` 其中 `raw_data` 是上述描述的正确形式的数据目录。 #### 过滤数据 为了仅加载由 `bbox` 指定的感兴趣区域(本例中为交叉口)内的数据,我们运行以下命令 ``` data = tool.dataloader(raw_data,spatio_temporal_info).get_bounded_data() ``` 或者,我们可以对 `raw_data` 应用一些过滤器来清除停放的车辆,因为它们不参与交通,并且可能会减慢分析速度。如果一辆车在录像中出现的时间中有超过 95% 的时间是静止不动的,则认为它是停放的。 这是通过以下命令实现的 ``` data = tool.dataloader(raw_data,spatio_temporal_info).get_filtered_data() ``` 该命令同时对数据进行边界界定和过滤。我们还可以选择将参数 `cursed_ids` 传递给 `get_filtered_data()`,在其中我们可以列出任何我们希望从数据集中明确删除的车辆 ID,即使它们不满足停放条件。 #### 根据路线对轨迹进行分类 首要任务是根据不同车辆轨迹的路线,或者更具体地说,根据它们在交叉口内的起点(o;*入口点*)和终点(d;*出口点*)对其进行分类。这对于我们稍后想要根据不同路线分离数据以进行单独分析时的后续步骤非常重要。 为了实现这一点,使用 `intersection_center` 和 `bbox` 将交叉口分为 4 个三角形。每个三角形从交叉口的下部开始顺时针依次用数字 1 到 4 标记。根据每辆车的路线为其分配一个 od 对。例如,如果一辆车在三角形 1 内进入交叉口并在三角形 3 内驶出 *(在 Panepistimiou 大道上向前行驶)*,那么分配的 od 对将是 `(1,3)`。我们可以使用以下命令可视化不同的 od 对 ``` visualization.draw_trajectories_od() ```

我们可以使用上图来识别我们交叉口的正确 od 对。它们是 `(1,3)` *(在 Panepistimiou 大道上向前行驶)*,`(1,2)` *(最初在 Panepistimiou 大道上行驶,然后向左转进入 Omirou 街)*,`(4,3)` *(最初在 Omirou 街上行驶,然后向右转进入 Panepistimiou 大道)*,最后是 `(4,2)` *(在 Omirou 街上向前行驶)*。我们可以通过运行以下命令,根据 od 对使用不同颜色可视化车辆轨迹,以使其更清晰 ``` visualization.draw_trajectories_cc(valid_od_pairs) ```

其中蓝色、橙色、绿色和红色分别对应 od 对 `(1,3)`、`(1,2)`、`(4,2)` 和 `(4,3)`。参数 `valid_od_pairs` 是一个包含正确 od 对的列表,`valid_od_pairs = [(1,3),(1,2),(4,3),(4,2)]`。这种轨迹分类也有助于计算每条街道的转向比例。对于我们的案例,它们如下所示

下一步是根据不同的起点/入口点将 `data` 字典分离为较小的子字典。当我们稍后进行特定起点的分析时,此步骤将会很有帮助。在我们的案例中,我们必须为 od 对 `(1,3),(1,2)` 和 `(4,3),(4,2)` 分别制作两个数据子字典 `data_a` 和 `data_b`。为此,我们运行以下命令 ``` data_a = analysis.get_od_data(desirable_pairs=[(1,3),(1,2)]) data_b = analysis.get_od_data(desirable_pairs=[(4,3),(4,2)]) ``` 在分析和可视化过程的后续步骤中,我们将讨论的方法将分别应用于这两个数据子字典,它们的变量名将以 `_a` 或 `_b` 结尾,具体取决于我们使用哪个子字典。为此,我们使用以下命令设置单独的分析和可视化类 ``` analysis_a = tool.analysis(data_a,spatio_temporal_info) visualization_a = tool.visualization(data_a,spatio_temporal_info) analysis_b = tool.analysis(data_b,spatio_temporal_info) visualization_b = tool.visualization(data_b,spatio_temporal_info) ``` #### 提取车道信息 下一个任务是提取交叉口组成部分的车道信息。所谓车道信息,我们指的是车道数量、它们的空间边界,以及在每个时间步中车辆在其中的分布情况。 道路上的车道数量及其对应的空间边界可以通过形成车辆沿该道路的横向分布来提取。预计沿着同一车道行驶的车辆距离道路边缘的横向距离大致相同,因此,会为道路上的每辆车计算该量的时间平均值。预计该量的分布会形成以每条对应车道的横向中心为中心的不同。每个峰值代表一条现有车道,因此峰值的总数等于道路中的车道数。例如,要可视化 Panepistimiou 大道的此分布,我们只需运行以下命令 ``` lane_info_a = analysis_a.get_lane_info(flow_direction='up') ``` 其中 `flow_direction` 是 `['up','down','left','right]` 之一;向北的车流对应 `'up'`,向南的车流对应 `down`,依此类推。最初,我们将看到此直方图

现在,系统将要求我们输入我们看到的 lanes 数量 *(即分布中的峰值数量 - 在此例中为 4)*,随后提供分布的下限和上限。在我们输入此信息后,聚类算法将计算每条车道的空间边界,我们将看到生成的图形

这里,`lane_info_a` 是一个包含我们需要的所有信息的字典。它的键是 `number` *(整数)* 和 `boundaries` *(列表)*,分别对应于车道数和作为道路宽度方向上车道边界的浮点值。此外,它还有一个名为 `distribution` 的附加键,它是一个包含嵌套列表的列表,每辆车一个,包含了在每个时间步该车辆所属的车道。如果在某个时刻车辆离开了道路,则从该时刻起相应的值将为 `None`。 #### 提取交通信号灯相位和周期 可以通过在交通信号灯杆的实际位置放置虚拟检测器,然后在这些点测量流量计数来提取交通信号灯相位。由于数据在时间上是离散的,因此流量测量发生在 `time_axis` 的不同时间步中。在特定时间步记录的计数对应于前一个时间步与当前时间步之间穿过虚拟交通信号灯杆的车辆数量。 我们预计,对于每条街道,属于同一相位的计数会在特定的时间窗口内被记录,并且在该窗口结束后的多个时间步内不会有记录的计数,直到下一个周期重复。要执行上述任务,我们运行以下命令 ``` flow_info_a = analysis_a.get_flow_info(detector_position_a) flow_info_b = analysis_b.get_flow_info(detector_position_b) ``` 其中 `detector_position` 参数是一个包含虚拟检测器坐标 (y,x) 的元组。`get_flow_info()` 方法的结果是一个字典列表,其中每个嵌套字典具有键 `time stamp` *(浮点数)*、`flow` *(整数)* 和 `id` *(列表)*,分别对应于相对于 `time_axis` 的测量时刻、当前和上一个时间步之间记录的计数数量,以及负责产生记录计数命中的车辆 ID。如果在相应的时间间隔内记录了 0 次计数,则 `id` 列表为空。例如, ``` flow_info_a[time_axis.index(24)] = {'time stamp': 24.0, 'flow': 4, 'id': [71,128,142,145]} ``` 在这里,录像的第 23 秒和第 24 秒之间,有 4 辆车在 Panepistimiou 大道上驶过了交通信号灯。此信息被用于将流量检测器的输出转换为二进制 *(如果有记录的计数命中则为 1,如果没有则为 0)*,并将它们组合在一起。不同的记录计数组代表不同的交通信号灯相位,每个相位的持续时间等于相应时间窗口的持续时间。为了做到这一点,我们运行以下命令 ``` flow_a,norm_flow_a = analysis_a.get_normalized_flow(threshold=15) flow_b,norm_flow_b = analysis_b.get_normalized_flow(threshold=15) ``` 这里的 `threshold` 参数指的是两次连续的记录命中之间所允许的最大距离 *(以时间为单位)*,以便将它们视为属于同一组。`flow_a`,`flow_b` 的输出都是一个列表,包含了 `time_axis` 每一步未归一化的命中,而 `norm_flow_a`,`norm_flow_b` 的输出也是一个列表,但这次包含的是 `time_axis` 每一步归一化并分组后的命中。要可视化上述内容,我们运行命令 ``` visualization.draw_traffic_light_phases(norm_flow_a,norm_flow_b,flow_a,flow_b) ``` 黑色和红色的计数分别对应于 Panepistimiou 大道和 Omirou 街。 要将上图转换为正式的交通信号灯相位数据,我们运行以下命令 ``` tlp_a = analysis_a.get_traffic_light_phases() tlp_b = analysis_b.get_traffic_light_phases() ``` `tlp_a`, `tlp_b` 的输出都是一个字典列表,其中每个字典都有键 `Green`,`Duration ON`,`Red`,`Duration OFF`,`Phase Duration`,分别对应于相应交通信号灯变绿的时刻、绿灯持续的时间、变红的时刻、红灯持续的时间以及整个相位持续时间 *(从绿灯到下一个绿灯)*,均以秒为单位。例如, ``` tlp_a[0] = {'Green':9.0, 'Duration ON':61.0, 'Red':70.0, 'Duration OFF':32.0, 'Phase Duration':93.0} ``` 如果在相位完成之前录像已经停止,则相应的键的值将为 `None`。例如,如果在交通信号灯为红灯时录像停止,则无法计算键 `Duration OFF` 的值,键 `Phase Duration` 也是如此。下面我们对 Panepistimiou 大道和 Omirou 街的绿灯、红灯的平均持续时间以及整个相位进行了可视化。

对于 Panepistimiou 大道,绿灯、红灯和整个相位的平均持续时间分别为 30 $\pm$ 4 秒、60 $\pm$ 2 秒和 90 $\pm$ 4 秒。Omirou 街的相应值为 16 $\pm$ 4 秒、74 $\pm$ 3 秒和 90 $\pm$ 2 秒。 接下来,我们将 `tlp_a`, `tlp_b` 结合起来,以获取关于完整周期的信息,即 2 个独立相位的相继完成。为此,我们运行以下命令 ``` cycles = analysis.get_traffic_light_cycles(tlp_a,tlp_b) ``` `cycles` 的输出是一个字典列表,其中每个字典都有键 `Start`,`Break`, `Continue`,`Stop`,`End`,分别对应于周期开始的时刻 *(即第一个相位开始)*、周期暂时停止的时刻 *(即第一个相位变为红灯)*、周期重新开始的时刻 *(即第二个相位开始)*、周期停止的时刻 *(即第二个相位变为红灯)*,最后是周期重新开始的时刻 *(即第一个相位重新开始)*,均以秒为单位。例如, ``` cycles[0] = {'Start': 9.0, 'Break': 70.0, 'Continue': 76.0, 'Stop': 96.0, 'End': 102.0} ``` 下面是数据集中第一个周期的可视化

阴影区域对应于两个交通信号灯均为红灯的时间窗口,这可能是人行横道启用的时间。 #### 提取跟驰信息 跟驰参数用于交通流理论中,描述驾驶员或自动驾驶车辆对同一车道内前方车辆的反应。其中一些参数包括加速度、减速度、速度差以及车辆之间的间距(前保险杠到后保险杠)。此类信息对于微观交通仿真模型至关重要。 每辆车的速度和加速度(或减速度)信息,可以通过位置坐标的离散时间微分简单提取。此类计算的准确性取决于交通数据的时间分辨率,而基于 UAV 的数据通常具有很高的时间分辨率。 取决于车辆与其前车之间相对运动的信息(如间距和速度差)按如下方式提取。根据车道内的行驶方向,将每条车道中的车辆 ID 从后车到前车进行排序;例如,如果车道中的车辆向北行驶,则它们的 ID 将根据纬度的增加进行排序。然后,一旦车辆被排序,由于完全掌握了位置坐标和速度,计算间距或速度差就变得非常简单了。上述任务可以在录像中的任何时间步执行。为了执行上述操作,我们运行以下命令 ``` sorted_id_a = analysis_a.get_sorted_id() gaps_a = analysis_a.get_gaps() sorted_id_b = analysis_b.get_sorted_id() gaps_b = analysis_b.get_gaps() ``` 我们不打算标定任何跟驰模型,但对我们来说,这些信息很重要,因为它将在稍后帮助我们提取排队信息。这两种方法的输出都是一个字典列表,其中每个字典都有键 `time stamp`,以及从 `lane 0` 到 `lane L`,其中 L+1 为总车道数。`time stamp` 对应当前 `time_axis` 的步长,每个特定于车道的键是一个包含已排序的 ID 或间距(以米为单位)的列表。例如, ``` sorted_id_a[time_axis.index(tlp_a[7].get('Green'))] = {'time stamp':551.0, 'lane 0':None, 'lane 1':[1778], 'lane 2':[1922, 2021], 'lane 3':[2045, 1659], 'lane 4':[2062]} gaps_a[time_axis.index(tlp_a[7].get('Green'))] = {'time stamp':551.0, 'lane 0':None, 'lane 1':[-1.0], 'lane 2':[9.4, -1.0], 'lane 3':[14.7, -1.0], 'lane 4':[-1.0]} ``` 值 `None` 表示车道内没有车辆,而值 `-1.0` 对应于前方没有车辆的车道头车。 ### 提取排队信息 当排队达到其最大潜力时(即不同相位下交通信号灯变为绿灯的时刻),我们继续进行排队信息的计算。对于每条街道以及其中的每条车道,如果在相应的绿灯亮起时,车辆满足以下条件,则被认为是排队的一部分: 1. 它在物理上位于代表交通信号灯杆的虚拟检测器之后 2. 其瞬时速度低于给定阈值 $u_{threshold}$ 3. 其与下一辆车的间距小于给定阈值 $g_{threshold}$ *(排队头车除外)* 满足上述条件的车辆在相应的交通信号灯相位下形成排队。这些条件的图解如下所示

最右侧的摩托车不被视为在排队中,因为它违反了条件 1,因为它已经穿过了虚拟交通信号灯杆,即使可能满足条件 2 和 3。最左侧的汽车也不被视为在排队中,因为尽管它满足条件 1,但它尚未减速并到达排队的尾部,因此违反了条件 2 和 3。中间的卡车和汽车被认为是排队的一部分,因为它们满足所有 3 个条件。 要正式提取排队信息,我们运行以下命令 ``` queue_info_a = analysis_a.get_queue_info(speed_threshold,gap_threshold) queue_info_b = analysis_b.get_queue_info(speed_threshold,gap_threshold) ``` 上述方法的输出是一个列表的列表,其中每个嵌套列表对应一个交通信号灯相位,并且内部有 L+1 个字典,对应于总车道数。每个嵌套字典具有键 `Lane`,`Queued Vehicles`,`Queue Length`,`Queued IDs`,`Dissipation Duration`,分别对应于所讨论的车道、绿灯亮起时排队的车辆数量、以米为单位的排队长度、排队车辆的 ID 以及以秒为单位的排队消散持续时间。 `Queue Length` 的计算方式是我们之前得出的车辆长度和间距的总和,而 `Dissipation Duration` 是所有排队车辆驶过绿灯信号灯杆所需的时间。如果在信号灯再次变红之前只有一部分排队消散,则排队消散持续时间等于绿灯的持续时间。例如, ``` queue_info_b[6] = [{'Lane':0, 'Queued Vehicles':6, 'Queue Length':38.0, 'Queued IDs':[2192, 2166, 2139, 2067, 2029, 1784], 'Dissipation Duration':11.0}] ``` 使用指南到此结束。
标签:Python, 交通数据分析, 交通轨迹, 微观交通分析, 无人机, 无后门, 逆向工具