OpenCV 运动检测
在本文中,我们将学习如何在 OpenCV 和 Python 的帮助下创建运动检测项目。
使用 OpenCV 和 Python 创建运动检测项目
首先说一下这个项目的需求。显然,第一个要求是安装 Python,我们还需要安装一个名为 opencv
的外部包。
我们需要打开命令提示符并运行此命令以在你的 PC 上安装此软件包。让我们跳到我们的编辑器并开始编写我们的代码。
我们将导入的第一件事是我们需要的库,cv2
和 time
,接下来我们将使用 OpenCV 的 VideoCapture()
方法从我们的网络摄像头获取数据。
让我们创建一个名为 Video
的对象,我们必须将 0
传递给 VideoCapture()
,因为我们正在为网络摄像头使用 0 通道。
import cv2
import time
Video = cv2.VideoCapture(0)
First_Frame = None
现在我们将创建一个 while True
循环或无限循环,因为我们将提取视频,而视频是图像幻灯片上的连续移动。
现在我们将在 while
循环中定义几条指令,在第一行中,我们将创建两个变量 Check
和 frame
,并读取 VideoCapture()
方法提取的数据。在下一条指令中,我们将把这个提取的图像转换成灰度图。
但是为什么我们要把它转换成灰度呢?我们这样做是因为我们想提高特征检测的准确性。
我们使用 cvtColor()
方法来改变灰度并且有两个参数。首先是帧
或我们要转换为灰度的图像,然后是 COLOR_BGR2GRAY
,它将图像转换为灰度。
现在我们将使图像模糊或平滑,这就是为什么物体检测或物体运动会容易得多的原因。我们使用 GaussianBlur()
方法来应用平滑并将灰度图像、内核大小和 sigma 传递给它。
while True:
Check, frame = Video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
我们将创建一个 if
语句来检查帧是否到来,我们这样做是因为我们希望 First_Frame
作为我们的参考帧。
让我们来看看物理学对运动的看法?运动是从一个参考点识别出来的,我们用一个例子来解释这一点。
假设你坐在火车上,对你来说,树木在移动,但它们并没有移动;它们仍然是,但你正在从你的参考点移动。在这种情况下,树是参考点,但在我们的例子中,框架是参考。
我们将 First_Frame
固定为我们的参考框架;如果参考系发生任何变化,那么我们可以说运动存在。
现在我们将设置一个语句,如果 First_Frame
变量为 None
(在第一种情况下为 true
),那么我们将使 First_Frame
变量等于作为 gray
变量的灰度图像。
if First_Frame is None:
First_Frame = gray
continue
我们将使用 absdiff()
方法来查找帧之间的差异。让我们创建一个增量帧变量并将两个参数传递给 absdiff()
方法进行比较。
我们需要设置一个阈值或限制,我们希望检测到运动,因为我们不希望噪声被检测为运动。
为此,我们使用 threshold()
方法,它有几个参数,第一个是 delta_frame
,第二个是强度,第三个是颜色阴影,在这种情况下是白色,然后是下一个是 THRESH_BINARY
,因为它是一个元组,所以我们需要选择第一个元素。
我们还需要在下一条指令中再应用一个平滑层。为此,我们需要使用另一个称为 dilate()
的平滑函数,它接受三个参数,第一个是 threshold
,第二个是 None
,第三个参数是 iterations
。
iterations
参数定义了平滑的精确度;如果你增加此参数值,你的程序也会捕获噪声。
这次我们将创建轮廓,那么轮廓是什么?轮廓是运动发生的点。
如果框架静止并且手在移动,那么手的部分就是轮廓。
findContours()
方法有助于查找轮廓,它接受三个参数,第一个是帧,我们使用 copy()
方法创建帧数组的副本。
delta_frame = cv2.absdiff(First_Frame, gray)
Threshold_frame = cv2.threshold(delta_frame, 50, 255, cv2.THRESH_BINARY)[1]
Threshold_frame = cv2.dilate(Threshold_frame, None, iterations=2)
(cntr, _) = cv2.findContours(
Threshold_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
现在我们将通过迭代获得轮廓并将近似区域定义为运动。如果我们不定义区域,我们将得到一个非常嘈杂的运动检测。
首先我们会检查,如果轮廓区域小于一千,那么我们不认为这是一个运动区域,我们会继续迭代,如果大于一千,那么我们就画一个三角形。
for contour in cntr:
if cv2.contourArea(contour) < 1000:
continue
findContours()
方法给出了四个值(x、y、高度、宽度),我们将使用 boundingRect()
方法提取这些点,该方法将绑定矩形的区域。现在我们将在 rectangle()
方法的帮助下创建矩形。
第一个参数是我们要在其上绘制矩形的 frame
或图像。接下来是 (x,y)
坐标点,接下来是高度和宽度,接下来是边框的颜色,最后一个参数是选择画矩形的笔的大小。
(x, y, w, h) = cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
完整的源代码:
import cv2
import time
Video = cv2.VideoCapture(0)
First_Frame = None
while True:
Check, frame = Video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
if First_Frame is None:
First_Frame = gray
continue
delta_frame = cv2.absdiff(First_Frame, gray)
Threshold_frame = cv2.threshold(delta_frame, 50, 255, cv2.THRESH_BINARY)[1]
Threshold_frame = cv2.dilate(Threshold_frame, None, iterations=2)
(cntr, _) = cv2.findContours(
Threshold_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
for contour in cntr:
if cv2.contourArea(contour) < 1000:
continue
(x, y, w, h) = cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.imshow("Frame", frame)
Key = cv2.waitKey(1)
if Key == ord("q"):
break
Video.release()
cv2.destroyAllWindows()
现在我们可以看到运动检测发生在手移动时。
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn