当前位置: 首页 > news >正文

基于帧间差分法的运动目标检测 MATLAB 实现

使用 MATLAB 实现帧间差分法运动目标检测的完整代码,包含详细注释和可视化界面。

function motion_detection_fd()% 基于帧间差分法的运动目标检测 MATLAB 实现% 创建主界面fig = figure('Name', '帧间差分法运动检测', 'NumberTitle', 'off', ...'Position', [100, 100, 1200, 700], 'MenuBar', 'none');% 创建控制面板controlPanel = uipanel('Title', '控制面板', 'Position', [0.02, 0.02, 0.3, 0.96], ...'BackgroundColor', [0.9, 0.9, 0.9]);% 创建参数控件uicontrol(controlPanel, 'Style', 'text', 'String', '阈值:', ...'Position', [20, 550, 80, 20], 'HorizontalAlignment', 'left');thresholdSlider = uicontrol(controlPanel, 'Style', 'slider', ...'Min', 1, 'Max', 100, 'Value', 30, ...'Position', [100, 550, 150, 20]);thresholdText = uicontrol(controlPanel, 'Style', 'text', ...'String', '30', 'Position', [260, 550, 40, 20]);uicontrol(controlPanel, 'Style', 'text', 'String', '最小区域:', ...'Position', [20, 500, 80, 20], 'HorizontalAlignment', 'left');minAreaSlider = uicontrol(controlPanel, 'Style', 'slider', ...'Min', 10, 'Max', 2000, 'Value', 500, ...'Position', [100, 500, 150, 20]);minAreaText = uicontrol(controlPanel, 'Style', 'text', ...'String', '500', 'Position', [260, 500, 40, 20]);uicontrol(controlPanel, 'Style', 'text', 'String', '形态学操作:', ...'Position', [20, 450, 80, 20], 'HorizontalAlignment', 'left');morphOps = {'无', '开运算', '闭运算', '开闭运算'};morphPopup = uicontrol(controlPanel, 'Style', 'popupmenu', ...'String', morphOps, 'Value', 4, ...'Position', [100, 450, 150, 20]);uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '加载视频', ...'Position', [20, 400, 100, 30], 'Callback', @loadVideo);uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '开始检测', ...'Position', [130, 400, 100, 30], 'Callback', @startDetection);uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '暂停', ...'Position', [20, 350, 100, 30], 'Callback', @pauseDetection);uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '停止', ...'Position', [130, 350, 100, 30], 'Callback', @stopDetection);uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '保存结果', ...'Position', [20, 300, 210, 30], 'Callback', @saveResults);% 创建结果显示区域resultPanel = uipanel('Title', '检测结果', 'Position', [0.34, 0.52, 0.64, 0.46], ...'BackgroundColor', 'white');ax1 = subplot(2, 3, 1, 'Parent', resultPanel);title(ax1, '原始帧');ax2 = subplot(2, 3, 2, 'Parent', resultPanel);title(ax2, '灰度图像');ax3 = subplot(2, 3, 3, 'Parent', resultPanel);title(ax3, '帧间差分');ax4 = subplot(2, 3, 4, 'Parent', resultPanel);title(ax4, '二值图像');ax5 = subplot(2, 3, 5, 'Parent', resultPanel);title(ax5, '形态学处理');ax6 = subplot(2, 3, 6, 'Parent', resultPanel);title(ax6, '检测结果');% 创建状态栏statusBar = uicontrol('Style', 'text', 'String', '就绪', ...'Position', [0.34, 0.02, 0.64, 0.04], ...'HorizontalAlignment', 'left', ...'BackgroundColor', [0.8, 0.8, 0.8]);% 初始化变量videoObj = [];currentFrame = [];prevFrame = [];isPlaying = false;timerObj = [];results = struct('original', {}, 'gray', {}, 'diff', {}, ...'thresh', {}, 'morph', {}, 'result', {});frameIndex = 0;% 加载视频回调函数function loadVideo(~, ~)[filename, pathname] = uigetfile({'*.avi;*.mp4;*.mov', '视频文件 (*.avi, *.mp4, *.mov)'}, ...'选择视频文件');if isequal(filename, 0)return;endvideoPath = fullfile(pathname, filename);tryvideoObj = VideoReader(videoPath);set(statusBar, 'String', ['已加载视频: ' filename]);% 读取第一帧prevFrame = readFrame(videoObj);frameIndex = 1;% 显示第一帧axes(ax1);imshow(prevFrame);title(ax1, '原始帧');axes(ax2);grayImg = rgb2gray(prevFrame);imshow(grayImg, []);title(ax2, '灰度图像');catch MEerrordlg(['无法读取视频文件: ' ME.message], '错误');endend% 开始检测回调函数function startDetection(~, ~)if isempty(videoObj)errordlg('请先加载视频文件', '错误');return;endif isPlayingreturn;endisPlaying = true;set(statusBar, 'String', '检测中...');% 获取参数值threshold = get(thresholdSlider, 'Value');minArea = get(minAreaSlider, 'Value');morphOp = get(morphPopup, 'Value');% 创建定时器处理视频帧timerObj = timer('ExecutionMode', 'fixedRate', 'Period', 0.05, ...'TimerFcn', @processFrame);start(timerObj);end% 暂停检测回调函数function pauseDetection(~, ~)if isPlayingisPlaying = false;if ~isempty(timerObj) && isvalid(timerObj)stop(timerObj);endset(statusBar, 'String', '已暂停');endend% 停止检测回调函数function stopDetection(~, ~)isPlaying = false;if ~isempty(timerObj) && isvalid(timerObj)stop(timerObj);delete(timerObj);timerObj = [];endframeIndex = 0;results = struct('original', {}, 'gray', {}, 'diff', {}, ...'thresh', {}, 'morph', {}, 'result', {});set(statusBar, 'String', '已停止');end% 保存结果回调函数function saveResults(~, ~)if isempty(results)errordlg('没有可保存的结果', '错误');return;end[filename, pathname] = uiputfile('motion_detection_results.avi', '保存结果视频');if isequal(filename, 0)return;endoutputPath = fullfile(pathname, filename);trywriterObj = VideoWriter(outputPath, 'Motion JPEG AVI');writerObj.FrameRate = videoObj.FrameRate;open(writerObj);for i = 1:length(results)writeVideo(writerObj, results(i).result);endclose(writerObj);set(statusBar, 'String', ['结果已保存到: ' outputPath]);catch MEerrordlg(['保存失败: ' ME.message], '错误');endend% 处理视频帧function processFrame(~, ~)if ~hasFrame(videoObj)stopDetection();return;end% 读取当前帧currentFrame = readFrame(videoObj);frameIndex = frameIndex + 1;% 获取参数值threshold = get(thresholdSlider, 'Value');minArea = get(minAreaSlider, 'Value');morphOp = get(morphPopup, 'Value');% 转换为灰度图像grayPrev = rgb2gray(prevFrame);grayCurr = rgb2gray(currentFrame);% 计算帧间差分diffImg = imabsdiff(grayCurr, grayPrev);% 二值化处理threshImg = imbinarize(diffImg, threshold/255);% 形态学处理se = strel('rectangle', [5, 5]);switch morphOpcase 1 % 无morphImg = threshImg;case 2 % 开运算morphImg = imopen(threshImg, se);case 3 % 闭运算morphImg = imclose(threshImg, se);case 4 % 开闭运算temp = imopen(threshImg, se);morphImg = imclose(temp, se);end% 标记运动目标labeledImg = bwlabel(morphImg);stats = regionprops(labeledImg, 'BoundingBox', 'Area');% 在原图上绘制检测结果resultImg = currentFrame;for i = 1:length(stats)if stats(i).Area > minAreabbox = stats(i).BoundingBox;resultImg = insertShape(resultImg, 'Rectangle', bbox, ...'LineWidth', 2, 'Color', 'green');resultImg = insertText(resultImg, [bbox(1), bbox(2)-20], ...'运动目标', 'FontSize', 12, ...'BoxColor', 'yellow', 'TextColor', 'black');endend% 更新结果显示axes(ax1);imshow(currentFrame);title(ax1, sprintf('原始帧 (%d/%d)', frameIndex, videoObj.NumFrames));axes(ax2);imshow(grayCurr, []);title(ax2, '灰度图像');axes(ax3);imshow(diffImg, []);title(ax3, '帧间差分');axes(ax4);imshow(threshImg);title(ax4, '二值图像');axes(ax5);imshow(morphImg);title(ax5, '形态学处理');axes(ax6);imshow(resultImg);title(ax6, '检测结果');% 保存结果results(end+1) = struct('original', currentFrame, ...'gray', grayCurr, ...'diff', diffImg, ...'thresh', threshImg, ...'morph', morphImg, ...'result', resultImg);% 更新前一帧prevFrame = currentFrame;% 更新状态栏set(statusBar, 'String', sprintf('处理中: 帧 %d/%d, 检测到 %d 个目标', ...frameIndex, videoObj.NumFrames, length(stats)));end% 滑块回调函数function thresholdSliderCallback(src, ~)value = round(get(src, 'Value'));set(thresholdText, 'String', num2str(value));endset(thresholdSlider, 'Callback', @thresholdSliderCallback);function minAreaSliderCallback(src, ~)value = round(get(src, 'Value'));set(minAreaText, 'String', num2str(value));endset(minAreaSlider, 'Callback', @minAreaSliderCallback);
end

使用说明

功能特点

  1. 完整的GUI界面:提供直观的用户界面,包含所有必要的控制选项
  2. 参数可调: 阈值:控制运动检测的灵敏度(1-100) 最小区域:过滤小面积噪声(10-2000像素) 形态学操作:选择不同的后处理方法(无、开运算、闭运算、开闭运算)
  3. 实时显示:同时显示原始帧、灰度图像、帧间差分、二值图像、形态学处理结果和最终检测结果
  4. 视频处理:支持加载和处理AVI、MP4、MOV等常见视频格式
  5. 结果保存:可将检测结果保存为视频文件

使用步骤

  1. 运行程序:motion_detection_fd()
  2. 点击"加载视频"按钮,选择要处理的视频文件
  3. 调整参数: 阈值:根据场景光照和运动速度调整 最小区域:根据目标大小调整 形态学操作:通常选择"开闭运算"效果最佳
  4. 点击"开始检测"按钮开始处理视频
  5. 处理过程中可随时暂停或停止
  6. 处理完成后,点击"保存结果"将检测结果保存为视频文件

算法原理

  1. 帧间差分:计算相邻两帧图像的绝对差值

    \(D(x,y)=∣I_{k+1}(x,y)−I_k(x,y)∣\)

  2. 二值化:设定阈值T,将差分图像转换为二值图像

    \(B_t(x, y) = \begin{cases} 255, & \text{if } |I_t(x, y) - I_{t-1}(x, y)| > T \\ 0, & \text{otherwise} \end{cases}\)

  3. 形态学处理:使用开运算和闭运算去除噪声和填充空洞

  4. 目标标记:标记连通区域,过滤小面积区域,绘制边界框

参数调整建议

  1. 阈值: 低光照场景:降低阈值(10-20) 高对比度场景:提高阈值(30-50) 快速运动目标:提高阈值减少噪声
  2. 最小区域: 小型目标(行人):100-300像素 中型目标(车辆):500-1000像素 大型目标(卡车):1000-2000像素
  3. 形态学操作: 噪声较多:使用开运算 目标有空洞:使用闭运算 一般情况:使用开闭运算

参考代码 基于帧间差分法的运动目标检测 www.3dddown.com/cnb/83299.html

扩展功能

如需进一步增强检测效果,可考虑:

  1. 添加背景建模(如高斯混合模型)
  2. 实现三帧差分法
  3. 结合光流法进行运动估计
  4. 添加目标跟踪功能
  5. 集成深度学习目标检测器
http://www.jsqmd.com/news/777431/

相关文章:

  • Qt 信号和槽的工作原理
  • 大模型算力浪费诊断手册(SITS2026闭门报告首次公开)
  • 使用Taotoken API Key管理功能实现团队权限与审计
  • 2026年新疆医疗污水处理一体化设备深度横评与选购指南 - 精选优质企业推荐官
  • 医疗大模型过审FDA认证全过程(附17份合规文档模板):2026奇点大会唯一公开披露案例
  • 3步零基础搭建象棋AI助手:VinXiangQi深度学习识别实战指南
  • 在Mac上原生运行iOS游戏:PlayCover终极指南与性能优化技巧
  • 2026年主数据系统厂商推荐,数据底座厂家与管理公司怎么选 - 品牌2026
  • AI助手工程化实战:从LLM对话到智能体架构的完整开发指南
  • 终极免费JSON查看器:1.4GB超大文件秒开指南
  • 低代码平台集成灾难现场还原(SITS大会故障复盘工作坊原始录像文字精要版)
  • OpenClaw快速接入DeepSeek全攻略
  • Auralith开源音频幻觉框架:从Shepard Tone到HRTF的听觉魔法实现
  • 基于Webhook的M365事件驱动自动化:从轮询到推送的成本优化实践
  • 保姆级教程:在RK3588开发板上搞定OV50C40和OV13855双摄配置(含DTS详解)
  • 超完整的招标投标流程和步骤,堪称工具书!
  • 我花一周把《纳瓦尔宝典》拆了,拆完后悔没早点读
  • LTspice基本功能之瞬态分析
  • 【研报A98】人形机器人丝杠的理想工艺:冷锻工艺精度C3+成本降30%
  • 动态镜像映射全域要素,物理智能驱动精准决策
  • 超详细的玻璃幕墙施工步骤,幕墙设计师必看!
  • CE-CF 锂电池模组均衡维护仪生产厂家 - 勇士快跑
  • 数字视频处理:色彩空间转换与FPGA实现
  • 从Silicon 60看2017年半导体创业:架构创新与开放硬件的崛起
  • 输入法词库转换终极指南:如何轻松迁移20+输入法个人词库
  • 2026最新防脱发洗发水生产厂家推荐!权威榜单发布,实力靠谱公司供应商放心选 - 十大品牌榜
  • 告别虚拟机!用PlayOnLinux在Ubuntu 22.04上安装Office 2016的保姆级教程
  • ncmdump终极指南:一键解锁网易云音乐NCM加密文件
  • 如何用开源3D重建软件Meshroom将普通照片变成专业3D模型
  • 洽洽集团数字化赋能:文沥助力渠道精耕项目 - 麦麦唛