小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】


小啾带你开天眼 开启py-OpenCV摄像头及视频处理
            【Python-Open_CV系列(十二)】

文章目录

  • 1.调用摄像头 – 使用VideoCapture
  • 2.视频文件处理
  • 3.视频文件的保存 – 使用VideoWriter

  •       ʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞ
                     请添加图片描述请添加图片描述请添加图片描述
        ʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔɞ


    🌹꧔ꦿ本系列blog传送门:

    OpenCV图像处理基本操作 【Python-Open_CV系列(一)】

    OpenCV像素处理基本操作 【Python-Open_CV系列(二)】

    OpenCV之 BGR、GRAY、HSV色彩空间&色彩通道专题 【Python-Open_CV系列(三)】

    OpenCV绘制图像与文字(可作为脚手架代码)(python) 【Python-Open_CV系列(四)】

    OpenCV图像几何变换专题(缩放、翻转、仿射变换及透视)【python-Open_CV系列(五)】

    基于梵·高《向日葵》的 图像阈值处理专题(二值处理、反二值处理、截断处理、自适应处理及Otsu方法)【Python-Open_CV系列(六)】

    OpenCV基本功 之 图像的掩模、运算 & 合并专题 -小啾带学【Python-Open_CV系列(七)】

    《三英战吕布》 – 图像模板匹配 【Python-Open_CV系列(八)】

    OpenCV滤波器 龙门石窟篇【Python-Open_CV系列(九)】(均值滤波器、中值滤波器、高斯滤波器、双边滤波器)

    Open_CV形态学运算专题 (腐蚀&膨胀、开&闭运算、梯度运算、顶帽运算黑帽运算 )【Python-Open_CV系列(十)】

    霍夫变换看不懂?小啾带你串一遍:OpenCV图形检测专题 这样学最简单【Python-Open_CV系列(十一)】

    小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】

    小啾带你开天眼 之 人脸检测与识别(以及华强、皇叔、高祖配墨镜特效)【Python-Open_CV系列(十三)】


    大家好,我是侯小啾!

    前边的blog中,学习了这么多的图像处理基本功,今天终于到了这个令人心动的环节了,我们要使用OpenCV控制我们电脑的摄像头了,这也是迈向OPenCV的一大核心功能——人脸识别 的重要环节之一。正式开始之前呢,小啾先给大家带来一点关于图像与视频文件的科普:
    众所周知,视频是由一张张地图像连续播放而组成的,这些图像中的每一幅在视频中被称为“帧”。OpenCV不仅仅可以处理图像,也可以用来处理视频。一个视频文件所含有的图像总数,被称为“帧数”。视频被播放的时候,每秒播放的帧的数量被称为“帧速率(FPS,单位 为 帧/s)”帧宽度帧高度则分别是指在画面水平和垂直方向上的像素数量,通常可以理解为对长度的描述了解了这些,再读下文就十分简单啦。


    1.调用摄像头 – 使用VideoCapture

    cv2.VideoCapture类,顾名思义,“视频捕获”,其主要方法如下:


  • cv2.VideoCapture()方法
  • 通过cv2.VideoCapture()方法可以创建出一个实例化对象,完成摄像头的初始化工作。

    capture = cv2.VideoCapture(index)

    其需要传入一个index参数,表示摄像头的序列。填0表示电脑的内置摄像头(前提是电脑有内置摄像头)。填1,则表示有内置摄像头的情况下,外置的第一个摄像头。依次类推。

    除此之外,如果有警告信息,为了避免,也可以再index后边再加一个参数:cv2.CAP_DSHOW即可。


  • inOpened()方法
  • inOpened()方法 用于检验摄像头是否打开成功

    retval = capture.isOpened()

    无需传入参数,其中capture是cv2.VideoCapture类的实例化对象,返回值retval是一个布尔类型的值,如果摄像头初始化成功则为True,不成功则为False


  • read()方法
  • read()方法 用于从摄像头中读取帧。

    retval,image = capture.read()

    其中capture是cv2.VideoCapture类的实例化对象,返回值retval是一个布尔类型的值,如果摄像头初始化成功则为True,不成功则为Falseimage是读到的帧,即读到的图像。


  • relase()方法
  • relase()方法 用于关闭摄像头。(不需要摄像头时应该关闭)

    capture.relase()


    将上边四种方法综合写起来,来完成读取并显示摄像头视频的需求:

    import cv2
    
    
    capture = cv2.VideoCapture(0)
    while (capture.isOpened()):
        retval, image = capture.read() 
        cv2.imshow("Video", image)
        # 窗口的图像刷新时间为1毫秒
        key = cv2.waitKey(1)  
        if key == 32:  
            break
    capture.release()  
    cv2.destroyAllWindows()  
    

    如图,电脑摄像头被打开,拍摄到接着奏乐接着舞片段。(这是小啾手机上的画面映进电脑摄像头)(/doge)
          

    摄像头开启过程中,如果键盘上的空格键被点击,则摄像头会被关闭,程序执行结束。


    如果想要使获取到的视频为灰度的,即 将每一帧都转化为灰度图像,只需要对以上代码中read()读取到的image操作,转化为灰度图像即可。

    此外,窗口数量也是可以增加的。

    下边,打开八个窗口为例,同时为了方便展示效果界面,小啾还将每个窗口缩小到了原来的三分之二大小。

    在调用摄像头显示图像的同时,我们还可以对图像加点操作。
    以前边博文中讲到过的操作为例,我们使
    窗口“Video”显示原画面
    窗口“Video1”显示经过 低于阈值零处理的 画面
    窗口“Video2”显示 二值化处理过的画面
    窗口“Video3”显示反二值化处理过的画面
    窗口“Video4”显示阈值为10-50的Canny边缘检测的结果
    窗口“Video5”显示阈值为200-400的Canny边缘检测的结果
    窗口“Video6”显示 双边滤波后的效果
    窗口“Video7”显示灰度处理过的画面。

    具体代码如下:

    import cv2
    
    capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    while (capture.isOpened()):
        retval, image = capture.read()
        # 为方便展示,现将视频的帧宽度和帧高度缩小到原来的三分之二
        dst = cv2.resize(image, None, fx=2 / 3, fy=2 / 3)
        image_Gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)  # 灰度处理
        t, dst1 = cv2.threshold(image_Gray, 127, 255, cv2.THRESH_TOZERO)  # 低于阈值零处理
        t2, dst2 = cv2.threshold(image_Gray, 127, 255, cv2.THRESH_BINARY)  # 二值化处理
        t3, dst3 = cv2.threshold(image_Gray, 127, 255, cv2.THRESH_BINARY_INV)  # 反二值化处理
        dst4 = cv2.Canny(dst, 10, 50)  # 阈值为10-50的Canny边缘检测
        dst5 = cv2.Canny(dst, 200, 400)  # 阈值为200-400的Canny边缘检测
        dst6 = cv2.bilateralFilter(dst, 15, 125, 200)  # 双边滤波
    
    
        if retval == True:
            cv2.imshow("Video", dst)
            cv2.imshow("Video1", dst1)
            cv2.imshow("Video2", dst2)
            cv2.imshow("Video3", dst3)
            cv2.imshow("Video4", dst4)
            cv2.imshow("Video5", dst5)
            cv2.imshow("Video6", dst6)
            cv2.imshow("Video7", image_Gray)
        key = cv2.waitKey(1)
        if key == 32:
            break
    capture.release()
    cv2.destroyAllWindows()
    

    拓展一点,如果想要保存某个时间或条件下的图像,还使用之前学过的cv2.imwrite()方法即可完成,只需要在上述代码中合适的位置将设定的条件表述出来即可。
    OpenCV也支持同时读取多个摄像头的视频,再创建一个cv2.VideoCapture对象即可,很简单就能实现。因为目前小啾的PC只有一个摄像头,这里就不再做演示啦。

    此外,需要留意key = cv2.waitKey(1)这行代码,表示等待1毫秒,1毫秒到了键盘没有被点击就结束等待继续执行程序,继续执行则就意味着继续循环读取下一帧图像,也就是说一毫秒更新一帧图像,是在瞬间完成的。这就实现了实时的摄像头的拍摄。


    2.视频文件处理

    小啾准备一个关于打篮球教学1的mp4视频文件,链接:打篮球教程,大家可以点击链接下载下来,方便我们测试和学习代码。这里小啾将其以avi类型的文件格式进行下载。
    文件名这里写作"playing_basketball.avi"。


  • cv2.VideoCapture类 及 方法
  • 首先,获取图像文件依然使用的是cv2.VideoCapture()方法,来实例化一个cv2.VideoCapture对象。.通过cv2.VideoCapture()方法可以创建出的实例化对象,不仅可以完成摄像头的初始化工作,也可以完成获取视频文件的初始化工作。

    capture = cv2.VideoCapture(filename)

    其需要传入一个filename参数,即视频文件的文件名。创建好这个cv2.VideoCapture对象后,依然要对其使用read()方法读取。


  • capture.get()方法
  • 在对视频文件进行操作前,通常要先去获取视频文件的属性,这个过程可以通过对cv2.VideoCapture对象使用get()方法来实现。

    retval = cv2.VideoCapture.get(propld)

    其需要传入一个prople参数,即要获取的属性类型。retval是对应的值。

    其中,prople有以下值可供选择:

    属性 描述
    cv2.CAP_PROP_POS_MSEC 视频文件播放的当前位置。
    cv2.CAP_PROP_POS_FRAMES 帧的索引,从0开始
    cv2.CAP_PROP_POS_AVI_RATIO 视频文件的相对位置(0表示开始播放,1表示结束播放)
    cv2.CAP_PROP_FRAME_WIDTH 视频文件的帧宽度
    cv2.CAP_PROP_HEIGHT 视频文件的帧高度
    cv2.CAP_PROP_FPS 帧速率
    cv2.CAP_PROP_FOURCC 用4个字符表示的视频编码格式
    cv2.CAP_PROP_FRAME_COUNT 视频文件的帧数
    cv2.CAP_PROP_FORMAT retrieve()方法返回的Mat对象的格式
    cv2.CAP_PROP_MODE 指示当前捕捉模式的后端专用的值
    cv2.CAP_PROP_CONVERT_RGB 指示是否应将图形转换为RGB

    首先第一步,我们来查看一下"playing_basketball.avi"视频文件的属性:

    import cv2
    
    video = cv2.VideoCapture("playing_basketball.avi")
    # 获取视频文件的帧速率
    fps = video.get(cv2.CAP_PROP_FPS) 
    # 获取视频文件的帧数
    frame_Count = video.get(cv2.CAP_PROP_FRAME_COUNT)
    # 获取视频文件的帧宽度
    frame_Width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
    # 获取视频文件的帧高度
    frame_Height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
    print("帧速率:", fps)
    print("帧数:", frame_Count)
    print("帧宽度:", frame_Width)
    print("帧高度:", frame_Height)
    

                    

    获取到了视频文件的基本属性后,我们就可以对其进行播放操作了。其中可以看到,帧速率为30.0,即每秒三十帧画面。使用程序播放视频文件的时候,我们需要手动设置这个值。如果设置的帧速率小于30,即相当于实现了小于1的倍速播放;如果大于30,则意味着实现了大于1的倍速播放。

    上一段代码中,我们是通过控制image的shape来控制窗口大小的。除此之外,还有另外一种方式可以完成此操作。在接下来的代码中,我们大可不必这样,我们可以通过cv2.namedWindow()方法创建窗口,并使用 cv2.resizeWindow()方法直接对窗口的大小进行设定。

    在前边所有的blog中,当我们使用cv2.imshow()时,都没有在其前面加cv2.namedWindow(),那是因为没有调用的情况下,程序会自动调用一次cv2.namedWindow()方法将窗口创建出来。

    接下来,我们将读取本地视频文件"playing_basketball.avi",图像刷新时间设定为10毫秒,换算一下即帧速率为100帧/秒。我们要做的是,打开七个窗口,分别展示原视频图像,灰度处理过的结果,转到HSV色彩空间下的结果,低于阈值零处理的结果,二值化处理的结果,阈值在10-50的Canny边缘检测,阈值在200-400的Canny边缘检测。且在视频播放过程中,如果空格键被点击,视频会暂停,然后再点击任意键,视频会继续播放。如果点击了Esc键,则会关闭所有视频窗口。

    根据需求,代码如下:


    import cv2
    
    
    video = cv2.VideoCapture("playing_basketball.avi")
    
    frame_Count = video.get(cv2.CAP_PROP_FRAME_COUNT)
    i = 0
    while (video.isOpened()):
        retval, image1 = video.read()  # 原图像
        image2 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)  # 灰度
        image3 = cv2.cvtColor(image1, cv2.COLOR_BGR2HSV)  # 转到HSV色彩空间
        t4, image4 = cv2.threshold(image2, 127, 255, cv2.THRESH_TOZERO)  # 低于阈值零处理
        t5, image5 = cv2.threshold(image2, 127, 255, cv2.THRESH_BINARY)  # 二值化处理
        image6 = cv2.Canny(image1, 10, 50)  # 阈值为10-50的Canny边缘检测
        image7 = cv2.Canny(image1, 200, 400)  # 阈值为200-400的Canny边缘检测
        # 设置“Video”窗口
        cv2.namedWindow("playing_basketball_1", 0)
        cv2.resizeWindow("playing_basketball_1", 426, 240)
        cv2.namedWindow("playing_basketball_2", 0)
        cv2.resizeWindow("playing_basketball_2", 426, 240)
        cv2.namedWindow("playing_basketball_3", 0)
        cv2.resizeWindow("playing_basketball_3", 426, 240)
        cv2.namedWindow("playing_basketball_4", 0)
        cv2.resizeWindow("playing_basketball_4", 426, 240)
        cv2.namedWindow("playing_basketball_5", 0)
        cv2.resizeWindow("playing_basketball_5", 426, 240)
        cv2.namedWindow("playing_basketball_6", 0)
        cv2.resizeWindow("playing_basketball_6", 426, 240)
        cv2.namedWindow("playing_basketball_7", 0)
        cv2.resizeWindow("playing_basketball_7", 426, 240)
        if retval == True:
            cv2.imshow("playing_basketball_1", image1)
            cv2.imshow("playing_basketball_2", image2)
            cv2.imshow("playing_basketball_3", image3)
            cv2.imshow("playing_basketball_4", image4)
            cv2.imshow("playing_basketball_5", image5)
            cv2.imshow("playing_basketball_6", image6)
            cv2.imshow("playing_basketball_7", image7)
        else:
            break
        # 窗口的图像刷新时间为10毫秒 则帧速率为100帧/秒
        key = cv2.waitKey(10)
        if key == 32:
            cv2.waitKey(0)
            continue
        if key == 27:
            break
        i += 1
        if i == frame_Count:
            break
    
    
    video.release()
    cv2.destroyAllWindows()
    

    程序执行过程片段如下:



    3.视频文件的保存 – 使用VideoWriter


  • cv2.VideoWriter()方法
  • 通过cv2.VideoWriter()方法可以创建出一个VideoWriter类的实例化对象,而保存视频文件的常见流程为,创建VideoWriter对象,写入读到的帧,帧可以是摄像头抓取的,也可以是视频中的。写入完毕后,再使用release()方法释放VideoWriter对象。

    <VideoWriter object> = cv2.VideoWriter(filename, fourcc, fps, frameSize)

    在创建cv2.VideoWriter对象时可以传入四个参数:
    filename 即
    一个index参数,表示摄像头的序列。填0表示电脑的内置摄像头(前提是电脑有内置摄像头)。填1,则表示有内置摄像头的情况下,外置的第一个摄像头。依次类推。

    除此之外,如果有警告信息,为了避免,也可以再index后边再加一个参数:cv2.CAP_DSHOW即可。



  • cv2.VideoWriter类 及 方法
  • OpenCV还提供了cv2.VideoWriter类来实现对视频文件的保存。

    <VideoWriter object> = cv2.VideoWriter(filename, fourcc, fps, frameSize)

    其中
    参数<VideoWriter object> 即该类的实例化对象,自行命名即可。
    参数filename即保存视频文件时的文件名(含扩展名),可加路径。
    参数fourcc指的是用四个字符表示的视频编码的格式。通过cv2.VideoWriter_fourcc()方法生成,具体在下一部分展示。
    参数fps指的是帧速率。
    参数frameSize即每一帧的大小。


    使用cv2.VideoWriter类主要还涉及了两个方法,一个是write()方法,一个是relase()方法。其中write()方法用于将帧写入文件,参数即为读到的帧。而relase()方法则用于在不需要使用cv2.VideoWriter类实例对象时将其释放掉。
    保存视频文件的常见流程为,创建VideoWriter对象,写入读到的帧,帧可以是摄像头抓取的,也可以是视频中的,也可以是一张张的图像。写入完毕后,再使用release()方法释放VideoWriter对象。



    关于cv2.VideoWriter()方法的fourcc参数,
    需要使用到>cv2.VideoWriter_fourcc()方法生成,具体如下表:

    参数fourcc 视频编码格式 文件扩展名
    cv2.VideoWriter_fourcc(‘I’,‘4’,‘2’,‘0’) 未压缩的YUV颜色编码格式,兼容性好,但文件较大 .avi
    cv2.VideoWriter_fourcc(‘P’,‘T’,‘M’,‘T’) MPEG-1编码格式 .avi
    cv2.VideoWriter_fourcc(‘X’,‘V’,‘I’,‘D’) MPEG-4编码格式,视频文件的大小为平均值 .avi
    cv2.VideoWriter_fourcc(‘T’,‘H’,‘E’,‘O’) Ogg Vorbis 编码格式,兼容性差 .ogv
    cv2.VideoWriter_fourcc(‘F’,‘L’,‘V’,‘I’) Flash 视频编码格式 .flv

    以保存一段摄像头视频为例,采用MPEG-4编码格式编码格式,将文件保存在当前目录下,文件名为"new_Video.avi"。
    执行程序开始录制,按Esc键结束录制,并保存为avi文件。

    import cv2
    
    capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
    output = cv2.VideoWriter("new_Video.avi", fourcc, 20, (640, 480))
    while capture.isOpened():
        retval, frame = capture.read()
        if retval == True:
            output.write(frame)
            cv2.imshow("frame", frame)
        key = cv2.waitKey(1)
        if key == 27: # 如果按下Esc键
            break
    # 关闭笔记本内置摄像头
    capture.release()
    # 释放VideoWriter类对象
    output.release()
    cv2.destroyAllWindows()
    

    如果需求为录制一定的时间,则只需要对循环条件加一点判断:
    以录制s秒的帧速率为n的的视频为例,则总共需要的帧数为s×n,每次循环使该计数减少1,直到该计数减小到0结束循环即可。
    如果要保存现存的视频文件的某片段,则也同理,这里不再对此示例。仅对摄像头拍摄下的视频计时进行示例:

    具体代码示例如下:

    import cv2
    
    capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
    fps = 20  # 帧速率
    # 创建VideoWriter类对象
    output = cv2.VideoWriter("ten_Seconds.avi", fourcc, fps, (640, 480))
    frame_Num = 20 * fps # 时长为20秒的摄像头视频含有的帧数
    while capture.isOpened() and frame_Num > 0:
        # 从摄像头中实时读取视频
        retval, frame = capture.read()  
        if retval:
            # 在VideoWriter类对象中写入读取到的帧
            output.write(frame)
            # 在窗口中显示摄像头视频,这个是为了方便用户使用,符合人的视觉效果。仅程序执行的话可以不需要。
            cv2.imshow("frame", frame)
        # 窗口的图像刷新时间为1毫秒
        key = cv2.waitKey(1)  
        frame_Num -= 1  # 每次循环每写入一帧图像,frame_Num就减小一帧,直到减小到零即帧数写够了,不再循环。
    capture.release()
    output.release()
    cv2.destroyAllWindows()
    

    本次分享就到这里,小啾感谢您的关注与支持!
    🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ

    来源:侯小啾

    物联沃分享整理
    物联沃-IOTWORD物联网 » 小啾带你开天眼 之 开启py-OpenCV摄像头及视频处理【Python-Open_CV系列(十二)】

    发表评论