城市环境下车辆目标跟踪算法 MATLAB 实现

一、算法架构设计

复制代码
                    城市车辆目标跟踪系统                   

  视频输入层   │  目标检测层   │  多目标跟踪层   │  轨迹管理   
               │               │                 │             
 • 城市街景   │  • 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 工程实现要点

  1. 实时性优化:使用GPU加速检测,简化跟踪算法
  2. 遮挡处理:实现轨迹预测和重识别机制
  3. 多摄像头融合:结合多个视角的跟踪结果
  4. 异常检测:识别跟踪失败的情况并进行恢复

4.3 适用场景

  1. 智能交通监控:十字路口、高速公路的车辆跟踪
  2. 自动驾驶:周边车辆的实时跟踪和预测
  3. 停车场管理:车位占用检测和车辆轨迹分析
  4. 交通流量统计:基于跟踪数据的交通流分析
相关推荐
tryCbest1 小时前
软考 - 排序算法
算法·排序算法
AKA__Zas1 小时前
芝士算法(双指针篇 1.0)
java·算法·学习方法
吃着火锅x唱着歌1 小时前
LeetCode 726.原子的数量
linux·算法·leetcode
机器学习之心1 小时前
轴承剩余寿命预测 | 基于BP神经网络的轴承剩余寿命预测MATLAB实现!
人工智能·神经网络·matlab·轴承剩余寿命预测
君义_noip1 小时前
CSP-S 2025 提高级 第一轮(初赛) 阅读程序(3)
c++·算法·信息学奥赛·csp-s 初赛
玛卡巴卡ldf1 小时前
【LeetCode 手撕算法】(栈)有效括号、最小栈、字符串解码、每日温度、柱状图最大矩形
java·数据结构·算法·leetcode·力扣
happyprince1 小时前
05-FlagEmbedding 评估模块详解
算法
wuweijianlove1 小时前
算法优化的多目标平衡与性能建模研究的技术7
算法
_深海凉_1 小时前
LeetCode热题100-两两交换链表中的节点
算法·leetcode·链表