繁体   English   中英

如何使用 opencv 和多线程(罗技 c920)在 python 中捕获视频

[英]How to capture video in python with opencv and multithread (logitech c920)

我正在尝试使用 Manjaro XFCE 中的 python3.8 和 opencv(4.2.0) 每 Y 小时捕获一段持续时间为 X 秒的视频。 我想以 720p 或 1080p 的分辨率获得至少 20-30fps。 我使用的是罗技 c920,但分辨率很高(例如 1920x1080),我的堆栈速度为 5fps。 我可以将 fps 设置为 30,但视频会缩短大约 6 倍(python 以 ~5fps 拍摄视频,但将其记录为 30fps)。 因此,为了提高 fps,我应该使用多线程,尽管我无法在我的代码中实现我见过的任何示例。 知道怎么做吗?

这是我的代码:

import numpy as np
import cv2
import time

#choose resolution and fps:

x=1920
y=1080
fps=30

# The duration in seconds of the video captured (s)
capture_duration = 5

# Lapse of time between videos (s), from beginning to beginning
vids_lapse=10

# Name of videos
data_string= time.strftime("%m-%d-%H-%M-%S")

for i in range (0,2): #Let's say I only want to do this process twice, to simplify
    cap = cv2.VideoCapture(2) #my camera is 2, but could be 0
    fourcc = cv2.VideoWriter_fourcc('M','J','P','G')

#set resolution and fps
    cap.set(3,int(x))
    cap.set(4,int(y))
    cap.set(cv2.CAP_PROP_FPS, int(fps))
#set name of video
    out = cv2.VideoWriter(data_string+"_vid"+str(i).zfill(2)+".avi",fourcc, fps, (x,y))
    start_time = time.time()
#start recording for a determined duration
    while( int(time.time() - start_time) < capture_duration+1 ):
        ret, frame = cap.read()
        if ret==True:
            #frame = cv2.flip(frame,0)
            out.write(frame)
            cv2.imshow('frame',frame)
        else:
            break

    cap.release()
    out.release()
    cv2.destroyAllWindows()
#Here I added time.sleep to wait for the next capture
    time.sleep(vids_lapse-capture_duration)

使用上面的代码,我的 30fps 视频比预期的要短,因为它不能超过 ~5fps。

我已经看到我可以使用多线程,并且可以使用以下代码录制 30fps 的视频(至少 ffprobe 是这么说的,尽管我不确定是这样):

from threading import Thread
import cv2, time

#again define resolution and fps
x=1920
y=1080
fps=30

class VideoStreamWidget(object):
    def __init__(self, src=2):
        self.capture = cv2.VideoCapture(src)
        self.capture.set(3,int(x))
        self.capture.set(4,int(y))
        self.capture.set(cv2.CAP_PROP_FPS, int(fps))
        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()
            time.sleep(.03)

    def show_frame(self):
        out.write(self.frame)
        # Display frames in main program
        cv2.imshow('frame', self.frame)
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            out.release()
            cv2.destroyAllWindows()
            exit(1)

if __name__ == '__main__':
    fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
    out = cv2.VideoWriter("output.avi",fourcc, fps, (x,y))
    video_stream_widget = VideoStreamWidget()
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass

这第二个代码的问题是我真的不知道如何引入我的 arguments (记录 5 秒,等待 10 秒,依此类推)或我正在使用多少个线程(我可以从我的相机使用 V4L2 工具,不知道它有多相关)。

所以我的问题是:知道我该怎么做吗? 是否可以合并两个代码? 或者,还有更好的方法?

以下是我检查过的一些指南,但无法使用我的代码: https://www.pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/ https ://github.com/gilbertfrancois/video-capture-async

提前非常感谢!

干杯!

编辑

我终于有事干了。 尽管如此,即使我的视频是 30fps,它仍然看起来像一个 5fps 的视频......似乎所有拍摄的图片都几乎相同......知道如何解决这个问题吗?

这里的代码:

rom threading import Thread, Lock
import cv2, time

#choose resolution
x=1920
y=1080
fps=60

# The duration in seconds of the video captured (s)
capture_duration = 5

# Days
Days=1

# Lapse of time between videos (s), from beginning to beginning
vids_lapse=10

data_string= time.strftime("%m-%d-%H-%M-%S")

class CameraStream(object):
    def __init__(self, src=0):
        self.stream = cv2.VideoCapture(src)
        self.stream.set(3,int(x))
        self.stream.set(4,int(y))
        self.stream.set(cv2.CAP_PROP_FPS,int(fps))
        self.video_file_name = data_string+"_vid"+str(i).zfill(2)+".avi"
        (self.grabbed, self.frame) = self.stream.read()
        self.started = False
        self.read_lock = Lock()
        
        # Set up codec and output video settings
        self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
        self.out = cv2.VideoWriter(self.video_file_name, self.codec, fps, (x, y))

    def start(self):
        if self.started:
            print("already started!!")
            return None
        self.started = True
        self.thread = Thread(target=self.update, args=())
        self.thread.start()
        return self

    def update(self):
        while self.started:
            (grabbed, frame) = self.stream.read()
            self.read_lock.acquire()
            self.grabbed, self.frame = grabbed, frame
            self.read_lock.release()
            # ~ time.sleep(1/fps)

    def read(self):
        self.read_lock.acquire()
        frame = self.frame.copy()
        self.read_lock.release()
        self.save_frame()
        return frame
    
    def save_frame(self):
        # Save obtained frame into video output file
        self.out.write(self.frame)

    def stop(self):
        self.started = False
        self.thread.join()
        self.stream.release()
        self.out.release()

    def __exit__(self, exc_type, exc_value, traceback):
        self.stream.release()


if __name__ == "__main__" :
    for i in range (0,2):
        start_time = time.time()
        cap = CameraStream(0).start()
        while (int(time.time() - start_time) < capture_duration):
            frame = cap.read()
            cv2.imshow('webcam', frame)
            # ~ if cv2.waitKey(1) == 27 :
        cap.stop()
        cv2.destroyAllWindows()
        time.sleep(vids_lapse-capture_duration)

问题在于FOURCC ,你应该设置cv2.CAP_PROP_FOURCC ,试试这个例子:

import cv2

HIGH_VALUE = 10000
WIDTH = HIGH_VALUE
HEIGHT = HIGH_VALUE

capture = cv2.VideoCapture(-1)

capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
capture.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)

width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = capture.get(cv2.CAP_PROP_FPS)

print(width, height, fps)

while True:
    ret, frame = capture.read()
    if ret:
        cv2.imshow('frame', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

capture.release()
cv2.destroyAllWindows()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM