我们得到了某监控点的检测视频数据,需要从数据当中得到车流量、速度、车辆时间占用率等基本数据然后用于车道推测拥堵。以某一路段内检测点为例利用YOLOv8实战检验。
假设:
- 车辆只有轿车与卡车两种类型并分别设置车长;
- 某路段只检测双车道并且应急车道不开放;
- YOLOv8在该情况下检测是准确的;
准备工作
首先需要安装python以及安装对应的库ultralytics,安装python可以参考CapRogers1之前的案例:利用背景去除和OpenCV哈里斯角点+透视变换实现任意四边物体的图像矫正-CSDN博客
安装完成python后需要安装对应库,首先我们新建一个文件夹将生数据放入其中并将文件夹命名为rawdata,内部存放采集的视频生数据。
接下来在此文件夹创建python虚拟环境,在此文件夹路径下打开一个终端(powershell或者cmd)并输入:
python -m venv venv
显示如上图所示表示创建成功。
首先由于我们接下来要处理视频文件,因此需要加快推理速度,建议有N卡的使用英伟达CUDA进行推理加速,首先安装CUDA,安装CUDA和cuDNN可参考:CUDA安装及环境配置,注意安装和自己显卡版本匹配的CUDA。
安装完成后然后回到之前的文件夹重新打开终端输入:
.\venv\Scripts\Activate.ps1
然后进入虚拟环境,接下来需要安装GPU版本的torch和torchvision,首先查看自己安装的CUDA是什么版本:
nvcc --version
例如我的cuda版本是11.6:
那么按照对应版本的torch,例如我的11.6版本cuda就寻找后缀是cu116,可以前往https://download.pytorch.org/whl/torch_stable.html查找对应版本torch和torchvision,同时注意torch和torchvision版本也是要对应的,查看对应版本的torch和对应vision可参考Torch和torchvision对应版本表
然后输入确定好的版本进行安装,以cu116为例输入下列指令:
pip install torch==1.13.1+cu116 -f https://download.pytorch.org/whl/torch_stable.html
pip install torchvision==0.14.1+cu116 -f https://download.pytorch.org/whl/torch_stable.html
安装完成torch-cu116显示如下:
安装完成torchvision-cu116显示如下:
然后再安装支持上述版本的ultralytics。
pip install ultralytics==8.2.21
输入上述代码后会自动安装yolov8并且安装其对应的依赖,已经安装的torch和torchvision在其支持版本内会自动跳过安装。
最后有显示successfully installed ultralytics表示安装成功。
Troubleshot
如果出现collection has no attribute的类似保存可以尝试输入下列指令重装:
pip uninstall ultralytics
pip install ultralytics==8.2.21
如果有报错如下:
如果出现上述错误说明numpy版本不匹配,由于pip自动安装最新版本numpy,如果出现上述错误请在虚拟环境内输入:
pip install numpy==1.23.5
检测是否安装成功,虚拟环境内输入:
yolo
如果显示如上表示安装成功,同时也可以用虚拟环境的python解释器输入import ultralytics检测。
预处理
首先需要对原本检测录像当中十抽一的视频裁剪非车道部分并去除然后为了方便计算进行降10帧逐帧处理。
预处理第一步:利用OpenCV可以对视频进行降帧处理:
import os
import cv2
input_root = 'rawdata' # 原始视频文件夹路径
output_root = 'slower' # 慢动作视频保存路径
slow_motion_factor = 10
# 检查并创建输出目录
if not os.path.exists(output_root):
os.makedirs(output_root)
total_videos = 0
for folder_name in ['32.31.250.103', '32.31.250.105', '32.31.250.107', '32.31.250.108']:
input_folder = os.path.join(input_root, folder_name)
total_videos += len([file for file in os.listdir(input_folder) if file.endswith('.mp4')])
video_index = 0
# 遍历 rawdata 文件夹中的子文件夹
for folder_name in ['32.31.250.103', '32.31.250.105', '32.31.250.107', '32.31.250.108']:
input_folder = os.path.join(input_root, folder_name)
output_folder = os.path.join(output_root, folder_name)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 遍历该文件夹中的所有视频文件
for video_file in os.listdir(input_folder):
if video_file.endswith('.mp4'):
input_video_path = os.path.join(input_folder, video_file)
output_video_path = os.path.join(output_folder, video_file.replace('.mp4', '_slower.mp4'))
cap = cv2.VideoCapture(input_video_path)
if not cap.isOpened():
print(f"Error: Unable to open video {input_video_path}")
continue
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_size = (width, height)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 总帧数
# 计算新帧率
new_fps = fps / slow_motion_factor
# 定义输出视频的编码器和创建 VideoWriter 对象
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 使用 'mp4v' 编码格式保存为 MP4 文件
out = cv2.VideoWriter(output_video_path, fourcc, new_fps, frame_size)
video_index += 1
# 输出处理进度(正在处理第几个视频)
print(f"Processing video {video_index}/{total_videos}: {video_file}")
# 逐帧读取视频,写入到新文件
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
# 将帧写入到输出视频文件
out.write(frame)
frame_count += 1
# 计算并显示帧处理进度百分比
progress = (frame_count / total_frames) * 100
print(f"Video {video_index}/{total_videos} - Frame {frame_count}/{total_frames} ({progress:.2f}% completed)")
cap.release()
out.release()
print(f"Processed {frame_count} frames from {input_video_path}. Saved as {output_video_path}\n")
print("All videos processed.")
代码简释:
- 首先定义了输入和输出的文件夹,其中包含视频的子文件夹;
- 批量从文件夹内部处理对应的视频文件并检测其帧率;
- 通过将当前处理的帧数和总共帧数计算百分比输出显示进度让大家看的时候不会不耐烦;
- 批处理完成后同样将每一个视频加上slower重命名保存到输出目录。
预处理第二步:接下来进行裁剪去除可能会干扰的区域:
import os
import cv2
input_root = 'slower' # 原始视频文件夹路径
output_root = 'cropped' # 裁剪后的视频保存路径
if not os.path.exists(output_root):
os.makedirs(output_root)
# 定义每个文件夹对应的裁剪尺寸和定点
crop_settings = {
'32.31.250.103': {'crop_width': 854, 'crop_height': 630, 'anchor': 'bottom_left'},
'32.31.250.105': {'crop_width': 688, 'crop_height': 663, 'anchor': 'bottom_left'},
'32.31.250.107': {'crop_width': 999, 'crop_height': 635, 'anchor': 'bottom_left'},
'32.31.250.108': {'crop_width': 907, 'crop_height': 512, 'anchor': 'bottom_right'}
}
# 遍历 slower 文件夹中的子文件夹
for folder_name, crop_setting in crop_settings.items():
input_folder = os.path.join(input_root, folder_name)
output_folder = os.path.join(output_root, folder_name)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
video_files = [f for f in os.listdir(input_folder) if f.endswith('.mp4')]
for video_file in video_files:
input_video_path = os.path.join(input_folder, video_file)
output_video_path = os.path.join(output_folder, video_file)
# 打开视频文件
cap = cv2.VideoCapture(input_video_path)
# 检查视频是否成功打开
if not cap.isOpened():
print(f"Error: Unable to open video {input_video_path}")
continue
# 获取视频的原始参数
original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 总帧数
# 获取裁剪尺寸和定点信息
crop_width = crop_setting['crop_width']
crop_height = crop_setting['crop_height']
anchor = crop_setting['anchor']
# 根据定点设置裁剪起点坐标
if anchor == 'bottom_left':
x_start = 0
y_start = original_height - crop_height
elif anchor == 'bottom_right':
x_start = original_width - crop_width
y_start = original_height - crop_height
# 设置输出视频编码格式和属性
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 使用 mp4v 编码格式保存为 MP4 文件
out = cv2.VideoWriter(output_video_path, fourcc, fps, (crop_width, crop_height))
current_frame = 0
while True:
ret, frame = cap.read()
if not ret:
break
# 裁剪帧
cropped_frame = frame[y_start:y_start + crop_height, x_start:x_start + crop_width]
# 将裁剪后的帧写入到输出视频
out.write(cropped_frame)
# 更新当前帧数并打印进度
current_frame += 1
progress = (current_frame / total_frames) * 100 # 计算当前进度百分比
print(f"Processing video '{video_file}' from folder '{folder_name}'... {progress:.2f}% completed")
cap.release()
out.release()
print(f"Cropped video saved as {output_video_path}\n")
print("All videos processed.")
代码简释:
- 首先定义了输入和输出的文件夹,其中包含视频的子文件夹;
- 批量从文件夹内部处理对应的视频文件并按照不同的裁剪框裁剪;
- 通过将当前处理的帧数和总共帧数计算百分比输出显示进度让大家看的时候不会不耐烦;
- 批处理完成后同样将每一个视频加上cropped重命名保存到输出目录。
裁剪掉了树和交通灯以及远处的车辆:
基本数据提取
YOLOv8车辆识别
模型训练
我们可以采用自己训练的方式训练出一组检测率较高的车体检测模型,首先需要车体的数据集,可以前往Roboflow下载yolov8数据集进行训练,训练方式是:
- 先设置一个yaml文件内部引入了对应数据集的信息,yaml文件应当表示如下:
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/Parking # dataset root dir
train: train/images # train images (relative to 'path') 4 images
val: valid/images # val images (relative to 'path') 4 imagesS
test: # test images (optional)
# Classes
names:
0: car5
1: car4
2: car3
3: car2
4: car1
5: car
- 然后按照该yaml文件内部的目录前往../datasets/Parking目录下创建train、valid、test文件夹;
- 将下载的数据集放到train,部分放到valid目录下;
train目录下应当有图片和对应的标签文件夹:
- 同样如果能够采集数据的自己拍摄数据并利用LabelImg进行标注并按照上述步骤存放数据集;
- 最后在配置好的环境下输入:
yolo detect train data="E://Library//AI//ultralytics//coco_set3.yaml" model="E://Library//AI//ultralytics//weights//detect//yolov8n.pt" epochs=120 imgsz=320 batch=8 workers=0 device=0
其中data代表yaml目录,model代表yolov8的预训练模型路径、epochs代表迭代次数、imgsz代表训练的图片尺寸、batch每次训练迭代中使用的图像数量、worker代表指定了用于数据加载的worker数量、指定了用于训练的设备,设置为0用GPU训练。
本处案例不采用训练新模型,本案例直接采用yolov8预训练模型,模型下载地址可参考:
Jetson Nano 开发环境搭建与实战、开发入门与进阶指南:系统、远程桌面及深度学习工具,包含基础配置、编程开发与视觉应用_jetson nano入门-CSDN博客当中关于yolov8配置安装的部分。
车流量(单位时间内的车辆数)检测
为了得到相同的时间序列以得到单位时间内的车辆数,需分别对降帧后的视频进行图像处理。这里本文将视频降帧为原来的十分之一,对于第二个观测点和第四个观测点的视频,以每5帧为时间序列,进而通过公式计算得到车辆数;同理,对于第二个观测点和第四个观测点的视频,以每10帧为时间序列,通过下列公式计算得到车辆数。
如果原视频视频帧数是25:
如果原视频视频帧数是33:
其中代表某一帧当中检测的车辆个数,N代表每秒的车辆数。
导入需要的库:
import os
import cv2
import csv
from ultralytics import YOLO
加载预训练模型:
model = YOLO('yolov8n.pt')
编写下列核心部分代码识别车体并记录数据:
while True:
ret, frame = cap.read()
if not ret:
break
results = model(frame)
car_count_in_frame = 0
for result in results[0].boxes.data:
if int(result[-1]) == 2:
car_count_in_frame += 1
# 更新每帧车的总数
car_count += car_count_in_frame
frame_count += 1
# 每处理五帧计算车流量
if frame_count % 5 == 0:
# 两秒车流量为过去五帧检测到的车数量总和除以 2
car_flow = car_count / 2
time_in_seconds = frame_count / fps
writer.writerow([time_in_seconds, car_flow])
car_count = 0
利用csv库的函数编写代码:
writer.writerow([time_in_seconds, car_flow])
将识别的车体数据保存到csv当中用于进一步处理,命名格式为car_flow加上原预处理文件名字。
观察识别过程当中的图片可以大致查看车体检测的准确度。
YOLOv8车速检测
为了计算车辆的速度,需要有路程和时间两个量来计算,考虑到一般监控摄像头视像的拍摄角度必然是平行于地面的,给图像设置了一条横线DOI,当车辆的方框接触此线到最后离开此线的时间内,只要车辆类型差不多的情况下三车道走过的路程基本相同。通过国标路标的长度和对应拍摄角度的图像距离和像素距离得到了一个猜测距离A,为确保速度精准度设置了卡车和轿车的不同参数和。当检测车体的方框横线触碰到DOI线后,立即分配一个ID并开始计时,直到该车辆方框从DOI线离开后计时,此时计时结束。车辆在场时间即为检测时间。单辆车的此时间段内的平均速度为:
其中代表ID是第 i 辆车子的车子型号,卡车则为1,轿车则为0,代表这辆车子的速度。同时为了获取车道内总体的车辆速度,采用加权求和的方式:
其中n代表单位时间内经过视频内设置的DOI横线的车辆数,代表权重,默认为1,则是在单位时间内测量的车道内总的车速数值。
建立好上述数学基础表示方式后编写代码:
首先加载基础库和预训练模型以及定义输入输出路径、定义不同车体在该视频当中的实际距离(通过视角和实际场景模型预估数据):
import cv2
import os
import csv
from ultralytics import YOLO
# 加载 YOLOv8 模型
model = YOLO('yolov8n.pt') # 确保你已经下载了yolov8n.pt权重文件
# 定义输入和输出根目录
input_root = 'slower' # 输入视频文件夹路径
output_root = 'car_speed' # 输出 CSV 文件的保存路径
# 定义在该车道内中心线不同车经过长度
car_length = 34.53
truck_length = 56.21
然后编写核心部分代码:
while True:
ret, frame = cap.read()
if not ret:
break
current_frame += 1
results = model(frame)
for result in results[0].boxes.data:
# 获取车辆类别
class_id = int(result[-1])
if class_id == 2: # 'car'
vehicle_type = 'car'
vehicle_length = car_length
elif class_id == 7: # 'truck'
vehicle_type = 'truck'
vehicle_length = truck_length
else:
continue
# 获取车辆的边界框
x1, y1, x2, y2 = map(int, result[:4])
vehicle_id = str(result[-2])
# 计算车辆的底部位置
vehicle_bottom_y = y2
# 检查车辆是否已经被追踪
if vehicle_id not in vehicle_tracking and vehicle_bottom_y > center_line_y:
# 车辆第一次触碰 DOI 线,开始计时
vehicle_tracking[vehicle_id] = [total_time, None, vehicle_type]
print(f"Vehicle {vehicle_id} detected at time {total_time:.2f}s")
elif vehicle_id in vehicle_tracking and vehicle_bottom_y < center_line_y:
# 车辆离开 DOI 线,结束计时
enter_time = vehicle_tracking[vehicle_id][0]
leave_time = total_time
vehicle_type = vehicle_tracking[vehicle_id][2]
time_diff = leave_time - enter_time # 经过时间
# 计算速度
if time_diff > 0 and time_diff < 15:
speed = vehicle_length / time_diff # 速度(m/s)
print(f"Vehicle {vehicle_id} speed: {speed:.2f} m/s")
# 记录速度和当前总时间到 CSV 文件
writer.writerow([total_time, speed])
# 移除追踪
vehicle_tracking.pop(vehicle_id)
total_time += 1 / fps
progress = (current_frame / total_frames) * 100
print(f"Processing video '{video_file}'... {progress:.2f}% completed")
cap.release()
代码简释:
- 首先逐个视频处理,每一个视频都拆成对应的每一帧同样逐帧处理;
- 根据yolov8预训练模型当中的coco的yaml文件选择需要识别的car和trunk进行识别并给每一个识别的对象都加上独立的ID和车体类型属性;
- 给每一个车体都画框并记录框接触线和离开线的时间并计算时间差;
- 记录的时间差可能会因为yolov8误判,同时高速路口车速不会太低,设置高于15的时间差不予记录;
- 通过将当前处理的帧数和总共帧数计算百分比输出显示进度让大家看的时候不会不耐烦;
- 批处理完成后保存速度数据为csv文件并保存到输出目录。
识别过程当中通过下列代码输出的显示界面如下:
cv2.putText(frame, f"Speed: {speed:.2f} m/s", (x1, y1 + 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
cv2.line(frame, (0, center_line_y), (width, center_line_y), (0, 255, 255), 2)
cv2.imshow('Vehicle Detection and Speed Estimation', frame)
最终能够得到该视频每次采样时间内的时间和总体车道速度的表格文件:
注意:
此策略记录的车速会受到摄像头监控角度、距离预测准度、车体实际车速等量的综合影响,为计算实际车道内部的总体车速需要让这几个量要有一定的精准度从而让预测数据较为实际描述车道的速度。
部分优化策略:
为了节省算力在计算速度的情况下如果车体方框底部过线就不需要再记录该车体并将多余的ID分配到别的车上,显示界面如下:
YOLOv8道路时间占有率计算
道路时间占有率是衡量道路上车辆密度的一个指标,表示在某一时刻道路上被车辆占据的空间比例,在一定程度上可以用于反映道路拥堵程度。为了获取该数据,同样每辆车在检测区域内首次出现时会被分配一个唯一的ID,并记录该时刻的时间作为车辆进入检测区域的时间。在接下来的每一帧中,通过跟踪车辆的ID来判断车辆是否仍然在检测区域内。如果车辆在当前帧中未被检测到,说明该车辆已经离开了检测区域,此时记录车辆离开检测区域的时间,并结束计时。车辆的停滞时间定义为车辆在检测区域内的总停留时间。同时记录单位每分钟内的车辆数和每辆车对应的停留时间,可以得到某一时刻道路时间占有率为:
编写批处理简易代码:
首先引入基础库:
import cv2
import csv
import os
from ultralytics import YOLO
model = YOLO('yolov8n.pt')
input_folder = 'fastflow' # 输入路径
output_folder = 'fastflow' # 输出 CSV 文件路径
如果没有该文件夹则创建文件夹,并遍历文件夹内部视频文件,利用OpenCV读取视频获取总fps数方便显示进度,然后初始化车体属性数据,包括开始和结束时间、ID、时间间隔
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for video_file in os.listdir(input_folder):
if video_file.endswith('.mp4'):
input_video_path = os.path.join(input_folder, video_file)
output_csv_path = os.path.join(output_folder, f"{video_file.replace('.mp4', '_car_times.csv')}")
cap = cv2.VideoCapture(input_video_path)
fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frame_time = 1 / fps
car_times = {} # {car_id: start_time}
unique_vehicle_id = 0 # 全局唯一车辆ID
total_time = 0 # 每60秒内总的车辆存在时间
time_interval = 60
elapsed_time = 0
核心部分:开始给视频的每一个车体都添加独特ID并实时检测该ID的车是否还能检测到直到视频当中无法检测到为止记录截止时间,以每分钟作为一个周期利用公式计算occ数据,最后将生成csv文件并记录数据。
with open(output_csv_path, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['Video Time (s)', 'Average Time (s)'])
while True:
ret, frame = cap.read()
if not ret:
break # 视频结束
current_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000 # 当前帧时间(秒)
elapsed_time += frame_time # 更新已过去的时间
results = model(frame)
detected_vehicle_ids = set()
for result in results[0].boxes.data:
# 分配唯一ID给每辆车
vehicle_id = unique_vehicle_id
x1, y1, x2, y2 = map(int, result[:4])
vehicle_bottom_y = y2
# 如果车辆第一次出现,记录初始时间
if vehicle_id not in car_times:
car_times[vehicle_id] = current_time # 记录车辆开始计时的时间
unique_vehicle_id += 1
detected_vehicle_ids.add(vehicle_id)
# 处理车辆的消失检测:如果某个车辆在当前帧未检测到,则认为它已消失
for vehicle_id in list(car_times):
if vehicle_id not in detected_vehicle_ids:
# 车辆消失,计算车辆在场的时间并加入到总时间
start_time = car_times.pop(vehicle_id)
vehicle_time = current_time - start_time
total_time += vehicle_time
# 每 60 秒处理一次,计算总时间 / 60
if elapsed_time >= time_interval:
average_time = total_time / time_interval # 平均时间
print(f"Processing video: {video_file}, Video Time: {current_time:.2f}s, Average Vehicle Time: {average_time:.2f}s")
# 记录到 CSV 文件
writer.writerow([round(current_time, 2), round(average_time, 2)])
total_time = 0
elapsed_time = 0
cap.release()
基本数据的函数模型
通过上述步骤得到的生数据是在固定采样周期或者不定频率采样周期当中得到的数万个点集,每一个具体时间段的数据都有其该时刻的特点而不能反映车道总体趋势的变化,为了能够准确反应并方便构造数学模型考虑用多次函数来拟合在该时间段内的总体趋势,采用matlab的数据分析函数polyfit进行多次函数拟合:
其中matlab代码表示如下,从csv当中读取数据并进行数据处理:
% 读取数据
data = readmatrix('data.csv');
time = data(:, 1); % 第一列为时间
flow = data(:, 2); % 第二列为流量
% 进行22阶多项式拟合
p = polyfit(time, flow, 22);
% 计算拟合值
fittedFlow = polyval(p, time);
% 绘制原始数据和拟合曲线
figure;
plot(time, flow, 'bo', 'DisplayName', '原始数据'); % 使用蓝色圆点绘制原始数据
hold on;
plot(time, fittedFlow, 'r-', 'DisplayName', '拟合曲线'); % 使用红线绘制拟合曲线
legend('show');
xlabel('时间/(s)');
ylabel('通过该地点的车辆数');
title('32.32.250。107');
% 输出拟合参数
disp('22阶拟合的参数向量:');
disp(p);
利用上述拟合代码给车流量拟合的结果图:
利用上述拟合代码给车速拟合的结果图:
利用上述拟合代码给道路时间占有率拟合的结果图:
由此可以得到整个车道内车速、流量、道路时间占有率和时间的关系表达式。
交通指数模型
模型一
交通状态评估标准在动态应急车道开放的决策模型中扮演了至关重要的角色,作为开放应急车道的关键前提条件。为了衡量交通拥挤程度,本文引用了一项指标,即交通拥挤指数【1】 (Traffic Performance Index,即“TPI”)。交通拥堵指数通过衡量道路的通行状况,提供了一个综合性的指标,用以量化道路的流畅度或拥堵程度。如表4-1所示,该指数设置在1到10的范围内,并分为五个等级,包括“畅通”、“基本畅通”、“轻度拥堵”、“中度拥堵”和“严重拥堵”,其中指数值越高,表示交通的拥堵程度越严重。其具体算法如下公式所示:
模型二
考虑到在高速公路上车速较高的情况下一般不会拥堵而低速的情况下拥堵量较大从而加入车速倒数项反映第一种拥堵度;同时车流量和最大流量的比值也能反映车道的承载力,也能够反映车道的拥堵程度;同时上述步骤当中直接测量的道路时间占有率也能够反映一种拥堵程度,因此综合考虑这三种拥堵量并添加权重求和组合为一个新的拥堵程度:
合并模型:
给两个模型都添加对应的权重参数合并为新模型,考虑到部分模型其中存在跑飞(过大或者过小的情况)出现,综合考虑的模型需要去除这部分干扰因子,通过编写自适应的参数函数来自动调节参数从而避免上述情况。
该式解释如下:
- 如果两个模型预测的拥堵数都在合理范围内则按照权重0.7和0.3配比,μ为0.7;
- 如果其中一个模型预估误判则根据误判程度利用指数式纠正其权重以降低误判程度;
- 如果两个模型都预估超出预期认为此处拥堵程度较大,设置为最大值。
其中该式当中的修正权重表示为:
其中的参数又可以表示为:
将上述式子编写为matlab代码:
%混合拥堵模型
x = 0:1:17000;
camip = 105;
if camip == 107
%监测点107的拟合的流量、车道时间占用率、速度函数
elseif camip == 105
%监测点105的拟合的流量、车道时间占用率、速度函数
elseif camip == 108
%监测点108的拟合的流量、车道时间占用率、速度函数
elseif camip == 103
%监测点103的拟合的流量、车道时间占用率、速度函数
end
%文献拥堵核心模型
gamma = 10*(o.^2)./(n.*v + 0.00001);
plot(x,gamma,"r")
ylim([0,10])
%本文提出的模型
D = 0.32.*(2*(1./v)+8.*n./60+o);
rou = n./v;
hold on;
plot(x,D,"g")
% 计算新混合拥堵模型Y
Y = zeros(size(D));
for i = 1:length(D)
if abs(gamma(i)) > 10 && abs(D(i)) > 10
Y(i) = 10;
elseif abs(gamma(i)) > 10
A = gamma(i) / 10;
weight = 0.1^(log(A));
Y(i) = (1 - weight) * D(i) + weight * gamma(i);
elseif abs(D(i)) > 10
A = D(i) / 10;
weight = 0.1^(log(A));
Y(i) = weight * D(i) + (1 - weight) * gamma(i);
else
Y(i) = 0.3 * D(i) + 0.7 * gamma(i);
end
end
plot(x,Y,'k')
得到的混合拥堵模型:
根据上述得到的模型,可以预测在第三个地点到第四个地点之间,即观测点三至观测点四之间,时间约2000秒开始会有约1000秒的拥堵,时间约5500秒开始有约1500秒的拥堵,从视频当中验证了算法准确性。
小结
- 本文通过监测点视频提取了车辆模型的基本参数和数据;
- 利用参数构造了总体的车各种基本函数模型;
- 通过基本函数模型构造了两种车道拥堵基础模型;
- 综合不同拥堵模型综合分析了道路拥堵函数;
- 利用函数进行道路拥堵预判。
注:此案例来源于数学建模E第一问
参考文献:
- 杨阳,刘强,石英杰.高速公路饱和路段动态应急车道开放决策模型研究[J].公路工程,2022,47(03):172-176.DOI:10.19782/j.cnki.1674-0610.2022.03.027.