译者|朱宪忠审稿人|孙书娟概述由于Python编程语言面临着多个可用的开源库;因此,选择Python语言进行运动检测开发是非常容易的。目前,运动检测有很多商业应用。例如,它可以用于在线考试的监考,也可以用于商店、银行等的安全目的。Python编程语言是一种开源语言,具有极其丰富的支持库。今天,基于这门语言为用户开发了大量的应用程序,它拥有大量的用户。正因为如此,Python语言在市场上发展迅速。Python语言的优点很多,不仅因为它的语法简单,容易发现错误,还因为它的调试过程非常快,因此更加人性化。为什么推荐大家学习Python?我们可以用下图来简单说明一下:Python于1991年设计,由PythonSoftwareFoundation开发。今天发布了很多版本。其中以Python2和Python3最为著名。目前,Python3已经得到广泛应用,用户数量也在快速增长。在这个项目中,我们将使用Python3作为开发语言。什么是运动检测?根据物理学原理,当一个物体静止且没有速度时,它被称为静止;当一个物体不是完全静止的并且处于某个方向(左右、前后或上下)时,情况恰恰相反。当有一定量的运动或速度时,据说它在运动在上面。在本文中,我们将尝试检测物体的移动。目前,运动检测在现实生活中已经有大量的实现或应用,充分证明了其巨大的应用价值。其中,使用网络摄像头(我们将在本文中实现)作为在线监考等安全卫士是最典型的应用。在本文中,我们将尝试实现一个脚本。使用此脚本,我们将使用安装在台式机或笔记本电脑上的网络摄像头实施运动检测。我们的想法是,我们将拍摄两帧视频并尝试找出它们之间的区别。如果两帧之间存在某种差异,那么很明显,镜头前的物体发生了某种运动,这就是差异所在。主要参考库在继续实施代码之前,让我们看一下我们将在代码中使用的一些模块或库,以操作网络摄像头进行运动检测。正如我们所讨论的,这些开源库在传播Python的声誉方面发挥着重要作用。我们来看看本文示例项目需要的开源库:OpenCVPandas以上两个库OpenCV和Pandas是纯基于Python的免费开源库,我们将通过Python语言的Python3版本来使用它们。1、OpenCVOpenCV是一个非常著名的开源库,可以与多种编程语言(如C++、Python等)一起使用,专门用于图像和视频程序开发。通过将应用程序与Python的开源库Pandas或NumPy库集成,我们可以充分发挥OpenCV的功能。2.PandasPandas是一个开源的Python库,提供了丰富的内置数据分析工具;因此,它在数据科学和数据分析领域得到了广泛的应用。Pandas中提供了DataFrame数据结构形式的数据结构,为将表格数据操作存储成二维数据结构提供了极其方便的支持。以上两个模块都没有内置到Python中,我们必须在使用它们之前安装它们。除此之外,我们将在我们的项目中使用另外两个模块。Python日期时间(DateTime)模块Python时间(Time)模块这两个模块都是Python内置的,以后不需要安装。这些模块分别用于处理日期和时间相关的功能。代码实现到目前为止,我们已经了解了我们将在代码中使用的库。接下来,让我们假设视频只是许多静止图像或帧的组合,并使用所有这些帧的组合来创建单个视频。导入所需的库在本节中,我们将首先导入所有库,例如Pandas和OpenCV。然后,我们从DateTime模块导入时间和DateTime函数。#ImportPandaslibraryimportPandasaspanda#ImportOpenCVlibraryimportcv2#Importtimemoduleimporttime#Importdatetimefromdatetimemodulefunctionfromdatetimeimportdatetime初始化数据变量进一步使用这些变量。首先,我们将初始状态定义为“None”,然后通过另一个变量motionTrackList存储跟踪的运动。此外,我们还定义了一个列表“motionTime”来存储发现运动的时间,并使用Panda的模块来初始化数据帧列表。#对于初始帧,在变量initialState中将初始状态指定为NoneinitialState=None#当在帧中检测到任何运动时用于存储所有轨迹的列表motionTrackList=[None,None]#存储的新“时间”列表检测到运动的时间motionTime=[]#使用带有初始列和最终列的Panda库初始化数据帧变量“DataFrame”dataFrame=panda.DataFrame(columns=["Initial","Final"])keyframeCaptureProcessInthis部分,我们将实现本文示例项目中最关键的运动检测步骤。接下来,我们一步一步来解释:首先,我们将开始使用cv2模块捕获视频并将其存储在video变量中。然后,我们将使用一个无限的while循环来捕获视频中的每一帧。接下来,将使用read()方法读取每一帧并将其存储到各自的变量中。我们定义一个变量var_motion并将其初始化为零。我们使用cv2函数cvtColor和GaussianBlur创建另外两个变量grayImage和grayFrame来查找运动变化。如果我们的initialState是None,我们指定当前grayFrame为initialState;否则,使用“continue”关键字跳过以下代码的执行。在后面的代码中,我们计算了当前迭代中创建的初始帧和灰度帧之间的差异。然后我们将使用cv2阈值和扩张函数来突出显示初始帧和当前帧之间的变化。我们将从当前图像或帧中的移动对象中找到轮廓,并通过使用矩形函数在它们周围创建绿色边框来指示移动对象。在此之后,我们会将当前检测到的元素添加到列表变量motionTrackList中。到目前为止,我们已经使用imshow方法将所有关键帧显示为灰度和原始帧。另外,我们还使用cv2模块的witkey()方法来结束进程。在程序中,我们选择通过按键盘上的“m”键来结束我们的进程。#使用cv2模块启动网络摄像头以捕获视频video=cv2.VideoCapture(0)#使用无限循环从视频中捕获帧whileTrue:#使用读取函数检查从视频中读取每个图像或帧,cur_frame=video。read()#Definethe'motion'variableasaninitialframeequalto0var_motion=0#Createagrayframefromacolorimagegray_image=cv2.cvtColor(cur_frame,cv2.COLOR_BGR2GRAY)#使用灰度图像的GaussianBlur函数找到变化的部分gray_frame=cv2.GaussianBlur(gray_image,(21,21),0)#第一次迭代条件检查#如果是None,将grayFrame赋给变量initialStateifinitialStateisNone:initialState=gray_framecontinue#计算静态(或初始)帧和我们创建的灰帧differ_frame=cv2.absdiff(initialState,gray_frame)#静态或初始背景与当前灰帧之间的变化将被突出显示thresh_frame=cv2.threshold(differ_frame,30,255,cv2.THRESH_BINARY)[1]thresh_frame=cv2.dilate(thresh_frame,None,iterations=2)#对于帧中的移动物体,求轮廓cont,_=cv2.findContours(thresh_frame.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcurincont:if简历2.contourArea(cur)<10000:continuevar_motion=1(cur_x,cur_y,cur_w,cur_h)=cv2.boundingRect(cur)#在移动物体周围创建一个绿色矩形cv2.rectangle(cur_frame,(cur_x,cur_y),(cur_x+cur_w,cur_y+cur_h),(0,255,0),3)#从帧中添加运动状态motionTrackList.append(var_motion)motionTrackList=motionTrackList[-2:]#添加运动开始时间ifmotionTrackList[-1]==1andmotionTrackList[-2]==0:motionTime.append(datetime.now())#添加运动结束时间ifmotionTrackList[-1]==0andmotionTrackList[-2]==1:motionTime.append(datetime.now())#显示拍摄图像的灰度cv2.imshow("GrayFrame中拍摄的图像如下所示:",gray_frame)#显示初始静态帧与当前帧的距离差cv2.imshow("Differencebetweentheinitialstaticframeandthecurrentframe:",differ_frame)#在帧屏上显示视频中的黑白图像cv2.imshow("ThresholdFramecreatedf来自PC或笔记本电脑网络摄像头的是:",thresh_frame)#通过色框显示物体轮廓cv2.imshow("FromPCorLaptopwebcam,thisisoneexampleoftheColorFrame:",cur_frame)#创建等待状态的键盘按键wait_key=cv2.waitKey(1)#当'm'键被按下时,执行整个过程ifwait_key==ord('m'):#当屏幕上有物体移动时,将运动变量值添加到motiontime列表中ifvar_motion==1:motionTime.append(datetime.now())break循环体执行结束后,我们将dataFrame和motionTime列表中的数据添加到CSV文件中,最后关闭视频。这部分代码的实现如下:#最后我们在dataframe中添加运动时间forainrange(0,len(motionTime),2):dataFrame=dataFrame.append({"Initial":time[a],"Final":motionTime[a+1]},ignore_index=True)#创建一个CSV文件记录所有的运动信息dataFrame.to_csv("EachMovement.csv")#释放显存video.release()#现在,借助openCVcv2.destroyAllWindows()关闭或销毁所有打开的窗口至此,我们已经成功创建了所有代码。现在,让我们再次总结一下整个过程。首先,我们使用设备的网络摄像头捕捉视频,然后使用输入视频的初始帧作为参考,并时不时检查下一帧。如果您发现与第一帧不同的帧,则存在运动。此信息将标记在绿色矩形中。完整代码现在,让我们将以上所有代码片段连接在一起,如下所示:在变量initialState中将初始状态指定为NoneinitialState=None#当在帧中检测到任何运动时存储所有轨道的列表motionTrackList=[None,None]#一个新的“时间”列表,用于存储运动时的时间被检测到motionTime=[]#使用具有初始和最终列的Panda库初始化数据帧变量“DataFrame”dataFrame=panda.DataFrame(columns=["Initial","Final"])#使用cv2模块启动网络摄像头以捕获视频video=cv2.VideoCapture(0)#使用无限循环从视频中捕获帧whileTrue:#使用读取函数从视频中读取每个图像或帧check,cur_frame=video.read()#将“motion”变量定义为初始帧等于零var_motion=0#从彩色图像中创建一个灰度帧gray_image=cv2.cvtColor(cur_frame,cv2.COLOR_BGR2GRAY)#使用GaussianBlur函数从灰度图像中找到变化部分gray_frame=cv2.GaussianBlur(gray_image,(21,21),0)#第一次迭代条件检查#如果为None,则将grayFrame赋值给变量initalStateifinitialStateisNone:initialState=gray_framecontinue#用灰度计算静态(或初始)帧帧之间的差异differ_frame=cv2.absdiff(initialState,gray_frame)#静态或初始背景与当前灰帧之间的变化将被突出显示thresh_frame=cv2.threshold(differ_frame,30,255,cv2.THRESH_BINARY)[1]thresh_frame=cv2.dilate(thresh_frame,None,iterations=2)#Formovingobjectsintheframe,findthecontourcont,_=cv2.findContours(thresh_frame.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)forcurincont:ifcv2复制代码.contourArea(cur)<10000:continuevar_motion=1(cur_x,cur_y,cur_w,cur_h)=cv2.boundingRect(cur)#在移动物体周围创建一个绿色矩形cv2.rectangle(cur_frame,(cur_x,cur_y),(cur_x+cur_w,cur_y+cur_h),(0,255,0),3)#添加来自帧的运动状态motionTrackList.append(var_motion)motionTrackList=motionTrackList[-2:]#添加运动开始时间ifmotionTrackList[-1]==1andmotionTrackList[-2]==0:motionTime.append(datetime.now())#添加运动的结束时间ifmotionTrackList[-1]==0andmotionTrackList[-2]==1:motionTime.append(datetime.now())#以灰度显示捕获的图像cv2.imshow("GrayFrame中捕获的图像如下所示:",gray_frame)#显示differencebetweentheinitialstaticframeandcurrentframecv2.imshow("Differencebetweentheinitialstaticframeandthecurrentframe:",differ_frame)#在帧屏幕上显示来自视频的黑白图像cv2.imshow("ThresholdPC或LaptopWebcam创建的Frameis:",thresh_frame)#通过色框显示物体的轮廓cv2.imshow("FromthePCorLaptopwebcam,thisisoneexampleofColorFrame:",cur_frame)#CreationiswaitingStatekeyboardkeywait_key=cv2.waitKey(1)#使用'm'键结束我们系统的整个过程ifwait_key==ord('m'):#将运动变量值添加到列表中当有物体在屏幕上运行时Ifvar_motion==1inmotiontime:motionTime.append(datetime.now())break#最后,我们广告d在range(0,len(motionTime),2)中的数据帧的运动时间:dataFrame=dataFrame.append({"Initial":time[a],"Final":motionTime[a+1]},ignore_index=True)#记录所有运行并创建一个在CSV文件中dataFrame.to_csv("EachMovement.csv")#释放显存video.release()#现在,在openCV的帮助下关闭或销毁所有打开的窗口结果类似于下面看到的从这个动画中,我们可以看到,视频中男子的动作已经被追踪。因此,可以相应地看到输出结果。然而,在这段代码中,跟踪是在移动对象周围的矩形框的帮助下完成的,类似于下面动画中显示的矩形框。这里需要注意的一件有趣的事情是,该视频是来自实际安全摄像头的镜头,已经过检测处理。结束语Python编程语言是一种开源语言,拥有丰富的开源库支持,目前为用户提供了许多现成的应用程序。当一个物体处于静止状态并且没有速度时,它被称为静止状态;相反,当一个物体没有完全静止时,它就被称为运动。OpenCV是一个开源库,适用于多种编程语言,通过与Python的Panda/NumPy库集成,可以充分发挥OpenCV的功能。最后,我们来总结一下。本文提出的运动检测的主要思想是每个视频只是很多静止图像(称为帧)的组合,我们通过判断帧之间的差异来实现运动检测。译者介绍朱宪忠,社区编辑,专家博主,讲师,潍坊某高校计算机教师,自由编程资深人士。早期专注于各种微软技术(编译成三本与ASP.NETAJX和Cocos2d-X相关的技术书籍)。/ESP32/RaspberryPi等物联网开发技术和Scala+Hadoop+Spark+Flink等大数据开发技术。原标题:HowtoPerformMotionDetectionUsingPython,作者:VaishnaviAmiraYada
