第一个视频帧有很大的延迟(python opencv)

时间:2017-07-07 19:25:01

标签: python-2.7 opencv webcam video-capture beagleboard

一些背景知识:我正在从视频捕获设备(网络摄像头)中读取帧,并使用Python中的OpenCV将其写入视频文件(out.avi)。我编写的脚本是从Node.js进程调用的,所以我可以开始录制视频以响应节点中发生的任何事情。

我正在使用Python 2.7,并且从aptitude包repos在Ubuntu上安装了OpenCV,所以我不确定它是什么版本,或者它的重要性。

这是我写的脚本:

#!/usr/bin/env python

# adapted from https://stackoverflow.com/questions/32943227/python-opencv-capture-images-from-webcam

from __future__ import print_function
from datetime import datetime
from cvDebug import CvDebug
import argparse
import json
import sys
import cv2

# TODO allow storing to a directory (prepended with date or not) --- TWW
parser = argparse.ArgumentParser(description='record and save a camera video')
parser.add_argument('-d', '--debug', action='store_true', help='turn on debugging')
parser.add_argument('-c', '--camera', type=int, default=0, help='camera number for recording the video')
parser.add_argument('-o', '--out', type=str, default='out.avi', help='name of the output-file')
parser.add_argument('-f', '--fps', type=int, default=10, help='frames per second for output video')
parser.add_argument('-l', '--length', type=int, default=1, help='length of time to record video in seconds')
parser.add_argument('-W', '--width', type=int, default=640, help='width of the image')
parser.add_argument('-H', '--height', type=int, default=480, help='height of the image')
parser.add_argument('-D', '--prepend-date', action='store_true')
parser.add_argument('-T', '--prepend-time', action='store_true')
parser.add_argument('--codec', type=str, default='XVID', help='codec to use when writing video')
# TODO argument to separate out image capture --- TWW
args = parser.parse_args(sys.argv[1:])

now = datetime.now()

if args.prepend_time is True:
    args.out = '{0}_{1}'.format(now.time().strftime('%H%M%S'), args.out)

if args.prepend_date is True:
    args.out = '{0}_{1}'.format(now.today().strftime('%Y%m%d'), args.out)

d = CvDebug(args.debug)


def main():
    # capture from camera at location 0
    d.time('opening camera', args.camera)
    cap = cv2.VideoCapture(args.camera)

    if not cap.isOpened():
        print('opening camera failed')
        cap.release()
        exit(1)

    d.time('setting width and height')
    cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, args.width)
    cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, args.height)

    # Change the camera setting using the set() function
    # cap.set(cv2.cv.CV_CAP_PROP_EXPOSURE, -6.0)
    # cap.set(cv2.cv.CV_CAP_PROP_GAIN, 4.0)
    # cap.set(cv2.cv.CV_CAP_PROP_BRIGHTNESS, 144.0)
    # cap.set(cv2.cv.CV_CAP_PROP_CONTRAST, 27.0)
    # cap.set(cv2.cv.CV_CAP_PROP_HUE, 13.0) # 13.0
    # cap.set(cv2.cv.CV_CAP_PROP_SATURATION, 28.0)

    # Read the current setting from the camera
    # test = cap.get(cv2.cv.CV_CAP_PROP_POS_MSEC)
    # d.log('Test:', test)
    # ratio = cap.get(cv2.cv.CV_CAP_PROP_POS_AVI_RATIO)
    # d.log('Ratio:', ratio)
    # frame_rate = cap.get(cv2.cv.CV_CAP_PROP_FPS)
    # d.log('Frame Rate:', frame_rate)
    height = cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)
    d.log('Height:', height)
    width = cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
    d.log('Width:', width)
    brightness = cap.get(cv2.cv.CV_CAP_PROP_BRIGHTNESS)
    d.log('Brightness:', brightness)
    contrast = cap.get(cv2.cv.CV_CAP_PROP_CONTRAST)
    d.log('Contrast:', contrast)
    saturation = cap.get(cv2.cv.CV_CAP_PROP_SATURATION)
    d.log('Saturation:', saturation)
    # hue = cap.get(cv2.cv.CV_CAP_PROP_HUE)
    # d.log('Hue:', hue)
    # gain = cap.get(cv2.cv.CV_CAP_PROP_GAIN)
    # d.log('Gain:', gain)
    # exposure = cap.get(cv2.cv.CV_CAP_PROP_EXPOSURE)
    # d.log('Exposure:', exposure)

    d.time('opening video container', args.out)
    d.log('codec {0}, fps {1}, geo {2}x{3}'.format(args.codec, args.fps, width, height))
    vid = cv2.VideoWriter(args.out, cv2.cv.CV_FOURCC(*args.codec), args.fps, (int(width), int(height)), True)
    d.time('container opened')

    if not vid.isOpened():
        print('opening video container failed')
        cap.release()
        vid.release()
        d.destroy_image_windows()
        exit(1)

    exit_code = 0
    image_count = args.fps * args.length

    while image_count > 0:
        ret, img = cap.read()
        if ret:
            vid.write(img)
            d.time('frame', args.fps * args.length - image_count, 'written')
        else:
            exit_code = 1
            print('frame', args.fps * args.length - image_count, 'failed')
        image_count -= 1

    print(json.dumps({"file": args.out}))
    d.time('releasing capture & video container')
    cap.release()
    vid.release()
    d.time('released')
    d.destroy_image_windows()
    exit(exit_code)


if __name__ == '__main__':
    main()

当我使用我的三星R580内置网络摄像头以python script.py -d运行时,我得到以下输出:

[0.000 s][Δ 0.000 s] opening camera 0
[0.151 s][Δ 0.151 s] setting width and height
Height: 480.0
Width: 640.0
Brightness: 0.850000023842
Contrast: 0.649999976158
Saturation: 0.600000023842
[0.173 s][Δ 0.022 s] opening video container out.avi
codec XVID, fps 10, geo 640.0x480.0
[0.189 s][Δ 0.016 s] container opened
[2.353 s][Δ 2.163 s] frame 0 written
[2.437 s][Δ 0.085 s] frame 1 written
[2.528 s][Δ 0.091 s] frame 2 written
[2.618 s][Δ 0.090 s] frame 3 written
[2.713 s][Δ 0.095 s] frame 4 written
[2.804 s][Δ 0.091 s] frame 5 written
[2.892 s][Δ 0.088 s] frame 6 written
[2.985 s][Δ 0.094 s] frame 7 written
[3.076 s][Δ 0.091 s] frame 8 written
[3.168 s][Δ 0.092 s] frame 9 written
{"file": "out.avi"}
[3.169 s][Δ 0.000 s] releasing capture & video container
[3.196 s][Δ 0.028 s] released

注意第一帧的检索时间超过2秒!但是接下来的帧大约每0.091秒就会出现一次。我不确定如何解释这种行为。

此外,我购买了一个不同的网络摄像头(Logitech C920为recommended by Derek Molloy),它肯定加快了第一帧的捕获速度。在我的笔记本电脑上,它的速度非常快,但是在beagleboard上第一帧仍然需要0.7-1.0秒(并且每个连续帧的时间约为0.2秒)。帧速率是可以接受的,但我基本上希望最小化脚本开始后开始录制所需的时间。

我尝试使用this stackoverflowcv2.cv.CV_CAP_PROP_BUFFERSIZE)中讨论的常量,但在我安装的python-opencv中似乎不存在常量。

有没有人有这方面的经验可以提供一些有关正在发生的事情的见解?有没有人有他们可以推荐阅读的资源?

0 个答案:

没有答案