Matlab基于光流场的交通汽车检测跟踪 光流:是空间运动物体在观察成像平面上的像素运动的瞬时速度。

张开发
2026/4/9 23:21:01 15 分钟阅读

分享文章

Matlab基于光流场的交通汽车检测跟踪 光流:是空间运动物体在观察成像平面上的像素运动的瞬时速度。
Matlab基于光流场的交通汽车检测跟踪光流是空间运动物体在观察成像平面上的像素运动的瞬时速度。光流法是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系从而计算出相邻帧之间物体的运动信息的一种方法。 代码设计思路背景建模可选但推荐虽然光流可以直接检测运动但为了减少树叶晃动、光影变化的干扰通常结合“背景减除法”来获取前景掩膜Mask。光流计算使用 Lucas-Kanade (LK) 光流算法 计算特征点的运动矢量。车辆检测与跟踪根据光流矢量的大小和方向筛选出车辆特征点并使用 vision.PointTracker 进行连续跟踪。边界框绘制根据跟踪到的特征点集计算最小外接矩形来框选车辆。 MATLAB 完整代码function OpticalFlowCarTracking()% 基于光流场的交通车辆检测与跟踪% 依赖工具箱Computer Vision Toolbox%% 1. 初始化视频读取对象 % 这里使用MATLAB自带的示例视频 visiontraffic.avi % 如果你有本地视频请修改为 your_video.mp4 videoFile visiontraffic.avi; if ~exist(videoFile, file) % 如果没有该视频尝试打开摄像头或提示错误 % videoSource VideoReader(your_video.mp4); error(未找到示例视频 visiontraffic.avi请确保视频文件存在或修改代码路径。); end videoReader VideoReader(videoFile); % 创建显示窗口 figure(Name, 光流车辆跟踪, NumberTitle, off); % 初始化光流显示对象 opticalFlowObj opticalFlowLK; % 初始化点跟踪器 (用于更稳定的跟踪) tracker vision.PointTracker(MaxBidirectionalError, 2); isFirstFrame true; prevFrame []; %% 2. 逐帧处理循环 while hasFrame(videoReader) % 读取当前帧 frame readFrame(videoReader); grayFrame rgb2gray(frame); % --- 步骤 A: 计算光流 --- if ~isempty(prevFrame) % 计算光流矢量 flow estimateFlow(opticalFlowObj, prevFrame, grayFrame); % 获取光流分量 u flow.Vx; % 水平方向速度 v flow.Vy; % 垂直方向速度 % --- 步骤 B: 运动区域分割 (简单阈值法) --- % 计算光流幅值 (速度大小) magnitude sqrt(u.^2 v.^2); % 设定阈值过滤掉静止背景如路面、天空 % 阈值需要根据视频实际情况调整 motionMask magnitude 1.5; % 形态学操作去噪连接邻近的运动区域 se strel(disk, 2); motionMask imopen(motionMask, se); motionMask imclose(motionMask, se); % --- 步骤 C: 特征点检测与跟踪 --- try if isFirstFrame % 第一帧检测特征点 points detectMinEigenFeatures(grayFrame); validPoints points.Location; % 初始化跟踪器 initialize(tracker, validPoints, grayFrame); else % 后续帧预测并更新点的位置 [validPoints, isFound] step(tracker, grayFrame); % 如果跟踪到的点太少重新检测 if sum(isFound) 0 x_coords 0 y_coords 20 height 20 rectangle(Position, [x_min, y_min, width, height], ... EdgeColor, g, LineWidth, 2); % 绘制质心 plot(mean(carPoints(:,1)), mean(carPoints(:,2)), r, MarkerSize, 10); end end % 绘制光流矢量图 (稀疏显示避免太乱) % 每隔10个像素显示一个矢量 stepSize 10; quiver(u(1:stepSize:end, 1:stepSize:end), v(1:stepSize:end, 1:stepSize:end), 1, w); end catch ME % 防止跟踪器出错导致程序崩溃 warning(跟踪器错误: %s, ME.message); isFirstFrame true; % 重置 end else % 第一帧处理 isFirstFrame false; end % 显示结果 imshow(frame); title(sprintf(帧数: %d, videoReader.CurrentTime * videoReader.FrameRate)); drawnow; % 更新上一帧 prevFrame grayFrame; endend 代码核心逻辑解析光流计算 (opticalFlowLK)我们使用了 Lucas-Kanade 算法。它假设光流在局部邻域内是恒定的。estimateFlow 函数会返回水平速度 V_x 和垂直速度 V_y。物理意义如果 V_x 和 V_y 接近 0说明该像素是静止背景如果幅值较大说明有物体运动。运动分割 (motionMask)代码通过 magnitude 1.5 创建了一个二值掩膜。这步非常关键因为它排除了静止的道路和建筑物只保留了“动”的东西车、行人、晃动的树。使用了形态学操作imopen, imclose来填补车辆内部的空洞使检测区域更连贯。特征点跟踪 (vision.PointTracker)单纯的光流只能计算相邻两帧的变化容易丢失目标。vision.PointTracker 内部集成了 KLT 算法能够跨越多帧跟踪角点Corner Features。代码逻辑是先找角点 - 跟踪 - 检查跟踪到的点是否在“运动掩膜”内 - 如果是则认为是车辆的一部分。边界框绘制最后代码收集所有被判定为“运动车辆”的特征点计算它们的最大/最小 X, Y 坐标从而画出一个绿色的矩形框。️ 运行前的准备视频文件代码默认读取 visiontraffic.avi。这是 MATLAB 官方示例视频。如果你的 MATLAB 版本较新可能需要下载该视频或将其替换为你电脑上的任意交通视频修改 videoFile 变量。工具箱确保安装了 Computer Vision Toolbox。这种效果的核心逻辑是检测当前帧中车辆的“角点”特征点。计算这些点在下一帧中的位置移动光流。在原图上绘制这些点和移动轨迹。以下是完整的 MATLAB 代码MATLAB 代码实现这段代码使用了 Lucas-Kanade 算法这是计算机视觉中最经典的光流算法。% 检查视频是否存在不存在则尝试使用摄像头或报错 if ~exist(videoFile, file) error(视频文件未找到请确保 viptraffic.avi 在当前目录下或修改代码路径。); end videoReader VideoReader(videoFile); % 创建图形窗口 hFig figure(Name, 交通场景光流场分析, NumberTitle, off); % 初始化变量 prevFrame []; % 上一帧灰度图 prevPoints []; % 上一帧的特征点 colors []; % 特征点的随机颜色用于轨迹可视化 pointTracker vision.PointTracker(MaxBidirectionalError, 2); % 点跟踪器对象 % 循环读取视频帧 while hasFrame(videoReader) frame readFrame(videoReader); currFrame rgb2gray(frame); % 转为灰度图用于计算 if isempty(prevFrame) % --- 第一帧初始化 --- % 使用 Shi-Tomasi 算法检测角点 prevPoints detectMinEigenFeatures(prevFrame, MinQuality, 0.05, FilterSize, 5); prevPoints prevPoints.Location; % 初始化跟踪器 initialize(pointTracker, prevPoints, prevFrame); % 生成随机颜色用于显示 colors rand(size(prevPoints, 1), 3); else % --- 后续帧处理 --- % 1. 执行点跟踪 [currPoints, validity] step(pointTracker, currFrame); % 2. 筛选有效的跟踪点 % validity 是一个逻辑向量标记哪些点跟踪成功了 prevPoints prevPoints(validity, :); currPoints currPoints(validity, :); colors colors(validity, :); % 3. 重新检测特征点为了维持点的数量防止车开走了点没了 numPointsToAdd 100 - size(prevPoints, 1); % 设定每帧维持约100个点 if numPointsToAdd 0 newPoints detectMinEigenFeatures(prevFrame, MinQuality, 0.1, FilterSize, 5); newPoints newPoints.Location; % 过滤掉离旧点太近的新点 if ~isempty(newPoints) % 简单的距离过滤可选优化 % 这里直接追加 prevPoints [prevPoints; newPoints(1:min(end,numPointsToAdd), :)]; colors [colors; rand(min(end,numPointsToAdd), 3)]; end end % 更新跟踪器状态 setLocations(pointTracker, prevPoints); % --- 绘图显示 --- imshow(frame); hold on; % 绘制光流线矢量场 % 使用 quiver 绘制箭头或者 plot 绘制连线 % 这里为了模仿你的图片效果使用连线 点 for i 1:size(currPoints, 1) % 画线 plot([prevPoints(i,1), currPoints(i,1)], [prevPoints(i,2), currPoints(i,2)], ... Color, colors(i,:), LineWidth, 1.5); % 画点 plot(currPoints(i,1), currPoints(i,2), Marker, ., Color, colors(i,:), MarkerSize, 8); end title(光流场标记图 (基于 Lucas-Kanade)); hold off; end % 更新上一帧数据 prevFrame currFrame; % 控制播放速度 drawnow; endend代码核心原理解析特征点检测 (detectMinEigenFeatures)代码首先寻找图像中纹理变化明显的地方比如车的角、车灯、车牌边缘。这就解释了为什么标记点主要集中在车辆上而不是在平坦的路面上。点跟踪 (vision.PointTracker)这是基于 Lucas-Kanade 算法的封装。它假设在一个小的局部窗口内像素的运动是一致的。它计算上一帧的点在当前帧移动到了哪里。轨迹绘制代码中的 plot 函数连接了 prevPoints上一帧位置和 currPoints当前帧位置从而形成了你图片中看到的“尾巴”或“矢量线”。如何运行确保你安装了 MATLAB 的 Computer Vision Toolbox。将上述代码保存为 TrafficFlowOpticalFlow.m。下载一个交通视频例如 viptraffic.avi放在同一目录下或者在代码中将 videoFile 变量改为你的视频路径。点击运行你将看到车辆被点云标记并带有运动轨迹。该方案通过特征点检测与跟踪实现了车辆运动轨迹的可视化分析。代码完整% 基于光流法的运动目标检测与跟踪 (完整复现代码)% 环境: MATLAB Computer Vision Toolbox% clc; clear; close all;%% 1. 初始化设置% 读取视频 (请确保视频文件存在或者使用摄像头)videoFile ‘viptraffic.avi’; % 示例视频名if ~exist(videoFile, ‘file’)error(‘视频文件未找到请确保视频在当前目录下。’);endhVideoSrc VideoReader(videoFile);% 获取视频属性cols hVideoSrc.Width;rows hVideoSrc.Height;% 创建 Computer Vision 系统对象% 光流计算对象 (Dense Optical Flow)hFlow vision.OpticalFlow(‘Method’, ‘Farneback’, …‘NoiseReductionThreshold’, 0.005, …‘PolynomialExpansionArea’, 15, …‘NumLevels’, 3, …‘AveragingWindowSize’, 5);% 计算运动幅度hMean2 vision.Statistics(‘Mean’);hMean1 vision.Statistics(‘Mean’);% 形态学操作对象hFilter vision.MedianFilter(‘Neighborhood’, [5 5]);hErode vision.MorphologicalEroder;hClose vision.MorphologicalCloser;% 连通域分析 (Blob Analysis)hBlob vision.BlobAnalysis(‘BoundingBoxOutputPort’, true, …‘AreaOutputPort’, true, …‘CentroidOutputPort’, false, …‘MinimumBlobArea’, 200);% 视频播放器 (可选用于查看结果)hVideoPlayer vision.VideoPlayer(‘Name’, ‘检测结果’, ‘Position’, [100 100 col2 rows2]);%% 2. 主循环 (对应图片中的 While 循环部分)frameIdx 0;while hasFrame(hVideoSrc)frameIdx frameIdx 1;frame readFrame(hVideoSrc);% 1. 预处理转灰度 gray rgb2gray(frame); % 2. 计算光流 flow step(hFlow, gray); % 计算光流场 [Vx, Vy] % 3. 网格化采样 (为了加速计算不计算每个像素) % 对应图片 47-49 行 [xpos, ypos] meshgrid(1:5:cols, 1:5:rows); xpos xpos(:); ypos ypos(:); locs sub2ind([rows, cols], ypos, xpos); % 线性索引 % 4. 构建运动矢量线 % 对应图片 56 行绘制光流矢量线 scaleFactor 20; % 放大系数方便观察 lines [xpos, ypos, ... xpos scaleFactor * real(flow(locs)), ... ypos scaleFactor * imag(flow(locs))]; % 5. 计算运动强度 % 对应图片 58 行Magnitude Vx^2 Vy^2 magnitude flow .* conj(flow); % 复数模的平方 % 6. 自适应阈值分割 % 对应图片 60 行 meanMag step(hMean2, step(hMean1, magnitude)); % 全局平均运动能量 threshold 0.5 * meanMag; carobj magnitude threshold; % 7. 图像处理 (去噪与形态学) % 对应图片 61 行 carobj step(hFilter, carobj); % 中值滤波 carobj step(hClose, step(hErode, carobj)); % 先腐蚀后闭运算去除噪点并连接区域 % 8. 连通域分析 (Blob Analysis) % 对应图片 62 行 [area, bbox] step(hBlob, carobj); % 9. 目标筛选逻辑 (对应图片 64-69 行) grow 22; % 边界框扩大系数 idx bbox(:,1) grow; % 筛选x坐标大于22 (去除左侧边缘干扰) ratio zeros(length(idx), 1); if any(idx) % 计算长宽比: Area / (Width * Height) % 注意bbox 格式通常是 [x, y, width, height] ratio(idx) single(area(idx,1)) ./ (single(bbox(idx,3)) .* single(bbox(idx,4))); end flag ratio 0.4; % 筛选长宽比大于0.4 (排除细长噪点) count int32(sum(flag)); % 统计检测到的车辆数 % 获取最终的边界框 if count 0 bbox_final bbox(idx, :); bbox_final bbox_final(flag, :); else bbox_final []; end % 10. 显示结果 (在原图上画框) outFrame frame; if ~isempty(bbox_final) outFrame insertShape(outFrame, Rectangle, bbox_final, Color, green, LineWidth, 3); end % 显示帧率或数量 outFrame insertText(outFrame, [10 10], [Vehicles: num2str(count)], ... BoxColor, white, FontSize, 15); step(hVideoPlayer, outFrame); % 暂停控制 pause(0.01);end% 释放资源release(hVideoPlayer);关键代码解析对应图片行号Line 47-50 (网格采样):meshgrid(1:5:cols, 1:5:rows): 这里没有对全图每个像素计算光流而是每隔 5 个像素取一个点。这大大减少了计算量是实时处理的关键。sub2ind: 将二维坐标 (x, y) 转换为线性索引以便直接从 flow 矩阵中提取数据。Line 58 (幅度计算):flow .* conj(flow): 光流 flow 通常是复数形式实部为 V_x虚部为 V_y。公式为 |V|^2 V_x^2 V_y^2。在 MATLAB 中z .* conj(z) 等价于 abs(z).^2但计算速度更快。Line 60 (自适应阈值):0.5 * step(hMean2, …)设定阈值为平均运动强度的 0.5 倍。这是一种动态阈值法能适应不同光照和交通密度的场景。Line 64-68 (长宽比筛选):代码通过 area ./ (width * height) 计算填充率或紧凑度。ratio 0.4用于剔除那些形状极其细长或稀疏的噪点保留接近矩形或块状的车辆目标。

更多文章