OpenCV_003-视频入门

本文主要内容来自于 OpenCV-Python 教程OpenCV 中的 GUI 功能 部分,这个部分的主要内容如下:

目标

从摄像头采集视频

通常,我们必须用摄像头捕捉实时流。OpenCV 提供了一个非常简单的接口来做这些。让我们从摄像头采集一段视频(我使用我笔记本电脑上内置的 webcam),把它转换为灰度视频并显示。只是一个入门的简单任务。

要捕捉视频,我们需要创建一个 VideoCapture 对象。它的参数可以是设备索引或视频文件的文件名。设备索引只是一个用于指定使用那个摄像头的数字。通常连接了一个摄像头(就我而言)。因而,我简单地传入 0 (或 -1)。你可以通过传入 1 选择第二个摄像头等等。随后你可以一帧一帧地捕捉图像。最后,不要忘记释放 capture。

#!/use/bin/env python
import sys

import numpy as np
import cv2 as cv


def main():
    cap = cv.VideoCapture(0)
    if not cap.isOpened():
        print("Cannot open camera")
        sys.exit()

    while True:
        # Capture frame-by-frame
        ret, frame = cap.read()

        # if frame is read correctly ret is True
        if not ret:
            print("Can't receive frame() (stream end?). Exiting ...")
            break
        # Our operations on the frame come here
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        # Display the resulting frame
        cv.imshow('frame', gray)
        if cv.waitKey(1) == ord('q'):
            break

    cap.release()
    cv.destroyAllWindows()


if __name__ == "__main__":
    main()

cap.read() 返回一个布尔值 (True/False)。如果正确地读取了帧,它为 True。因此可以通过检查这个返回值来确认视频是否结束。

有时,cap 可能还没有初始化捕捉。在那种情况下,这段代码将显示错误。我们可以通过 cap.isOpened() 方法检查它是否初始化。如果它是 True,则 OK。否则使用 cap.open() 打开它。

我们还可以使用 cap.get(propId) 方法访问这个视频的一些功能,其中 propId 是一个从 0 到 68 的数字。每个数字表示视频的一个属性(如果它适用于该视频的话)。完整的描述可以在这里找到:cv::VideoCapture::get()。这些值中的一些可以使用 cap.set(propId, value) 来修改。value 是想要的新值。

比如,我们可以通过 cap.get(cv.CAP_PROP_FRAME_WIDTH)cap.get(cv.CAP_PROP_FRAME_HEIGHT) 检查帧的宽度和高度。它默认给出了 640x480。但我们想要把它修改为 320x240。则使用 ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320)ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)。如:

    width = cap.get(cv.CAP_PROP_FRAME_WIDTH)
    height = cap.get(cv.CAP_PROP_FRAME_WIDTH)
    fps = cap.get(cv.CAP_PROP_FPS)
    print("FPS:{}, width x height: {} x {}".format(fps, width, height))

可以得到如下输出:

FPS:30.0, width x height: 640.0 x 640.0

注意:如果遇到了错误,则可以使用任何其它的摄像头应用程序(比如 Linux 下的 Cheese)来确认摄像头是否工作良好。

播放视频文件

播放视频文件与从摄像头采集类似,只是把摄像头索引改为视频文件的文件名。同样在显示视频帧的时候,传入适当的时间调用 cv.waitKey()。如果时间值太低,则视频会非常快,如果它太高,则视频会非常慢(好吧,这就是我们可以慢动作显示视频的方式)。一般情况下 25 毫秒就不错。

def play_video_file():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
    while cap.isOpened():
        ret, frame = cap.read()
        # if frame is read correctly ret is True
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        cv.imshow('frame', gray)
        if cv.waitKey(25) == ord('q'):
            break
    cap.release()
    cv.destroyAllWindows()

cap.get(propId) 可用的 propId 由一些枚举值定义,这其中部分适用于摄像头的 VideoCapture,部分则适用于视频文件的 VideoCapture。对于视频文件,我们可以通过给 cap.get(propId) 传入 cv.CAP_PROP_FRAME_COUNT 获得视频文件的视频帧总数。

注意,请确保安装了适当版本的 ffmpeg 或 gstreamer。有时使用 video capture 比较头疼,这大多数是由于 ffmpeg/gstreamer 的错误安装。

保存视频

我们捕捉了视频,并能一帧一帧地处理它,但我们还想保存视频。对于图像,它很简单:使用 cv.imwrite() 就好。在这里,需要做更多的工作。

这次我们创建一个 VideoWriter 对象。我们应该指定输出文件名(比如:output.avi)。然后我们应该指定 FourCC 码(下一段会有详细说明)。应该传入每秒多少帧 (fps) 以及帧大小。最后一个是 isColor 标记。如果它是 True,则编码器期望是彩色帧,否则,它使用灰度帧。

FourCC 是一个用于指定视频编解码器的 4 字节码。在其官网 fourcc.org 可以找到可用的编解码器的列表。它是平台独立的。以下编解码器对我来说很好用。

  • 在 Fedora 中:DIVX,XVID,MJPG,X264,WMV1,WMV2。(XVID 是更优选的。 MJPG 会产生大尺寸的视频。 X264 提供非常小尺寸的视频)
  • 在 Windows 上:DIVX (更多有待测试和添加)
  • 在 OSX 上:MJPG (.mp4),DIVX (.avi),X264 (.mkv)。

cv.VideoWriter_fourcc('M','J','P','G')cv.VideoWriter_fourcc(*'MJPG') 的形式为 MJPG 传 FourCC
码。

如下的代码从摄像头捕捉图形,在垂直方向翻转每一帧,并保存视频。

def save_video_file():
    cap = cv.VideoCapture(0)
    # Define the codec and create VideoWriter object
    fourcc = cv.VideoWriter_fourcc(*'XVID')
    out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        frame = cv.flip(frame, 0)
        # write the flipped frame
        out.write(frame)
        cv.imshow('frame', frame)
        if cv.waitKey(1) == ord('q'):
            break
    # Release everything if job is finished
    cap.release()
    out.release()
    cv.destroyAllWindows()

Done.

参考文档 Getting Started with Videos

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352