一、算法架构设计
城市车辆目标跟踪系统
视频输入层 │ 目标检测层 │ 多目标跟踪层 │ 轨迹管理
│ │ │
• 城市街景 │ • ACF检测 │ • Kalman滤波 │ • 轨迹预测
• 交通监控 │ • CNN检测 │ • 匈牙利匹配 │ • ID管理
• 车载视频 │ • 特征提取 │ • 遮挡处理 │ • 状态估计
│ • 非极大值抑制│ • 运动模型 │ • 轨迹平滑
二、实现
2.1 主程序 (urban_vehicle_tracking.m)
matlab
%% 城市环境下车辆目标跟踪系统
% 功能:基于多目标跟踪算法的城市车辆检测与跟踪
clear all; close all; clc;
fprintf('=== 城市环境下车辆目标跟踪系统 ===\n\n');
%% 1. 参数配置
config = struct();
config.video_file = 'urban_traffic.mp4'; % 城市交通视频文件
config.detector_type = 'acf'; % 检测器类型: 'acf', 'yolo', 'hog'
config.tracker_type = 'sort'; % 跟踪器类型: 'sort', 'deepsort', 'byte'
config.max_disappeared = 30; % 最大消失帧数
config.min_detection_confidence = 0.7; % 最小检测置信度
config.iou_threshold = 0.3; % IOU匹配阈值
config.max_distance = 100; % 最大匹配距离
config.show_trajectories = true; % 显示轨迹
config.save_results = true; % 保存结果
fprintf('系统配置:\n');
fprintf(' 检测器: %s\n', config.detector_type);
fprintf(' 跟踪器: %s\n', config.tracker_type);
fprintf(' IOU阈值: %.2f\n', config.iou_threshold);
fprintf(' 最大消失帧: %d\n\n', config.max_disappeared);
%% 2. 初始化检测器
fprintf('初始化车辆检测器...\n');
detector = initialize_vehicle_detector(config.detector_type);
fprintf('检测器初始化完成\n\n');
%% 3. 初始化跟踪器
fprintf('初始化多目标跟踪器...\n');
tracker = initialize_multi_object_tracker(config);
fprintf('跟踪器初始化完成\n\n');
%% 4. 打开视频文件
if exist(config.video_file, 'file')
video_reader = VideoReader(config.video_file);
fprintf('视频文件已加载: %s\n', config.video_file);
else
% 使用摄像头或生成测试视频
fprintf('视频文件不存在,使用测试视频生成器\n');
video_reader = generate_test_video();
end
%% 5. 主处理循环
fprintf('开始车辆跟踪处理...\n');
frame_count = 0;
tracking_results = struct('frame_ids', {}, 'bboxes', {}, 'track_ids', {});
while hasFrame(video_reader)
frame_count = frame_count + 1;
frame = readFrame(video_reader);
% 5.1 车辆检测
[detections, confidence_scores] = detect_vehicles(frame, detector, config);
% 5.2 多目标跟踪
[tracker, tracks] = update_tracker(tracker, detections, frame_count, config);
% 5.3 轨迹管理和预测
tracks = manage_tracks(tracks, frame_count, config);
% 5.4 存储结果
if config.save_results
tracking_results(frame_count).frame_id = frame_count;
tracking_results(frame_count).detections = detections;
tracking_results(frame_count).tracks = tracks;
end
% 5.5 可视化显示
display_results(frame, detections, tracks, confidence_scores, config);
% 5.6 控制显示速度
pause(0.03);
% 5.7 按q键退出
if frame_count > 1000 % 限制处理帧数
break;
end
end
fprintf('处理完成!共处理 %d 帧\n', frame_count);
%% 6. 性能评估
if config.save_results
evaluate_tracking_performance(tracking_results);
end
%% 7. 保存结果
if config.save_results
save('urban_vehicle_tracking_results.mat', 'tracking_results', 'config');
fprintf('结果已保存到: urban_vehicle_tracking_results.mat\n');
end
2.2 车辆检测器模块 (initialize_vehicle_detector.m)
matlab
function detector = initialize_vehicle_detector(detector_type)
% 初始化车辆检测器
switch detector_type
case 'acf'
% 使用MATLAB内置的ACF车辆检测器
detector = vehicleDetectorACF('caltech');
detector.MinObjectSize = [20, 20];
detector.WindowStride = 4;
detector.MaxWeakCount = 100;
case 'hog'
% 基于HOG特征的检测器
hog = extractHOGFeatures(randn(64,64,3), 'CellSize', [8 8]);
detector.hog_cell_size = [8, 8];
detector.window_size = [64, 64];
detector.svm_model = train_hog_detector();
case 'yolo'
% YOLO风格的检测器(简化版)
detector.network = initialize_yolo_network();
detector.anchor_boxes = [32, 64, 128, 256];
detector.confidence_threshold = 0.5;
otherwise
error('未知的检测器类型: %s', detector_type);
end
detector.type = detector_type;
fprintf(' %s检测器配置完成\n', detector_type);
end
function svm_model = train_hog_detector()
% 训练HOG-SVM检测器(简化版)
% 实际应用中需要使用标注数据进行训练
svm_model = struct();
svm_model.weights = randn(3780, 1); % HOG特征维度
svm_model.bias = 0.5;
end
function network = initialize_yolo_network()
% 初始化简化的YOLO网络
network = struct();
network.conv1 = randn(3, 3, 3, 16);
network.conv2 = randn(3, 3, 16, 32);
network.fc = randn(7*7*32, 5); % 5: x,y,w,h,confidence
end
2.3 检测函数 (detect_vehicles.m)
matlab
function [detections, confidence_scores] = detect_vehicles(frame, detector, config)
% 执行车辆检测
detections = [];
confidence_scores = [];
switch detector.type
case 'acf'
% ACF检测器
[bboxes, scores] = detect(detector, frame);
% 过滤低置信度检测
keep_idx = scores > config.min_detection_confidence;
detections = bboxes(keep_idx, :);
confidence_scores = scores(keep_idx);
% 非极大值抑制
if ~isempty(detections)
[detections, confidence_scores] = non_maximum_suppression(...
detections, confidence_scores, 0.3);
end
case 'hog'
% HOG检测器
[detections, confidence_scores] = hog_detect_vehicles(frame, detector);
case 'yolo'
% YOLO检测器
[detections, confidence_scores] = yolo_detect_vehicles(frame, detector);
end
% 确保检测框格式正确
if ~isempty(detections)
detections = round(detections);
% 限制边界
[h, w, ~] = size(frame);
detections(:,1) = max(1, detections(:,1));
detections(:,2) = max(1, detections(:,2));
detections(:,3) = min(w, detections(:,3));
detections(:,4) = min(h, detections(:,4));
end
end
function [detections, scores] = hog_detect_vehicles(frame, detector)
% HOG车辆检测
gray = rgb2gray(frame);
[h, w] = size(gray);
detections = [];
scores = [];
% 滑动窗口检测
window_size = detector.window_size;
cell_size = detector.hog_cell_size;
for y = 1:cell_size(1):h-window_size(1)
for x = 1:cell_size(2):w-window_size(2)
patch = gray(y:y+window_size(1)-1, x:x+window_size(2)-1);
hog_features = extractHOGFeatures(patch, 'CellSize', cell_size);
% SVM分类
score = hog_features * detector.svm_model.weights + detector.svm_model.bias;
if score > 0.5
detections = [detections; [x, y, window_size(2), window_size(1)]];
scores = [scores; score];
end
end
end
end
function [detections, scores] = yolo_detect_vehicles(frame, detector)
% 简化的YOLO检测
[h, w, ~] = size(frame);
% 生成网格
grid_size = 7;
cell_w = w / grid_size;
cell_h = h / grid_size;
detections = [];
scores = [];
for i = 1:grid_size
for j = 1:grid_size
x = (j-1) * cell_w + cell_w/2;
y = (i-1) * cell_h + cell_h/2;
% 模拟检测
if rand() > 0.7 % 30%的概率检测到车辆
w_box = 50 + rand() * 100;
h_box = 30 + rand() * 60;
confidence = 0.6 + rand() * 0.4;
detections = [detections; [x-w_box/2, y-h_box/2, w_box, h_box]];
scores = [scores; confidence];
end
end
end
end
function [bboxes, scores] = non_maximum_suppression(bboxes, scores, overlap_thresh)
% 非极大值抑制
if isempty(bboxes)
return;
end
x1 = bboxes(:,1);
y1 = bboxes(:,2);
x2 = bboxes(:,1) + bboxes(:,3);
y2 = bboxes(:,2) + bboxes(:,4);
areas = (x2 - x1 + 1) .* (y2 - y1 + 1);
[~, order] = sort(scores, 'descend');
keep = [];
while order.length > 0
i = order(1);
keep = [keep; i];
xx1 = max(x1(i), x1(order(2:end)));
yy1 = max(y1(i), y1(order(2:end)));
xx2 = min(x2(i), x2(order(2:end)));
yy2 = min(y2(i), y2(order(2:end)));
w = max(0, xx2 - xx1 + 1);
h = max(0, yy2 - yy1 + 1);
inter = w .* h;
ovr = inter ./ (areas(i) + areas(order(2:end)) - inter);
inds = find(ovr <= overlap_thresh);
order = order(inds + 1);
end
bboxes = bboxes(keep, :);
scores = scores(keep);
end
2.4 多目标跟踪器 (initialize_multi_object_tracker.m)
matlab
function tracker = initialize_multi_object_tracker(config)
% 初始化多目标跟踪器
tracker = struct();
tracker.next_track_id = 1;
tracker.tracks = struct('id', {}, 'bbox', {}, 'kalman_filter', {}, ...
'age', {}, 'disappeared', {}, 'trajectory', {});
tracker.config = config;
tracker.frame_count = 0;
fprintf(' 多目标跟踪器初始化完成\n');
end
function [tracker, tracks] = update_tracker(tracker, detections, frame_count, config)
% 更新跟踪器
tracker.frame_count = frame_count;
tracks = tracker.tracks;
if isempty(tracks)
% 没有现有轨迹,创建新轨迹
if ~isempty(detections)
for i = 1:size(detections, 1)
tracker = create_new_track(tracker, detections(i, :), frame_count);
end
end
tracks = tracker.tracks;
return;
end
% 预测现有轨迹
predicted_tracks = predict_tracks(tracks);
% 计算代价矩阵
cost_matrix = calculate_cost_matrix(predicted_tracks, detections);
% 使用匈牙利算法进行匹配
[matched_indices, unmatched_track_indices, unmatched_detection_indices] = ...
hungarian_matching(cost_matrix, config.iou_threshold);
% 更新匹配的轨迹
for i = 1:size(matched_indices, 1)
track_idx = matched_indices(i, 1);
det_idx = matched_indices(i, 2);
% 更新卡尔曼滤波
measurement = detections(det_idx, :);
tracks(track_idx) = update_kalman_filter(tracks(track_idx), measurement);
tracks(track_idx).disappeared = 0;
tracks(track_idx).trajectory{end+1} = measurement(1:2) + measurement(3:4)/2;
end
% 处理未匹配的轨迹
for i = 1:length(unmatched_track_indices)
track_idx = unmatched_track_indices(i);
tracks(track_idx).disappeared = tracks(track_idx).disappeared + 1;
end
% 处理未匹配的检测
for i = 1:length(unmatched_detection_indices)
det_idx = unmatched_detection_indices(i);
tracker = create_new_track(tracker, detections(det_idx, :), frame_count);
end
tracker.tracks = tracks;
end
function predicted_tracks = predict_tracks(tracks)
% 预测所有轨迹
predicted_tracks = tracks;
for i = 1:length(tracks)
if isfield(tracks(i), 'kalman_filter')
predicted_tracks(i) = predict_kalman_filter(tracks(i));
end
end
end
function cost_matrix = calculate_cost_matrix(tracks, detections)
% 计算代价矩阵(IOU距离)
num_tracks = length(tracks);
num_detections = size(detections, 1);
cost_matrix = zeros(num_tracks, num_detections);
for i = 1:num_tracks
track_bbox = tracks(i).bbox;
for j = 1:num_detections
det_bbox = detections(j, :);
cost_matrix(i, j) = 1 - calculate_iou(track_bbox, det_bbox);
end
end
end
function iou = calculate_iou(bbox1, bbox2)
% 计算IOU
x1 = max(bbox1(1), bbox2(1));
y1 = max(bbox1(2), bbox2(2));
x2 = min(bbox1(1) + bbox1(3), bbox2(1) + bbox2(3));
y2 = min(bbox1(2) + bbox1(4), bbox2(2) + bbox2(4));
inter_area = max(0, x2 - x1) * max(0, y2 - y1);
union_area = bbox1(3)*bbox1(4) + bbox2(3)*bbox2(4) - inter_area;
iou = inter_area / union_area;
end
function [matched_indices, unmatched_tracks, unmatched_detections] = hungarian_matching(cost_matrix, threshold)
% 匈牙利算法匹配
[num_tracks, num_detections] = size(cost_matrix);
% 简化版本:贪心匹配
matched_indices = [];
unmatched_tracks = 1:num_tracks;
unmatched_detections = 1:num_detections;
% 按代价排序
[sorted_costs, sorted_indices] = sort(cost_matrix(:));
[track_indices, det_indices] = ind2sub(size(cost_matrix), sorted_indices);
used_tracks = false(num_tracks, 1);
used_detections = false(num_detections, 1);
for k = 1:length(sorted_costs)
if sorted_costs(k) > threshold
break;
end
track_idx = track_indices(k);
det_idx = det_indices(k);
if ~used_tracks(track_idx) && ~used_detections(det_idx)
matched_indices = [matched_indices; [track_idx, det_idx]];
used_tracks(track_idx) = true;
used_detections(det_idx) = true;
end
end
unmatched_tracks = find(~used_tracks);
unmatched_detections = find(~used_detections);
end
function tracker = create_new_track(tracker, bbox, frame_count)
% 创建新轨迹
track_id = tracker.next_track_id;
tracker.next_track_id = tracker.next_track_id + 1;
% 初始化卡尔曼滤波
kalman_filter = initialize_kalman_filter(bbox);
% 创建轨迹结构
new_track = struct();
new_track.id = track_id;
new_track.bbox = bbox;
new_track.kalman_filter = kalman_filter;
new_track.age = 1;
new_track.disappeared = 0;
new_track.trajectory = {bbox(1:2) + bbox(3:4)/2};
new_track.start_frame = frame_count;
% 添加到跟踪器
tracker.tracks(end+1) = new_track;
end
2.5 卡尔曼滤波模块
matlab
function kalman_filter = initialize_kalman_filter(bbox)
% 初始化卡尔曼滤波
kalman_filter = struct();
% 状态向量: [x, y, w, h, vx, vy, vw, vh]
kalman_filter.state = [bbox(1)+bbox(3)/2, bbox(2)+bbox(4)/2, bbox(3), bbox(4), 0, 0, 0, 0]';
% 状态转移矩阵 (匀速运动模型)
dt = 1;
kalman_filter.F = [1 0 0 0 dt 0 0 0;
0 1 0 0 0 dt 0 0;
0 0 1 0 0 0 dt 0;
0 0 0 1 0 0 0 dt;
0 0 0 0 1 0 0 0;
0 0 0 0 0 1 0 0;
0 0 0 0 0 0 1 0;
0 0 0 0 0 0 0 1];
% 观测矩阵 (只能观测位置和大小)
kalman_filter.H = [1 0 0 0 0 0 0 0;
0 1 0 0 0 0 0 0;
0 0 1 0 0 0 0 0;
0 0 0 1 0 0 0 0];
% 过程噪声协方差
kalman_filter.Q = eye(8) * 0.01;
% 观测噪声协方差
kalman_filter.R = eye(4) * 1;
% 估计误差协方差
kalman_filter.P = eye(8) * 100;
end
function track = predict_kalman_filter(track)
% 卡尔曼滤波预测
kalman_filter = track.kalman_filter;
% 预测状态
kalman_filter.state = kalman_filter.F * kalman_filter.state;
kalman_filter.P = kalman_filter.F * kalman_filter.P * kalman_filter.F' + kalman_filter.Q;
% 更新边界框
center_x = kalman_filter.state(1);
center_y = kalman_filter.state(2);
width = kalman_filter.state(3);
height = kalman_filter.state(4);
track.bbox = [center_x - width/2, center_y - height/2, width, height];
track.kalman_filter = kalman_filter;
end
function track = update_kalman_filter(track, measurement)
% 卡尔曼滤波更新
kalman_filter = track.kalman_filter;
% 观测向量
z = [measurement(1)+measurement(3)/2, measurement(2)+measurement(4)/2, measurement(3), measurement(4)]';
% 计算卡尔曼增益
K = kalman_filter.P * kalman_filter.H' / (kalman_filter.H * kalman_filter.P * kalman_filter.H' + kalman_filter.R);
% 更新状态
kalman_filter.state = kalman_filter.state + K * (z - kalman_filter.H * kalman_filter.state);
kalman_filter.P = (eye(8) - K * kalman_filter.H) * kalman_filter.P;
track.kalman_filter = kalman_filter;
track.bbox = measurement;
end
2.6 轨迹管理模块 (manage_tracks.m)
matlab
function tracks = manage_tracks(tracks, frame_count, config)
% 管理轨迹:删除长时间消失的轨迹
valid_tracks = [];
for i = 1:length(tracks)
track = tracks(i);
% 删除长时间消失的轨迹
if track.disappeared < config.max_disappeared
track.age = track.age + 1;
valid_tracks = [valid_tracks; track];
end
end
tracks = valid_tracks;
end
2.7 可视化模块 (display_results.m)
matlab
function display_results(frame, detections, tracks, confidence_scores, config)
% 显示跟踪结果
figure(1);
imshow(frame);
hold on;
% 显示检测结果
if ~isempty(detections)
for i = 1:size(detections, 1)
bbox = detections(i, :);
rectangle('Position', [bbox(1), bbox(2), bbox(3), bbox(4)], ...
'EdgeColor', 'green', 'LineWidth', 1);
if length(confidence_scores) >= i
text(bbox(1), bbox(2)-5, sprintf('%.2f', confidence_scores(i)), ...
'Color', 'green', 'FontSize', 10, 'FontWeight', 'bold');
end
end
end
% 显示跟踪轨迹
if config.show_trajectories && ~isempty(tracks)
colors = lines(length(tracks));
for i = 1:length(tracks)
track = tracks(i);
% 绘制边界框
bbox = track.bbox;
rectangle('Position', [bbox(1), bbox(2), bbox(3), bbox(4)], ...
'EdgeColor', colors(i,:), 'LineWidth', 2);
% 绘制轨迹
if length(track.trajectory) > 1
traj = cell2mat(track.trajectory);
plot(traj(:,1), traj(:,2), '-', 'Color', colors(i,:), 'LineWidth', 1);
end
% 显示ID和年龄
text(bbox(1), bbox(2)-10, sprintf('ID:%d Age:%d', track.id, track.age), ...
'Color', colors(i,:), 'FontSize', 10, 'FontWeight', 'bold');
end
end
hold off;
drawnow;
end
2.8 测试视频生成 (generate_test_video.m)
matlab
function video = generate_test_video()
% 生成测试视频(模拟城市交通场景)
% 创建视频写入器
writer = VideoWriter('urban_traffic_test.mp4', 'MPEG-4');
writer.FrameRate = 30;
open(writer);
% 生成100帧测试视频
for frame_idx = 1:100
frame = generate_urban_frame(frame_idx);
writeVideo(writer, frame);
end
close(writer);
% 返回视频读取器
video = VideoReader('urban_traffic_test.mp4');
end
function frame = generate_urban_frame(frame_idx)
% 生成城市交通帧
frame = uint8(zeros(480, 640, 3));
% 绘制道路背景
frame = draw_road_background(frame);
% 绘制移动车辆
frame = draw_moving_vehicles(frame, frame_idx);
% 添加一些噪声和光照变化
frame = add_lighting_effects(frame, frame_idx);
end
function frame = draw_road_background(frame)
% 绘制道路背景
[h, w, ~] = size(frame);
% 天空
frame(1:round(h/2), :, 1) = 135;
frame(1:round(h/2), :, 2) = 206;
frame(1:round(h/2), :, 3) = 235;
% 道路
road_start = round(w/3);
road_end = round(2*w/3);
frame(round(h/2):end, road_start:road_end, 1) = 80;
frame(round(h/2):end, road_start:road_end, 2) = 80;
frame(round(h/2):end, road_start:road_end, 3) = 80;
% 道路标线
for y = round(h/2):20:h
frame(y:y+5, road_start-2:road_start+2, :) = 255;
frame(y:y+5, road_end-2:road_end+2, :) = 255;
end
% 中央分隔线
frame(round(h/2):h, round(w/2)-2:round(w/2)+2, :) = 255;
end
function frame = draw_moving_vehicles(frame, frame_idx)
% 绘制移动车辆
[h, w, ~] = size(frame);
% 车辆1:从左向右移动
car1_x = mod(frame_idx * 3, w);
car1_y = round(h * 0.6);
frame = draw_car(frame, car1_x, car1_y, [255, 0, 0]); % 红色车
% 车辆2:从右向左移动
car2_x = mod(w - frame_idx * 2, w);
car2_y = round(h * 0.7);
frame = draw_car(frame, car2_x, car2_y, [0, 0, 255]); % 蓝色车
% 车辆3:静止车辆
frame = draw_car(frame, round(w/2), round(h*0.65), [0, 255, 0]); % 绿色车
end
function frame = draw_car(frame, x, y, color)
% 绘制车辆
[h, w, ~] = size(frame);
% 车辆尺寸
car_w = 40;
car_h = 20;
% 边界检查
x_start = max(1, x - car_w/2);
y_start = max(1, y - car_h/2);
x_end = min(w, x + car_w/2);
y_end = min(h, y + car_h/2);
% 绘制车身
frame(y_start:y_end, x_start:x_end, 1) = color(1);
frame(y_start:y_end, x_start:x_end, 2) = color(2);
frame(y_start:y_end, x_start:x_end, 3) = color(3);
% 绘制车窗
window_start_x = x_start + 5;
window_end_x = x_end - 5;
window_start_y = y_start + 3;
window_end_y = y_start + 8;
frame(window_start_y:window_end_y, window_start_x:window_end_x, :) = 200;
end
function frame = add_lighting_effects(frame, frame_idx)
% 添加光照效果
lighting_factor = 0.8 + 0.2 * sin(frame_idx * 0.1);
frame = uint8(double(frame) * lighting_factor);
end
2.9 性能评估模块 (evaluate_tracking_performance.m)
matlab
function evaluate_tracking_performance(tracking_results)
% 评估跟踪性能
fprintf('=== 跟踪性能评估 ===\n\n');
% 统计基本信息
num_frames = length(tracking_results);
total_detections = 0;
total_tracks = 0;
unique_track_ids = [];
for i = 1:num_frames
if isfield(tracking_results(i), 'detections') && ~isempty(tracking_results(i).detections)
total_detections = total_detections + size(tracking_results(i).detections, 1);
end
if isfield(tracking_results(i), 'tracks') && ~isempty(tracking_results(i).tracks)
tracks = tracking_results(i).tracks;
total_tracks = total_tracks + length(tracks);
for j = 1:length(tracks)
if isfield(tracks(j), 'id')
unique_track_ids = [unique_track_ids, tracks(j).id];
end
end
end
end
unique_track_ids = unique(unique_track_ids);
fprintf('基本统计:\n');
fprintf(' 处理帧数: %d\n', num_frames);
fprintf(' 总检测数: %d\n', total_detections);
fprintf(' 总跟踪数: %d\n', total_tracks);
fprintf(' 唯一轨迹ID数: %d\n', length(unique_track_ids));
fprintf(' 平均每帧检测数: %.2f\n', total_detections / num_frames);
fprintf(' 平均每帧跟踪数: %.2f\n\n', total_tracks / num_frames);
% 计算跟踪稳定性指标
fprintf('跟踪稳定性分析:\n');
track_lengths = zeros(length(unique_track_ids), 1);
for i = 1:length(unique_track_ids)
track_id = unique_track_ids(i);
track_length = 0;
for frame_idx = 1:num_frames
if isfield(tracking_results(frame_idx), 'tracks')
tracks = tracking_results(frame_idx).tracks;
for j = 1:length(tracks)
if isfield(tracks(j), 'id') && tracks(j).id == track_id
track_length = track_length + 1;
break;
end
end
end
end
track_lengths(i) = track_length;
end
fprintf(' 最长轨迹长度: %d 帧\n', max(track_lengths));
fprintf(' 最短轨迹长度: %d 帧\n', min(track_lengths));
fprintf(' 平均轨迹长度: %.2f 帧\n', mean(track_lengths));
fprintf(' 轨迹长度标准差: %.2f 帧\n\n', std(track_lengths));
% 可视化轨迹分析
visualize_tracking_statistics(tracking_results, unique_track_ids);
end
function visualize_tracking_statistics(tracking_results, unique_track_ids)
% 可视化跟踪统计
figure('Position', [100, 100, 1200, 800]);
% 1. 每帧检测数和跟踪数
subplot(2, 3, 1);
frame_indices = 1:length(tracking_results);
detections_per_frame = zeros(length(tracking_results), 1);
tracks_per_frame = zeros(length(tracking_results), 1);
for i = 1:length(tracking_results)
if isfield(tracking_results(i), 'detections') && ~isempty(tracking_results(i).detections)
detections_per_frame(i) = size(tracking_results(i).detections, 1);
end
if isfield(tracking_results(i), 'tracks') && ~isempty(tracking_results(i).tracks)
tracks_per_frame(i) = length(tracking_results(i).tracks);
end
end
plot(frame_indices, detections_per_frame, 'g-', 'LineWidth', 1.5, 'DisplayName', '检测数');
hold on;
plot(frame_indices, tracks_per_frame, 'r-', 'LineWidth', 1.5, 'DisplayName', '跟踪数');
xlabel('帧序号');
ylabel('数量');
title('每帧检测数与跟踪数对比');
legend('Location', 'northwest');
grid on;
% 2. 轨迹长度分布
subplot(2, 3, 2);
track_lengths = zeros(length(unique_track_ids), 1);
for i = 1:length(unique_track_ids)
track_id = unique_track_ids(i);
track_length = 0;
for frame_idx = 1:length(tracking_results)
if isfield(tracking_results(frame_idx), 'tracks')
tracks = tracking_results(frame_idx).tracks;
for j = 1:length(tracks)
if isfield(tracks(j), 'id') && tracks(j).id == track_id
track_length = track_length + 1;
break;
end
end
end
end
track_lengths(i) = track_length;
end
histogram(track_lengths, 10, 'FaceColor', 'b', 'EdgeColor', 'none');
xlabel('轨迹长度 (帧)');
ylabel('轨迹数量');
title('轨迹长度分布');
grid on;
% 3. 跟踪ID随时间变化
subplot(2, 3, 3);
track_id_matrix = zeros(length(unique_track_ids), length(tracking_results));
for i = 1:length(unique_track_ids)
track_id = unique_track_ids(i);
for frame_idx = 1:length(tracking_results)
if isfield(tracking_results(frame_idx), 'tracks')
tracks = tracking_results(frame_idx).tracks;
for j = 1:length(tracks)
if isfield(tracks(j), 'id') && tracks(j).id == track_id
track_id_matrix(i, frame_idx) = 1;
break;
end
end
end
end
end
imagesc(track_id_matrix);
xlabel('帧序号');
ylabel('轨迹ID');
title('轨迹存在性矩阵');
colorbar;
% 4. 检测与跟踪的一致性
subplot(2, 3, 4);
consistency_ratio = zeros(length(tracking_results), 1);
for i = 1:length(tracking_results)
if isfield(tracking_results(i), 'detections') && isfield(tracking_results(i), 'tracks')
detections = tracking_results(i).detections;
tracks = tracking_results(i).tracks;
if ~isempty(detections) && ~isempty(tracks)
% 计算检测框与跟踪框的IOU
ious = zeros(size(detections, 1), length(tracks));
for d = 1:size(detections, 1)
for t = 1:length(tracks)
if isfield(tracks(t), 'bbox')
ious(d, t) = calculate_iou(detections(d, :), tracks(t).bbox);
end
end
end
% 计算一致性比例
max_ious = max(ious, [], 2);
consistency_ratio(i) = mean(max_ious > 0.5);
end
end
end
plot(frame_indices, consistency_ratio, 'b-', 'LineWidth', 1.5);
xlabel('帧序号');
ylabel('一致性比例');
title('检测与跟踪一致性');
ylim([0, 1]);
grid on;
% 5. 跟踪稳定性指标
subplot(2, 3, 5);
stability_metrics = zeros(length(unique_track_ids), 3);
for i = 1:length(unique_track_ids)
track_id = unique_track_ids(i);
trajectory = [];
for frame_idx = 1:length(tracking_results)
if isfield(tracking_results(frame_idx), 'tracks')
tracks = tracking_results(frame_idx).tracks;
for j = 1:length(tracks)
if isfield(tracks(j), 'id') && tracks(j).id == track_id && isfield(tracks(j), 'trajectory')
if ~isempty(tracks(j).trajectory)
traj_points = tracks(j).trajectory{end};
trajectory = [trajectory; traj_points'];
end
end
end
end
end
if size(trajectory, 1) > 1
% 计算轨迹平滑度(加速度变化)
velocities = diff(trajectory, 1, 1);
accelerations = diff(velocities, 1, 1);
stability_metrics(i, 1) = mean(abs(accelerations(:, 1))); % x方向加速度
stability_metrics(i, 2) = mean(abs(accelerations(:, 2))); % y方向加速度
stability_metrics(i, 3) = std(accelerations(:, 1)) + std(accelerations(:, 2)); % 总抖动
end
end
bar([mean(stability_metrics(:,1)), mean(stability_metrics(:,2)), mean(stability_metrics(:,3))]);
set(gca, 'XTickLabel', {'X加速度', 'Y加速度', '总抖动'});
ylabel('稳定性指标');
title('跟踪稳定性分析');
grid on;
% 6. 综合性能雷达图
subplot(2, 3, 6);
radar_chart(stability_metrics);
title('跟踪性能雷达图');
sgtitle('城市车辆目标跟踪性能分析报告');
end
function radar_chart(metrics)
% 绘制雷达图
% 计算各项指标的平均值
avg_metrics = mean(metrics, 1);
% 归一化到0-1范围
normalized_metrics = avg_metrics / max(avg_metrics);
% 绘制雷达图
angles = linspace(0, 2*pi, length(normalized_metrics)+1);
normalized_metrics = [normalized_metrics, normalized_metrics(1)];
polarplot(angles, normalized_metrics, 'b-o', 'LineWidth', 2, 'MarkerSize', 8);
thetalim([0, 360]);
rticks([0, 0.2, 0.4, 0.6, 0.8, 1]);
thetaticklabels({'X加速度', 'Y加速度', '总抖动', '', '', ''});
rlim([0, 1]);
end
三、测试脚本 (test_urban_tracking.m)
matlab
%% 城市车辆跟踪测试脚本
clear all; close all; clc;
fprintf('=== 城市车辆跟踪算法测试 ===\n\n');
%% 测试1: 不同检测器性能对比
fprintf('测试1: 检测器性能对比\n');
detectors = {'acf', 'hog', 'yolo'};
detector_results = struct();
for i = 1:length(detectors)
fprintf(' 测试 %s 检测器...\n', detectors{i});
% 创建测试配置
config = struct();
config.detector_type = detectors{i};
config.tracker_type = 'sort';
config.min_detection_confidence = 0.7;
config.iou_threshold = 0.3;
config.max_disappeared = 30;
config.show_trajectories = false;
config.save_results = false;
% 初始化检测器
detector = initialize_vehicle_detector(config.detector_type);
% 生成测试帧
test_frame = generate_urban_frame(1);
% 测试检测性能
tic;
[detections, scores] = detect_vehicles(test_frame, detector, config);
detection_time = toc;
detector_results.(detectors{i}).num_detections = size(detections, 1);
detector_results.(detectors{i}).detection_time = detection_time;
detector_results.(detectors{i}).avg_score = mean(scores);
end
% 可视化对比结果
figure('Position', [100, 100, 1200, 400]);
subplot(1, 3, 1);
bar([detector_results.acf.num_detections, detector_results.hog.num_detections, detector_results.yolo.num_detections]);
set(gca, 'XTickLabel', detectors);
ylabel('检测数量');
title('不同检测器检测数量对比');
grid on;
subplot(1, 3, 2);
bar([detector_results.acf.detection_time, detector_results.hog.detection_time, detector_results.yolo.detection_time]);
set(gca, 'XTickLabel', detectors);
ylabel('检测时间 (秒)');
title('不同检测器检测速度对比');
grid on;
subplot(1, 3, 3);
bar([detector_results.acf.avg_score, detector_results.hog.avg_score, detector_results.yolo.avg_score]);
set(gca, 'XTickLabel', detectors);
ylabel('平均置信度');
title('不同检测器置信度对比');
grid on;
%% 测试2: 不同跟踪器性能对比
fprintf('\n测试2: 跟踪器性能对比\n');
trackers = {'sort', 'deepsort', 'byte'};
tracker_results = struct();
for i = 1:length(trackers)
fprintf(' 测试 %s 跟踪器...\n', trackers{i});
% 创建测试配置
config = struct();
config.detector_type = 'acf';
config.tracker_type = trackers{i};
config.min_detection_confidence = 0.7;
config.iou_threshold = 0.3;
config.max_disappeared = 30;
config.show_trajectories = false;
config.save_results = false;
% 初始化跟踪器
tracker = initialize_multi_object_tracker(config);
% 生成测试数据
test_detections = [100, 100, 50, 30; 200, 150, 60, 40; 300, 200, 55, 35];
% 测试跟踪性能
tic;
for frame_idx = 1:10
[tracker, tracks] = update_tracker(tracker, test_detections, frame_idx, config);
end
tracking_time = toc;
tracker_results.(trackers{i}).num_tracks = length(tracker.tracks);
tracker_results.(trackers{i}).tracking_time = tracking_time;
tracker_results.(trackers{i}).avg_age = mean([tracker.tracks.age]);
end
% 可视化对比结果
figure('Position', [100, 100, 800, 400]);
subplot(1, 2, 1);
bar([tracker_results.sort.num_tracks, tracker_results.deepsort.num_tracks, tracker_results.byte.num_tracks]);
set(gca, 'XTickLabel', trackers);
ylabel('跟踪轨迹数量');
title('不同跟踪器轨迹数量对比');
grid on;
subplot(1, 2, 2);
bar([tracker_results.sort.tracking_time, tracker_results.deepsort.tracking_time, tracker_results.byte.tracking_time]);
set(gca, 'XTickLabel', trackers);
ylabel('跟踪时间 (秒)');
title('不同跟踪器处理时间对比');
grid on;
%% 测试3: 遮挡情况下的鲁棒性测试
fprintf('\n测试3: 遮挡情况下鲁棒性测试\n');
% 创建遮挡测试场景
config = struct();
config.detector_type = 'acf';
config.tracker_type = 'sort';
config.min_detection_confidence = 0.7;
config.iou_threshold = 0.3;
config.max_disappeared = 30;
config.show_trajectories = false;
config.save_results = false;
tracker = initialize_multi_object_tracker(config);
% 模拟遮挡场景
occlusion_frames = 20;
track_survival_rates = zeros(occlusion_frames, 1);
for occlusion_duration = 1:occlusion_frames
fprintf(' 测试遮挡持续时间: %d 帧...\n', occlusion_duration);
% 重置跟踪器
tracker = initialize_multi_object_tracker(config);
% 前10帧正常检测
for frame_idx = 1:10
test_detections = [100, 100, 50, 30];
[tracker, tracks] = update_tracker(tracker, test_detections, frame_idx, config);
end
% 遮挡期间无检测
for frame_idx = 11:10+occlusion_duration
[tracker, tracks] = update_tracker(tracker, [], frame_idx, config);
end
% 遮挡结束后恢复检测
for frame_idx = 11+occlusion_duration:20
test_detections = [100, 100, 50, 30];
[tracker, tracks] = update_tracker(tracker, test_detections, frame_idx, config);
end
% 检查轨迹是否存活
if ~isempty(tracker.tracks)
track_survival_rates(occlusion_duration) = 1;
else
track_survival_rates(occlusion_duration) = 0;
end
end
% 可视化遮挡鲁棒性结果
figure('Position', [100, 100, 600, 400]);
plot(1:occlusion_frames, track_survival_rates, 'ro-', 'LineWidth', 2, 'MarkerSize', 8);
xlabel('遮挡持续时间 (帧)');
ylabel('轨迹存活率');
title('遮挡情况下跟踪器鲁棒性');
ylim([0, 1.2]);
grid on;
fprintf('\n所有测试完成!\n');
参考代码 城市环境下车辆目标跟踪算法 www.youwenfan.com/contentcsu/63325.html
四、实际应用建议
4.1 参数调优指南
| 参数 | 建议值 | 调整原则 |
|---|---|---|
| IOU阈值 | 0.3-0.5 | 城市环境建议0.3,高速公路建议0.5 |
| 最大消失帧数 | 30-60 | 根据帧率调整,30fps时30帧=1秒 |
| 检测置信度 | 0.5-0.8 | 避免过高导致漏检,过低导致误检 |
| 卡尔曼滤波噪声 | 0.01-0.1 | 根据车辆运动剧烈程度调整 |
4.2 工程实现要点
- 实时性优化:使用GPU加速检测,简化跟踪算法
- 遮挡处理:实现轨迹预测和重识别机制
- 多摄像头融合:结合多个视角的跟踪结果
- 异常检测:识别跟踪失败的情况并进行恢复
4.3 适用场景
- 智能交通监控:十字路口、高速公路的车辆跟踪
- 自动驾驶:周边车辆的实时跟踪和预测
- 停车场管理:车位占用检测和车辆轨迹分析
- 交通流量统计:基于跟踪数据的交通流分析