简体   繁体   English

如何在python中使用cv2和多处理并行获取视频帧

[英]how to get frames from video in parallel using cv2 & multiprocessing in python

I've been working with cv2 & multiprocessing in python, and I finally have a working script that does stuff to the individual frames once they are already in an input queue. 我一直在python中使用cv2和多处理,最后我有一个工作脚本,一旦它们已经在输入队列中就会对各个帧进行处理。 However, I wanted to speed up getting the frames into the queue in the first place by using multiple cores, so I tried to use the same multiprocessing approach to read each image into the queue. 但是,我想通过使用多个核心来加速将帧放入队列,因此我尝试使用相同的多处理方法将每个图像读入队列。 I can't seem to get this to work though, and I'm not sure why. 我似乎无法让它工作,我不知道为什么。 I thought maybe it was because I was trying to write to one queue, so I split those up, but now I'm wondering if it's because I'm trying to read from the same video file at the same time. 我想也许是因为我试图写入一个队列,所以我把它们分开了,但现在我想知道是不是因为我试图同时从同一个视频文件中读取。

Here is what I am hoping to accomplish in pseudocode: 这是我希望在伪代码中完成的事情:

for process in range(processCount):
    start a process that does this:
        for frame in range(startFrame,endFrame):
            set next frame to startFrame
            read frame
            add frame to queue

Here is my current code. 这是我目前的代码。 I've tried using pool & separate processes, but for now I'm sticking to separate processes because I'm not sure if the problem is with queue management. 我已经尝试过使用池和单独的进程,但是现在我坚持使用单独的进程,因为我不确定问题是否与队列管理有关。 If I call getFrame manually, I get the right stuff into the queue, so I think that function by itself works okay. 如果我手动调用getFrame,我会将正确的东西放入队列中,所以我认为该函数本身可以正常工作。

I'm sure I'm doing something really silly (or really odd). 我确定我做的事情真的很傻(或者很奇怪)。 Can someone suggest a solution? 有人可以提出解决方案吗? It would be great to just have one queue as well... I just had two to try to break down the problem. 只有一个队列也很棒......我只有两个试图解决问题。

Thanks in advance. 提前致谢。

import numpy as np
import cv2
import multiprocessing as mp
import time

def getFrame(queue, startFrame, endFrame):
    for frame in range(startFrame, endFrame):
        cap.set(1,frame)
        frameNo = int(cap.get(0))
        ret, frame = cap.read()
        queue.put((frameNo,frame))

file = 'video.mov'
cap = cv2.VideoCapture(file)
fileLen = int(cap.get(7))

# get cpuCount for processCount
processCount = mp.cpu_count()/3

inQ1 = mp.JoinableQueue()  # not sure if this is right queue type, but I also tried mp.Queue()
inQ2 = mp.JoinableQueue()
qList = [inQ1,inQ2]

# set up bunches
bunches = []
for startFrame in range(0,fileLen,fileLen/processCount):
    endFrame = startFrame + fileLen/processCount
    bunches.append((startFrame,endFrame))

getFrames = []
for i in range(processCount):
    getFrames.append(mp.Process(target=getFrame, args=(qList[i], bunches[i][0],bunches[i][1],)))

for process in getFrames:
    process.start()

results1 = [inQ1.get() for p in range(bunches[0][0],bunches[0][1])]
results2 = [inQ2.get() for p in range(bunches[1][0],bunches[1][1])]

inQ1.close()
inQ2.close()
cap.release()

for process in getFrames:
    process.terminate()
    process.join()

There is indeed a mistake in the code : the use of the same VideoCapture object across processes. 代码确实存在错误:跨进程使用相同的VideoCapture对象。 Obviously there's a conflict on the position currently being read in the file. 显然,当前正在文件中读取的位置存在冲突。

This being said, when trying to instantiate one VideoCapture per process, my interpreter crashes (tested with python3.4.2 + opencv3.0.0-beta , and python2.7.6 + opencv2.4.8 ). python3.4.2 ,当我尝试在每个进程中实例化一个VideoCapture时,我的解释器崩溃了(用python3.4.2 + opencv3.0.0-betapython2.7.6 + opencv2.4.8 )。 Here's my try so far if you want to check it / go further. 这是我到目前为止的尝试,如果你想检查它/进一步。

import cv2
import multiprocessing as mp

def getFrame(queue, startFrame, endFrame):
    cap = cv2.VideoCapture(file)  # crashes here
    print("opened capture {}".format(mp.current_process()))
    for frame in range(startFrame, endFrame):
        # cap.set(cv2.CAP_PROP_POS_FRAMES, frame)  # opencv3            
        cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frame)
        # frameNo = int(cap.get(cv2.CAP_PROP_POS_FRAMES))  # opencv3
        frameNo = int(cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES))
        ret, f = cap.read()
        if ret:
            print("{} - put ({})".format(mp.current_process(), frameNo))
            queue.put((frameNo, f))
    cap.release()

file = "video.mov"
capture_temp = cv2.VideoCapture(file)
# fileLen = int((capture_temp).get(cv2.CAP_PROP_FRAME_COUNT))  # opencv3
fileLen = int((capture_temp).get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))
capture_temp.release()

# get cpuCount for processCount
# processCount = mp.cpu_count() / 3
processCount = 2

inQ1 = mp.JoinableQueue()  # not sure if this is right queue type, but I also tried mp.Queue()
inQ2 = mp.JoinableQueue()
qList = [inQ1, inQ2]

# set up bunches
bunches = []
for startFrame in range(0, fileLen, int(fileLen / processCount)):
    endFrame = startFrame + int(fileLen / processCount)
    bunches.append((startFrame, endFrame))

getFrames = []
for i in range(processCount):
    getFrames.append(mp.Process(target=getFrame, args=(qList[i], bunches[i][0], bunches[i][1])))

for process in getFrames:
    process.start()

results1 = [inQ1.get() for p in range(bunches[0][0], bunches[0][1])]
results2 = [inQ2.get() for p in range(bunches[1][0], bunches[1][1])]

inQ1.close()
inQ2.close()

for process in getFrames:
    process.terminate()
    process.join()

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

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