如何使用Python进行运动检测

175 阅读10分钟

概述

由于Python编程语言提供了多种开源库,因此使用Python进行运动检测很容易。运动检测在现实世界中有许多应用。例如,它可以用于在线考试的监考,或用于商店、银行等的安全目的。

简介

Python编程语言是一种开源的库丰富的语言,它为用户提供了大量的应用,并拥有众多的用户。因此,它在市场上快速发展。由于Python语言的语法简单,容易发现错误,而且调试过程快,使其更方便用户使用,所以它的好处不胜枚举。

为什么要学习Python?一个图示。

How to Perform Motion Detection Using Python
资料来源:《中国日报》。Scaler Topics

Python设计于1991年,它是由Python软件基金会开发的。有许多版本的Python被发布。在这些版本中,python2和python3是最有名的。目前,python3被广泛使用,python3的用户正在迅速增加。在这个项目或脚本中,我们将使用python3。

什么是运动检测?

根据物理学原理,当一个物体没有运动,没有速度,那么它就被认为是处于静止状态,而恰恰相反,当一个物体没有完全静止,并且在某个方向上有一些运动或速度,无论是左-右、前-后或上-下,那么它就被认为是在运动。在这篇文章中,我们将尝试对其进行检测。

How to Perform Motion Detection Using Python
来源:gtycat

运动检测在现实生活中有很多实现或使用,它可以证明自己的价值,例如使用网络摄像头监考在线考试(我们将在本文中实现),作为一个保安,等等。

在这篇文章中,我们将尝试实现一个脚本,通过这个脚本,我们将使用台式机或笔记本电脑的网络摄像头检测运动。我们的想法是,我们将采取两帧视频,并试图找到它们之间的差异。如果两帧之间有某种差异,那么很明显,摄像机前面的物体有某种运动,从而产生了这种差异。

重要的程序库

在我们开始执行代码之前,让我们看看我们将通过我们的代码使用的一些模块或库,用于网络摄像头的运动检测。正如我们所讨论的,库在python的名声中起着重要的作用,让我们看看我们需要什么。

  1. OpenCV
  2. Pandas

上述两个库,OpenCV和Pandas都是纯粹的基于python的、免费的、开源的库,我们将在Python3版本的python编程语言中使用它们。

1.1.OpenCV

OpenCV是一个开源的库,可以与许多编程语言如C++、Python等一起使用。它被用来处理图像和视频,通过使用或与python的panda/NumPy库集成,我们可以最好地利用OpenCV的功能。

2.2.潘达。

正如我们所讨论的,"Pandas"是Python的一个开源库,为数据分析提供了丰富的内置工具,因此它被广泛用于数据科学和数据分析的领域。pandas为我们提供了数据框架形式的数据结构,有助于操作和存储表格数据到一个二维数据结构。

以上讨论的两个模块都不是在python中内置的,我们必须在使用前先安装它们。除此之外,还有两个模块,我们将在我们的项目中使用。

  1. Python DateTime模块
  2. Python时间模块

这两个模块都是在Python中内置的,不需要再安装它们。这些模块分别处理与日期和时间有关的功能。

代码实现

到目前为止,我们已经看到了我们将在代码中使用的库,让我们开始实施,视频只是许多静态图像或帧的组合,所有这些帧的组合创造了一个视频:

导入所需的库

在本节中,我们将导入所有的库,如pandas和panda。然后我们从DateTime模块中导入cv2、time和DateTime函数。

# Importing the Pandas libraries  
import pandas as panda  

# Importing the OpenCV libraries  
import cv2  

# Importing the time module  
import time  

# Importing the datetime function of the datetime module  
from datetime import datetime 

初始化我们的数据变量

在这一节中,我们初始化了我们的一些变量,我们将在代码中进一步使用这些变量。我们将初始状态定义为 "无",并将运动跟踪存储在另一个变量motionTrackList中。

我们定义了一个列表 "motionTime "来存储运动被发现的时间,并使用熊猫的模块初始化了dataFrame列表。

# Assigning our initial state in the form of variable initialState as None for initial frames  
initialState = None  

# List of all the tracks when there is any detected of motion in the frames  
motionTrackList= [ None, None ]  

# A new list ‘time’ for storing the time when movement detected  
motionTime = []  

# Initialising DataFrame variable ‘dataFrame’ using pandas libraries panda with Initial and Final column  
dataFrame = panda.DataFrame(columns = ["Initial", "Final"])  

主要的捕捉过程

在这一节中,我们将执行我们的主要运动检测步骤。让我们按步骤来理解它们。

  1. 首先,我们将使用cv2模块开始捕获视频,并将其存储在视频变量中。
  2. 然后我们将使用一个无限的while循环来捕捉视频中的每一帧。
  3. 我们将使用read()方法来读取每一帧,并将它们存储到各自的变量中。
  4. 我们定义了一个变量motion并将其初始化为零。
  5. 我们又创建了两个变量grayImage和grayFrame,使用cv2函数cvtColor和GaussianBlur来寻找运动的变化。
  6. 如果我们的initialState是None,那么我们就把当前的greyFrame分配给initialState,否则就使用'continue'关键字来停止下一个进程。
  7. 在下一节中,我们计算了我们在当前迭代中创建的初始帧和灰度帧之间的差异。
  8. 然后我们将使用cv2的阈值和扩张函数来突出初始帧和当前帧之间的变化。
  9. 我们将从当前图像或帧中找到移动物体的轮廓,并通过使用矩形函数在其周围创建一个绿色的边界来表明移动物体。
  10. 在这之后,我们将把当前检测到的元素添加到motionTrackList中。
  11. 我们通过使用imshow方法显示所有的帧,如灰度和原始帧等。
  12. 此外,我们使用cv2模块的witkey()方法创建了一个键来结束这个过程,我们可以通过使用'm'键来结束我们的过程。
# starting the webCam to capture the video using cv2 module  
video = cv2.VideoCapture(0)  

# using infinite loop to capture the frames from the video 
while True:  

   # Reading each image or frame from the video using read function 

   check, cur_frame = video.read()  

   

   # Defining 'motion' variable equal to zero as initial frame 

   var_motion = 0  

   

   # From colour images creating a gray frame 

   gray_image = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY)  

   

   # To find the changes creating a GaussianBlur from the gray scale image  

   gray_frame = cv2.GaussianBlur(gray_image, (21, 21), 0)  

   

   # For the first iteration checking the condition

   # we will assign grayFrame to initalState if is none  

   if initialState is None:  

       initialState = gray_frame  

       continue  

       

   # Calculation of difference between static or initial and gray frame we created  

   differ_frame = cv2.absdiff(initialState, gray_frame)  

   

   # the change between static or initial background and current gray frame are highlighted 

   

   thresh_frame = cv2.threshold(differ_frame, 30, 255, cv2.THRESH_BINARY)[1]  

   thresh_frame = cv2.dilate(thresh_frame, None, iterations = 2)  

   

   # For the moving object in the frame finding the coutours 

   cont,_ = cv2.findContours(thresh_frame.copy(),   

                      cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  

   

   for cur in cont:  

       if cv2.contourArea(cur) < 10000:  

           continue  

       var_motion = 1  

       (cur_x, cur_y,cur_w, cur_h) = cv2.boundingRect(cur)  

       

       # To create a rectangle of green color around the moving object  

       cv2.rectangle(cur_frame, (cur_x, cur_y), (cur_x + cur_w, cur_y + cur_h), (0, 255, 0), 3)  

       

  # from the frame adding the motion status   

   motionTrackList.append(var_motion)  

   motionTrackList = motionTrackList[-2:]  

   

   # Adding the Start time of the motion 

   if motionTrackList[-1] == 1 and motionTrackList[-2] == 0:  

       motionTime.append(datetime.now())  

       

  # Adding the End time of the motion 

   if motionTrackList[-1] == 0 and motionTrackList[-2] == 1:  

       motionTime.append(datetime.now())  

       

  # In the gray scale displaying the captured image 

   cv2.imshow("The image captured in the Gray Frame is shown below: ", gray_frame)  

   

   # To display the difference between inital static frame and the current frame 

   cv2.imshow("Difference between the  inital static frame and the current frame: ", differ_frame)  

   

   # To display on the frame screen the black and white images from the video  

   cv2.imshow("Threshold Frame created from the PC or Laptop Webcam is: ", thresh_frame)  

   

   # Through the colour frame displaying the contour of the object

   cv2.imshow("From the PC or Laptop webcam, this is one example of the Colour Frame:", cur_frame)  

   

   # Creating a key to wait  

   wait_key = cv2.waitKey(1)  

   

   # With the help of the 'm' key ending the whole process of our system   

   if wait_key == ord('m'):  

       # adding the motion variable value to motiontime list when something is moving on the screen  

       if var_motion == 1:  

           motionTime.append(datetime.now())  

       break 

完成代码

关闭循环后,我们将把我们的数据从dataFrame和motionTime列表中添加到CSV文件中,最后关闭视频。

# At last we are adding the time of motion or var_motion inside the data frame  
for a in range(0, len(motionTime), 2):  

   dataFrame = dataFrame.append({"Initial" : time[a], "Final" : motionTime[a + 1]}, ignore_index = True)  

   
# To record all the movements, creating a CSV file  
dataFrame.to_csv("EachMovement.csv")  

# Releasing the video   
video.release()  

# Now, Closing or destroying all the open windows with the help of openCV  
cv2.destroyAllWindows()

过程总结

我们已经创建了代码,现在让我们再次简要地讨论一下这个过程。

首先,我们使用设备的网络摄像头拍摄了一段视频,然后以输入视频的初始帧为参考,并不时地检查接下来的帧。如果发现有与第一帧不同的帧,就说明有运动存在。这将被标记在绿色的矩形中。

合并代码

我们已经看到了不同部分的代码。现在,让我们把它结合起来。

# Importing the Pandas libraries  
import pandas as panda  

# Importing the OpenCV libraries  
import cv2  

# Importing the time module  
import time  

# Importing the datetime function of the datetime module  
from datetime import datetime 

# Assigning our initial state in the form of variable initialState as None for initial frames  
initialState = None  

# List of all the tracks when there is any detected of motion in the frames  
motionTrackList= [ None, None ]  

# A new list 'time' for storing the time when movement detected  
motionTime = []  

# Initialising DataFrame variable 'dataFrame' using pandas libraries panda with Initial and Final column  
dataFrame = panda.DataFrame(columns = ["Initial", "Final"])

# starting the webCam to capture the video using cv2 module  
video = cv2.VideoCapture(0)  

# using infinite loop to capture the frames from the video 
while True:  

   # Reading each image or frame from the video using read function 

   check, cur_frame = video.read()  

   

   # Defining 'motion' variable equal to zero as initial frame 

   var_motion = 0  

   

   # From colour images creating a gray frame 

   gray_image = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY)  

   

   # To find the changes creating a GaussianBlur from the gray scale image  

   gray_frame = cv2.GaussianBlur(gray_image, (21, 21), 0)  

   

   # For the first iteration checking the condition

   # we will assign grayFrame to initalState if is none  

   if initialState is None:  

       initialState = gray_frame  

       continue  

       

   # Calculation of difference between static or initial and gray frame we created  

   differ_frame = cv2.absdiff(initialState, gray_frame)  

   

   # the change between static or initial background and current gray frame are highlighted 

   

   thresh_frame = cv2.threshold(differ_frame, 30, 255, cv2.THRESH_BINARY)[1]  

   thresh_frame = cv2.dilate(thresh_frame, None, iterations = 2)  

   

   # For the moving object in the frame finding the coutours 

   cont,_ = cv2.findContours(thresh_frame.copy(),   

                      cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  

   

   for cur in cont:  

       if cv2.contourArea(cur) < 10000:  

           continue  

       var_motion = 1  

       (cur_x, cur_y,cur_w, cur_h) = cv2.boundingRect(cur)  

       

       # To create a rectangle of green color around the moving object  

       cv2.rectangle(cur_frame, (cur_x, cur_y), (cur_x + cur_w, cur_y + cur_h), (0, 255, 0), 3)  

       

  # from the frame adding the motion status   

   motionTrackList.append(var_motion)  

   motionTrackList = motionTrackList[-2:]  

   

   # Adding the Start time of the motion 

   if motionTrackList[-1] == 1 and motionTrackList[-2] == 0:  

       motionTime.append(datetime.now())  

       

  # Adding the End time of the motion 

   if motionTrackList[-1] == 0 and motionTrackList[-2] == 1:  

       motionTime.append(datetime.now())  

       

  # In the gray scale displaying the captured image 

   cv2.imshow("The image captured in the Gray Frame is shown below: ", gray_frame)  

   

   # To display the difference between inital static frame and the current frame 

   cv2.imshow("Difference between the  inital static frame and the current frame: ", differ_frame)  

   

   # To display on the frame screen the black and white images from the video  

   cv2.imshow("Threshold Frame created from the PC or Laptop Webcam is: ", thresh_frame)  

   

   # Through the colour frame displaying the contour of the object

   cv2.imshow("From the PC or Laptop webcam, this is one example of the Colour Frame:", cur_frame)  

   

   # Creating a key to wait  

   wait_key = cv2.waitKey(1)  

   

   # With the help of the 'm' key ending the whole process of our system   

   if wait_key == ord('m'):  

       # adding the motion variable value to motiontime list when something is moving on the screen  

       if var_motion == 1:  

           motionTime.append(datetime.now())  

       break 

# At last we are adding the time of motion or var_motion inside the data frame  
for a in range(0, len(motionTime), 2):  

   dataFrame = dataFrame.append({"Initial" : time[a], "Final" : motionTime[a + 1]}, ignore_index = True)  

   
# To record all the movements, creating a CSV file  
dataFrame.to_csv("EachMovement.csv")  

# Releasing the video   
video.release()  

# Now, Closing or destroying all the open windows with the help of openCV  
cv2.destroyAllWindows()

结果

运行上述代码后得出的结果将与下面的内容类似。

How to Perform Motion Detection Using Python

在这里,我们可以看到视频中的人的运动已经被跟踪了。因此,可以看到相应的输出。

然而,在这段代码中,跟踪将在移动物体周围的矩形框的帮助下完成,类似于下面所看到的。这里需要注意的是,该视频是一个安全摄像机的录像,已经完成了检测。

image.png

How to Perform Motion Detection Using Python

结论

  • Python编程语言是一种开放源码的丰富语言,为用户提供了许多应用。

  • 当一个物体不动,没有速度,那么它就被认为是静止的,而恰恰相反,当一个物体没有完全静止,那么它就被认为是在运动。

  • OpenCV是一个开源的库,可以用于许多编程语言,通过与python的panda/NumPy库集成,我们可以最好地利用OpenCV的功能。

  • 其主要思想是,每个视频都是由许多被称为帧的静态图像组合而成的,而帧之间的差异被用于检测