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

ano*_*its 6 python multithreading opencv

我一直在 python 中使用 cv2 和多处理,我终于有了一个工作脚本,一旦各个帧已经在输入队列中,它就会对它们进行处理。但是,我想首先通过使用多个核心来加快将帧放入队列的速度,因此我尝试使用相同的多处理方法将每个图像读入队列。但我似乎无法让它发挥作用,我也不知道为什么。我想也许是因为我试图写入一个队列,所以我将它们分开,但现在我想知道这是否是因为我试图同时读取同一个视频文件。

这是我希望用伪代码完成的事情:

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
Run Code Online (Sandbox Code Playgroud)

这是我当前的代码。我尝试过使用池和单独的进程,但现在我坚持使用单独的进程,因为我不确定问题是否出在队列管理上。如果我手动调用 getFrame,我会将正确的内容放入队列中,所以我认为该函数本身可以正常工作。

我确信我正在做一些非常愚蠢(或者非常奇怪)的事情。有人可以提出解决方案吗?如果也只有一个队列就太好了……我只有两个队列来尝试解决问题。

提前致谢。

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()
Run Code Online (Sandbox Code Playgroud)

Arn*_*d P 2

代码中确实有一个错误:\xc2\xa0VideoCapture跨进程使用同一个对象。显然文件中当前读取的位置存在冲突。

\n\n

话虽这么说,当尝试为每个进程实例化一个 VideoCapture 时,我的解释器崩溃(使用python3.4.2+opencv3.0.0-betapython2.7.6+进行测试opencv2.4.8)。如果您想检查/进一步了解,这是我迄今为止的尝试。

\n\n
import cv2\nimport multiprocessing as mp\n\ndef getFrame(queue, startFrame, endFrame):\n    cap = cv2.VideoCapture(file)  # crashes here\n    print("opened capture {}".format(mp.current_process()))\n    for frame in range(startFrame, endFrame):\n        # cap.set(cv2.CAP_PROP_POS_FRAMES, frame)  # opencv3            \n        cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frame)\n        # frameNo = int(cap.get(cv2.CAP_PROP_POS_FRAMES))  # opencv3\n        frameNo = int(cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES))\n        ret, f = cap.read()\n        if ret:\n            print("{} - put ({})".format(mp.current_process(), frameNo))\n            queue.put((frameNo, f))\n    cap.release()\n\nfile = "video.mov"\ncapture_temp = cv2.VideoCapture(file)\n# fileLen = int((capture_temp).get(cv2.CAP_PROP_FRAME_COUNT))  # opencv3\nfileLen = int((capture_temp).get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))\ncapture_temp.release()\n\n# get cpuCount for processCount\n# processCount = mp.cpu_count() / 3\nprocessCount = 2\n\ninQ1 = mp.JoinableQueue()  # not sure if this is right queue type, but I also tried mp.Queue()\ninQ2 = mp.JoinableQueue()\nqList = [inQ1, inQ2]\n\n# set up bunches\nbunches = []\nfor startFrame in range(0, fileLen, int(fileLen / processCount)):\n    endFrame = startFrame + int(fileLen / processCount)\n    bunches.append((startFrame, endFrame))\n\ngetFrames = []\nfor i in range(processCount):\n    getFrames.append(mp.Process(target=getFrame, args=(qList[i], bunches[i][0], bunches[i][1])))\n\nfor process in getFrames:\n    process.start()\n\nresults1 = [inQ1.get() for p in range(bunches[0][0], bunches[0][1])]\nresults2 = [inQ2.get() for p in range(bunches[1][0], bunches[1][1])]\n\ninQ1.close()\ninQ2.close()\n\nfor process in getFrames:\n    process.terminate()\n    process.join()\n
Run Code Online (Sandbox Code Playgroud)\n