一些背景知识:我正在从视频捕获设备(网络摄像头)中读取帧,并使用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 stackoverflow(cv2.cv.CV_CAP_PROP_BUFFERSIZE
)中讨论的常量,但在我安装的python-opencv中似乎不存在常量。
有没有人有这方面的经验可以提供一些有关正在发生的事情的见解?有没有人有他们可以推荐阅读的资源?