移动目标检测的几种常用方法和代码实现

移动目标检测的几种常用方法和代码实现

      • 帧差法(Frame Difference Method)
      • 持续帧差法(Continuous Frame Difference Method)
      • 总结
      • 背景减法
      • 自适应背景减法
      • 总结

帧差法和持续帧差法都是通过分析视频帧之间的差异来检测场景中的运动对象的方法,但它们在实现和使用场景上有所不同。下面是两种方法的主要区别:

帧差法(Frame Difference Method)

  • 基本原理:帧差法通过比较连续两帧之间的像素差异来检测运动。具体来说,它计算当前帧和前一帧之间的差异。
  • 简单直接:这种方法实现简单,对于实时应用非常有效。
  • 运动检测:能够有效检测运动区域,但对于快速运动或小区域变化可能不够敏感。
  • 局限性:对于背景中的小幅度变化(如光照变化)可能较为敏感,容易产生误检。此外,如果运动对象在连续两帧内移动距离不大,帧差法可能无法准确检测到运动。
import cv2def frame_difference_motion_detection(video_path):# 打开视频文件cap = cv2.VideoCapture(video_path)if not cap.isOpened():print("Error opening video stream or file")return# 读取第一帧ret, prev_frame = cap.read()if not ret:print("Failed to read the video")cap.release()return# 将第一帧转换为灰度图prev_frame_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)while True:# 读取下一帧ret, frame = cap.read()if not ret:break# 将当前帧转换为灰度图frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 计算当前帧和前一帧的差异frame_diff = cv2.absdiff(frame_gray, prev_frame_gray)# 应用阈值化来获取前景_, thresh = cv2.threshold(frame_diff, 25, 255, cv2.THRESH_BINARY)# 腐蚀操作减少噪声erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))eroded = cv2.erode(thresh, erode_kernel, iterations=2)# 膨胀操作恢复对象大小dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 8))dilated = cv2.dilate(eroded, dilate_kernel, iterations=2)# 查找轮廓contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 在原始帧上绘制轮廓for contour in contours:if cv2.contourArea(contour) > 500:  # 过滤掉小轮廓x, y, w, h = cv2.boundingRect(contour)cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 显示结果cv2.imshow('Frame', frame)cv2.imshow('Motion Detection', dilated)if cv2.waitKey(30) & 0xFF == ord('q'):break# 更新前一帧prev_frame_gray = frame_graycap.release()cv2.destroyAllWindows()# 使用示例
video_path = 'your_video_path_here.mp4'  # 替换为您的视频文件路径
frame_difference_motion_detection(video_path)

持续帧差法(Continuous Frame Difference Method)

  • 基本原理:持续帧差法不仅比较连续的两帧,而且会持续跟踪帧与帧之间的差异,并可能采用多帧差分的方法来提高检测的稳定性和准确性。
  • 改进的运动检测:通过对多帧进行差分,持续帧差法可以更好地处理背景噪声和光照变化,减少误检,同时增强对持续运动的检测能力。
  • 应用场景:更适合于需要较高准确度和稳定性的应用场景,如在复杂环境下的运动检测。
  • 计算成本:与简单的帧差法相比,持续帧差法在处理多帧数据时可能需要更高的计算资源。
import cv2
import numpy as npdef persistent_frame_difference(video_path):# 打开视频文件cap = cv2.VideoCapture(video_path)if not cap.isOpened():print("Error opening video stream or file")return# 读取第一帧,并初始化背景帧为第一帧ret, prev_frame = cap.read()if not ret:print("Failed to read the video")cap.release()returnprev_frame_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)# 初始化持续差分图像persistent_diff = np.zeros_like(prev_frame_gray, dtype=np.float32)while True:# 读取下一帧ret, frame = cap.read()if not ret:break# 将当前帧转换为灰度图frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 计算当前帧和前一帧的差异frame_diff = cv2.absdiff(frame_gray, prev_frame_gray).astype(np.float32)# 更新持续差分图像decay_factor = 0.9  # 衰减因子,用于调整旧差分值的衰减速率persistent_diff = cv2.max(persistent_diff * decay_factor, frame_diff)# 将持续差分图像转换为二值图像_, persistent_thresh = cv2.threshold(persistent_diff, 25, 255, cv2.THRESH_BINARY)# 腐蚀和膨胀操作改善结果kernel = np.ones((5, 5), np.uint8)persistent_thresh = cv2.erode(persistent_thresh, kernel, iterations=1)persistent_thresh = cv2.dilate(persistent_thresh, kernel, iterations=2)# 查找轮廓并绘制矩形框contours, _ = cv2.findContours(persistent_thresh.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for contour in contours:if cv2.contourArea(contour) > 500:  # 过滤小轮廓x, y, w, h = cv2.boundingRect(contour)cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 显示结果cv2.imshow('Frame', frame)cv2.imshow('Persistent Frame Difference', persistent_thresh)if cv2.waitKey(30) & 0xFF == ord('q'):break# 更新前一帧prev_frame_gray = frame_graycap.release()cv2.destroyAllWindows()# 使用示例
video_path = 'your_video_path_here.mp4'  # 替换为您的视频文件路径
persistent_frame_difference(video_path)

persistent_diff其实也就是保存了之前2帧的差或者当前2帧的差而已。如果在更新persistent_diff时,当前帧与前一帧的差异总是大于persistent_diff中经过衰减的值,那么persistent_diff将主要反映最近的帧差异,而不是累积较长时间内的历史差异。这种情况通常发生在视频中有持续且显著的运动时,使得每次的帧差都足够大,以至于经衰减处理后的persistent_diff还是小于最新的帧差。

在这种情况下,persistent_diff确实可能更多地反映近期的运动情况,而不是长时间内的累积运动历史。但是,这并不完全是一个缺点,因为:

  1. 动态适应性:这种更新机制使得persistent_diff能够动态地适应视频中的运动情况,即使在有强烈运动的场景中也能保持对运动的敏感性。
  2. 运动强度的反映:通过这种方式,persistent_diff不仅保留了运动信息,还在一定程度上反映了运动的强度。如果某个区域持续出现在persistent_diff中,这意味着该区域有持续的或重复的运动。

为了确保persistent_diff能够更好地反映一段时间内的运动历史,可以考虑以下策略:

  • 调整衰减因子:通过调整衰减因子(decay_factor),可以控制历史运动信息在persistent_diff中保留的时长。较低的衰减因子会导致历史信息更快地衰减,而较高的衰减因子可以让这些信息保留更长时间。
  • 考虑使用阈值调整:根据场景的特定需求,可以适当调整用于生成二值图像的阈值,以更好地区分重要的运动信息和背景噪声。
  • 引入历史帧的加权:在某些实现中,还可以考虑对不同时间点的帧差进行加权,以赋予不同时间的运动不同的重要性。

通过这样的调整,可以更精细地控制persistent_diff反映的运动信息,既能捕捉到持续的运动,也能在一定程度上保留运动的历史轨迹。

总结

总的来说,帧差法更适用于计算资源受限或对实时性要求较高的场景,它能够提供快速但相对粗糙的运动检测。而持续帧差法通过对多帧进行分析,能够提供更稳定和准确的运动检测结果,更适合于背景条件复杂或需要更细致运动检测的应用。选择哪种方法取决于具体的应用需求、可用的计算资源以及环境条件。

背景减法(Background Subtraction)和自适应背景减法(Adaptive Background Subtraction)是视频分析中用于检测移动对象的两种常见方法。它们都试图通过比较当前帧和背景模型来识别前景对象,即移动中的对象。然而,它们在处理背景更新时采用了不同的策略,下面是它们的主要区别:

背景减法

  • 静态背景假设:背景减法通常基于一个静态的背景模型,假设背景在视频序列中保持不变或变化很小。
  • 简单和直接:这种方法首先从视频中提取一个或多个背景帧作为背景模型,然后将后续帧与此背景模型进行比较,通过差分得到前景掩模。
  • 局限性:在面对复杂环境时(如动态背景、光照变化、摄像机抖动等),这种方法的效果往往不理想,因为它不能自动适应背景的变化。
import cv2def simple_background_subtraction(video_path, background_frame):# 打开视频文件cap = cv2.VideoCapture(video_path)if not cap.isOpened():print("Error opening video stream or file")return# 将背景帧转换为灰度图background_gray = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)while cap.isOpened():ret, frame = cap.read()if not ret:break# 将当前帧转换为灰度图frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 计算当前帧和背景帧的差异frame_diff = cv2.absdiff(frame_gray, background_gray)# 应用阈值化来获取前景_, thresh = cv2.threshold(frame_diff, 30, 255, cv2.THRESH_BINARY)# 显示结果cv2.imshow('Frame', frame)cv2.imshow('Foreground', thresh)if cv2.waitKey(30) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()# 使用示例
video_path = 'your_video_path_here.mp4'  # 替换为您的视频文件路径
background_frame = cv2.imread('your_background_frame_path_here.jpg')  # 替换为您的背景帧图片路径
simple_background_subtraction(video_path, background_frame)

自适应背景减法

  • 动态背景适应:自适应背景减法能够根据每个新帧动态更新背景模型,以适应环境中的变化,如光照变化、摄像机移动等。
  • 更复杂的算法:采用如高斯混合模型(Gaussian Mixture Model, GMM)等更复杂的算法来维护背景模型,允许背景中存在多种模式。
  • 更好的适应性:由于背景模型是动态更新的,自适应背景减法在处理动态背景、光照变化、长时间的场景变化等方面更加有效。
import cv2def detect_motion_with_adaptive_background_subtraction(video_path):# 创建背景减法器background_subtractor = cv2.createBackgroundSubtractorMOG2()# 打开视频文件cap = cv2.VideoCapture(video_path)if not cap.isOpened():print("Error opening video stream or file")returnwhile cap.isOpened():ret, frame = cap.read()if not ret:break# 应用背景减法fg_mask = background_subtractor.apply(frame)# 腐蚀操作减少噪声erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))fg_mask_eroded = cv2.erode(fg_mask, erode_kernel, iterations=2)# 膨胀操作恢复对象大小dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 8))fg_mask_dilated = cv2.dilate(fg_mask_eroded, dilate_kernel, iterations=2)# 查找轮廓contours, _ = cv2.findContours(fg_mask_dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 在原始帧上绘制轮廓for contour in contours:if cv2.contourArea(contour) > 500:  # 过滤掉小轮廓x, y, w, h = cv2.boundingRect(contour)cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 显示结果cv2.imshow('Frame', frame)cv2.imshow('Foreground Mask', fg_mask_dilated)if cv2.waitKey(30) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()# 使用示例
video_path = 'your_video_path_here.mp4'  # 将此路径替换为你的视频文件路径
detect_motion_with_adaptive_background_subtraction(video_path)

总结

  • 背景减法适合于背景几乎不变的简单场景,实现起来相对简单,但在动态环境下容易失败。
  • 自适应背景减法适用于更广泛的场景,尤其是背景、光照等持续变化的环境。尽管算法更复杂、计算成本更高,但它能够提供更准确的移动对象检测。

选择哪种方法取决于应用场景的具体需求,包括环境的复杂度、实时性要求、以及可接受的计算负担。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/726714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1.5如何缓解图像分类任务中训练数据不足带来的问题?

1.5 图像数据不足时的处理方法 场景描述 在机器学习中,绝大部分模型都需要大量的数据进行训练和学习(包括有监督学习和无监督学习),然而在实际应用中经常会遇到训练数据不足的问题。 比如图像分类,作为计算机视觉最基本的任务之一&#xff0…

生成 Linux/ubuntu/Debian 上已安装软件包的列表

你可以在终端中使用以下命令生成已安装软件包的列表: 列出所有已安装的软件包: dpkg --get-selections要将列表保存到文件中: dpkg -l > installed_packages_detailed.txt这将在当前目录中创建一个名为“installed_packages_detailed.txt”…

高效提升控制效率 | 基于ACM32 MCU的LED灯箱控制器方案

LED灯箱上各种文字、图案有序跳跃、交替辉映,产生强烈的视觉冲击力,被广泛应用于商场、美容美发、宾馆、娱乐场所等地方。 锁存器的工作原理 在LED和数码管显示方面,要维持一个数据的显示,往往要持续的快速的刷新。尤其是在四段八…

Python算法100例-3.6 自守数

1.问题描述2.问题分析3.算法设计4.求给定数的位数5.分离给定数中的最后几位6.确定程序框架7.完整的程序 1.问题描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如, 5 2 25 , 2 5 2 625 , 7 6 2 5776 &#xff0c…

java基础-锁之volatilesynchronized

文章目录 volatilevolatile内存语义volatile的可见性volatile无法保证原子性volatile禁止重排优化硬件层的内存屏障volatile内存语义的实现下面是基于保守策略的JMM内存屏障插入策略。下面是保守策略下,volatile写插入内存屏障后生成的指令序列示意图下图是在保守策…

Mac下java环境搭建

JDK 教程:MAC安装JDK及环境变量配置-CSDN博客 建议JDK7和JDK8都装上,因为一些老项目是用JDK7开发,使用JDK8编译时报错。(若没有老项目,直接安装jdk8) 若配置环境变量时找不到JDK的安装路径,有两种方式: 方式一、mac默认位置为:/Library/Java/JavaVirtualMachines/…

Android APP性能指标(二)

文章目录 一、响应时间1.1 数据获取1.2 响应时间指标测试点1.3 启动速度测试点1.4 响应时间测试解决方法 二、流量2.1 数据获取2.2 流量测试关注点2.3 测试标准 三、电量3.1 连接手机3.2 数据获取3.3 获取APP的UID3.3 重置电池数据收集数据3.4 电量指标测试 四、温度五、性能测…

打包系统待优化点

Base.Widget.AppCompat.ActivityChooserView中相关资源重复 D:\channelPackage\ToolConfigPath\games\dcpPro\100081\mumu\tempRes\values\attrs.xml:1171: error: duplicate value for resource attr/displayOptions with config . D:\channelPackage\ToolConfigPath\games\d…

linux系统nginx常用命令

查nginx位置 find / -name nginx nginx目录:/usr/local/ 查看nginx进程号 ps -ef |grep nginx 停止进程 kill 2072 启动 ./sbin/nginx /usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf 启动并校验校验配置文件 ./sbin/nginx -t 看到如下显…

【C++精简版回顾】19.异常处理

1.throw抛出问题 int print(int a,int b) {if (b 0)throw b;return a / b; } 2.try与catch解决问题 try {print(2, 0); } catch (int b) {cout << "竟然是&#xff1a;"<<b<<endl; } 结果&#xff1a; 补充1&#xff1a;可以抛出字符串等 1.throw…

day13_微服务监控Nginx(微服务集成SBA)

文章目录 1 微服务系统监控1.1 监控系统的意义1.2 SBA监控方案1.3 SBA实战1.3.1 创建SBA服务端1.3.2 微服务集成SBA 1.4 微服务集成logback1.5 配置邮件告警 2 Nginx2.1 Nginx简介2.2 下载和安装2.2.1 方式1&#xff1a;window本地安装2.2.1.1 下载2.2.1.2 安装2.2.1.3 目录结构…

关于 typeof 与 instanceof 区别引出的原型对象问题

一、关于 typeof 与 instanceof 区别&#xff1a; typeof 和 instanceof 是 JavaScript 中用于检查变量类型的两个不同操作符&#xff0c;它们在使用上有着明显的区别和不同的适用场景。 typeof typeof 是一个一元操作符&#xff0c;用于返回一个变量或表达式的数据类型的字符…

Docker部署的MySQL容器数据备份与导入

适用场景 采用Docker部署MySQL时&#xff0c;需要对MySQL的数据&#xff0c;通过服务器命令的方式进行导入导出的情况。 假设MySQL容器名为dsms_mysql5.7&#xff0c;用户名为root&#xff0c;密码为123456&#xff0c;数据库名为demo&#xff0c;备份SQL文件为backup.sql&am…

简单认识算法

什么是算法&#xff1f; 解决某个实际问题的过程和方法。 排序算法 1.冒泡排序 打印结果&#xff1a; 2.选择排序 打印结果&#xff1a; 优化选择排序&#xff1a;因为每一轮都需要以当前位置为基准与后面元素比较&#xff0c;太过繁琐&#xff0c;所以可以找到后面元素中较小…

Long使用==

1、背景&#xff1a;测试程序的时候发生了没数据的bug,于是在sevice层的一堆代码中调试&#xff0c;最后发现问题是在stream的filter方法中对两个Long使用造成的问题。 2、测试代码&#xff1a; Long a Long.valueOf(340);Long b Long.valueOf(340);System.out.println(a b)…

指针的学习4

目录 回调函数 qsort使用样例 使用qsort函数排序整形数据 使用qsort函数排序结构体 回调函数 回调函数就是一个通过函数指针调用的函数。如果把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xf…

想打造爆款AI应用?ai虚拟数字人制作助你一臂之力

如今&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI应用已经渗透到我们生活的方方面面。而在这个充满竞争和创新的时代&#xff0c;不少企业都在努力寻找打造爆款AI应用的机会。其中&#xff0c;AI虚拟数字人制作可以为他们提供一臂之力。 AI虚拟数字人制作是指利用人…

六氟化硫SF6气体怎么监测泄漏?

在当今的电力工程领域中,六氟化硫是一种应用广泛的电负性气体,从它发明至今已有百年历史。六氟化硫耐电强度为同一压力下氮气的2.5倍,击穿电压是空气的2.5倍,灭弧能力是空气的100倍,是一种优于空气和油之间的新-代超高压绝缘介质材料。 六氟化硫以其良好的绝缘性能和灭弧性能,在…

解决ts报错:类型“entry”上不存在属性“$AppTools”

uniapp ts 项目&#xff0c;已经将AppTools挂在了vue的原型上&#xff0c;但是在vue页面使用时报错&#xff0c;如图&#xff1a; 解决&#xff1a; 在项目根目录下的tsconfig.json文件添加如下配置&#xff1a; "include": ["src/**/*"],这样报错就消失…

centos7.4下升级最新的ssh

一 安装telnet服务器 安装telnet服务器目的&#xff0c;防止我们升级失败的时候&#xff0c;可以通过telnet登录&#xff0c;而不至于上机房。 由于我们是临时启动&#xff0c;所以只要简单的使用&#xff0c;不要通过xinetd来进行守护。 命令如下&#xff1a; yum -y install …