OpenCV-Python接口-3视频操作

一、视频读写

1. 读取视频文件

1.1 创建读取视频的对象

cap = cv.VideoCapture(filepath)        参数:filepath: 视频文件路径

1.2 视频的属性信息

获取视频的某些属性

retval = cap.get(propId)

参数:propId: 从0到18的数字,每个数字表示视频的属性

常用属性 

修改视频的属性信息

cap.set(propId,value)

参数:

  • proid: 属性的索引,与上面的表格相对应
  • value: 修改后的属性值

1.3 判断视频是否读取成功

isornot = cap.isOpened()

若读取成功则返回true,否则返回False

1.4 获取视频的一帧图像

ret, frame = cap.read()

参数:

  • ret: 若获取成功返回True,获取失败,返回False
  • Frame: 获取到的某一帧的图像

1.5 调用cv.imshow()显示图像

在显示图像时使用cv.waitkey()设置适当的持续时间,如果太低视频会播放的非常快,如果太高就会播放的非常慢,通常情况下我们设置25ms就可以了。

1.6 调用cap.realease()将视频释放掉

2. 保存视频文件

在OpenCV中我们保存视频使用的是VedioWriter对象,在其中指定输出文件的名称。

2.1 创建视频写入的对象

out = cv2.VideoWriter(filename,fourcc, fps, frameSize)

参数:

  • filename:视频保存的位置
  • fourcc:指定视频编解码器的4字节代码
  • fps:帧率
  • frameSize:帧大小

2.2 设置视频的编解码器

retval = cv2.VideoWriter_fourcc( c1, c2, c3, c4 )

  • 参数:

    c1,c2,c3,c4: 是视频编解码器的4字节代码,在fourcc.org中找到可用代码列表,与平台紧密相关,常用的有:
  • 在Windows中:DIVX(.avi)
  • 在OS中:MJPG(.mp4),DIVX(.avi),X264(.mkv)

2.3 获取图像,写入视频

利用cap.read()获取视频中的每一帧图像,并使用out.write()将每一帧图像写入视频中

2.4 释放资源

使用cap.release()和out.release()释放资源

3.示例代码

import cv2 as cv                          #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np 


def VideoPlay():

    #1.读取视频
    cap = cv.VideoCapture('/home/meta/Videos/Screencasts/DOG.webm')
    
    #2.判断是否读取成功
    while (cap.isOpened()):
        # 3 获取每一帧图像
        ret, frame = cap.read()
        # 4 是否获取成功
        if ret == True:
            cv.imshow("frame", frame)
        if cv.waitKey(25) & 0xFF == ord("q"):
            break

    cap.release()
    cv.destroyAllWindows()


def VideoWrite():

    # 1.读取视频
    cap = cv.VideoCapture("/home/meta/Videos/Screencasts/DOG.webm")
    
    # 2.获取图像的属性(宽和高,),并将其转换为整数
    frame_width = int(cap.get(3))
    frame_height = int(cap.get(4))   
    
    # 3.创建保存视频的对象,设置编码格式,帧率,图像的宽高等
    out = cv.VideoWriter('/home/meta/Videos/Screencasts/out1.avi',
                cv.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))
    
    while(True):
        # 4.获取视频中的每一帧图像
        ret, frame = cap.read()
        if ret == True: 
            # 5.将每一帧图像写入到输出文件中
            out.write(frame)
        else:
            break 
    
    # 6.释放资源
    cap.release()
    out.release()
    cv.destroyAllWindows()


if __name__ == "__main__":

    #VideoPlay()

    VideoWrite()

二、视频追踪

1. meanshift算法

meanshift算法的原理是,假设有一堆点集,还有一个小的窗口,这个窗口可能是圆形的,现在需要移动这个窗口到点集密度最大的区域当中。

最开始的窗口是蓝色圆环的区域,命名为C1。蓝色圆环的圆心用一个蓝色的矩形标注,命名为C1_o。 

而窗口中所有点的点集构成的质心在蓝色圆形点C1_r处,显然圆环的形心和质心并不重合。所以,移动蓝色的窗口,使得形心与之前得到的质心重合。在新移动后的圆环的区域当中再次寻找圆环当中所包围点集的质心,然后再次移动,通常情况下,形心和质心是不重合的。不断执行上面的移动过程,直到形心和质心大致重合结束。 这样,最后圆形的窗口会落到像素分布最大的地方,也就是图中的绿色圈,命名为C2。

meanshift算法除了应用在视频追踪当中,在聚类,平滑等等各种涉及到数据以及非监督学习的场合当中均有重要应用,是一个应用广泛的算法。

1.1 算法大致流程

图像是一个矩阵信息,如何在一个视频当中使用meanshift算法来追踪一个运动的物体? 大致流程如下:

  1. 首先在图像上选定一个目标区域
  2. 计算选定区域的直方图分布,一般是HSV色彩空间的直方图。
  3. 对下一帧图像b同样计算直方图分布。
  4. 计算图像b当中与选定区域直方图分布最为相似的区域,使用meanshift算法将选定区域沿着最为相似的部分进行移动,直到找到最相似的区域,便完成了在图像b中的目标追踪。
  5. 重复3到4的过程,就完成整个视频目标追踪。

通常情况下我们使用直方图反向投影得到的图像和第一帧目标对象的起始位置,当目标对象的移动会反映到直方图反向投影图中,meanshift 算法就把我们的窗口移动到反向投影图像中灰度密度最大的区域了。

1.2 直方图反向投影的流程

假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:

  1. 从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
  2. 生成临时图像的直方图;
  3. 用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
  4. 直方图对比结果c,就是结果图像(0,0)处的像素值;
  5. 切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
  6. 重复1~5步直到输入图像的右下角,就形成了直方图的反向投影。

1.3 OpenCV中实现Meanshift的API

cv.meanShift(probImage, window, criteria)

参数:

  • probImage: ROI区域,即目标的直方图的反向投影
  • window: 初始搜索窗口,就是定义ROI的rect
  • criteria: 确定窗口搜索停止的准则,主要有迭代次数达到设置的最大值,窗口中心的漂移值大于某个设定的限值等。

1.4 实现Meanshift的主要流程

  1. 读取视频文件:cv.videoCapture()
  2. 感兴趣区域设置:获取第一帧图像,并设置目标区域,即感兴趣区域
  3. 计算直方图:计算感兴趣区域的HSV直方图,并进行归一化
  4. 目标追踪:设置窗口搜索停止条件,直方图反向投影,进行目标追踪,并在目标位置绘制矩形框。
     

2. Camshift算法

上面的跟踪结果有一个问题,就是检测的窗口的大小是固定的,而狗狗由近及远是一个逐渐变小的过程,固定的窗口是不合适的。所以我们需要根据目标的大小和角度来对窗口的大小和角度进行修正。CamShift可以帮我们解决这个问题。

CamShift算法全称是“Continuously Adaptive Mean-Shift”(连续自适应MeanShift算法),是对MeanShift算法的改进算法,可随着跟踪目标的大小变化实时调整搜索窗口的大小,具有较好的跟踪效果。

Camshift算法首先应用meanshift,一旦meanshift收敛,它就会更新窗口的大小,还会计算最佳拟合椭圆的方向,从而根据目标的位置和大小更新搜索窗口。

Camshift在OpenCV中实现时,只需将上述的meanshift函数(4.4、4.5)改为Camshift函数即可。         

 		#进行camshift追踪
    	ret, track_window = cv.CamShift(dst, track_window, term_crit)
        # 绘制追踪结果
        pts = cv.boxPoints(ret)
        pts = np.int0(pts)
        img2 = cv.polylines(frame,[pts],True, 255,2)

3. 总结

Meanshift和camshift算法都各有优势,自然也有劣势:

Meanshift算法:

原理:一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束。

优缺点:简单,迭代次数少,但无法解决目标的遮挡问题并且不能适应运动目标的的形状和大小变化。

camshift算法:

可适应运动目标的大小形状的改变,具有较好的跟踪效果,但当背景色和目标颜色接近时,容易使目标的区域变大,最终有可能导致目标跟踪丢失。

4. 示例代码

def MeanshiftVideoTrack():

    # 1.获取图像
    cap = cv.VideoCapture("/home/meta/Videos/Screencasts/dog.webm")

    # 2.获取第一帧图像,并指定目标位置
    ret,frame = cap.read()
    #cv.imshow("frame", frame)

    #在opencv中,坐标系的原点位于图片的左上角,但是其X轴为水平向右,Y轴为竖直向下
    # 2.1 目标位置(行,高,列,宽)
    y,h,x,w = 210,190,450,110  
    track_window = (x,y,w,h)
    # 2.2 指定目标的感兴趣区域
    roi = frame[y:y+h, x:x+w]    
    # # 画出感兴趣区域矩形框
    # cv.imshow("roi", roi)    
    # cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 3)  
    # cv.imshow("frame", frame)
    # cv.waitKey(0)

    # 3. 计算直方图
    # 3.1 转换色彩空间(HSV)
    hsv_roi =  cv.cvtColor(roi, cv.COLOR_BGR2HSV)
    # 3.2 去除低亮度的值
    # mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
    # 3.3 计算直方图
    roi_hist = cv.calcHist([hsv_roi],[0],None,[180],[0,180])
    # 3.4 归一化
    cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)

    # 4. 目标追踪
    # 4.1 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
    term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )
    print("*************************")
    while(True):
        # 4.2 获取每一帧图像
        ret ,frame = cap.read()
        if ret == True:
            # 4.3 计算直方图的反向投影
            hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
            dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1)

            # # 4.4 进行meanshift追踪
            # ret, track_window = cv.meanShift(dst, track_window, term_crit)

            # # 4.5 将追踪的位置绘制在视频上,并进行显示
            # x,y,w,h = track_window
            # img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2)         


            # 4.4进行camshift追踪
            ret, track_window = cv.CamShift(dst, track_window, term_crit)
            # 4.5绘制追踪结果
            pts = cv.boxPoints(ret)
            pts = np.int0(pts)
            img2 = cv.polylines(frame,[pts],True, 255,2)

           
            cv.imshow('frame',img2)
            if cv.waitKey(60) & 0xFF == ord('q'):
                break        
        else:
            break
    # 5. 资源释放        
    cap.release()
    cv.destroyAllWindows()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值