【问题标题】:how to get frames from video in parallel using cv2 & multiprocessing in python如何在 python 中使用 cv2 和多处理从视频中并行获取帧
【发布时间】:2014-11-19 11:31:05
【问题描述】:

我一直在使用 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

这是我当前的代码。我尝试过使用池和单独的进程,但现在我坚持使用单独的进程,因为我不确定问题是否与队列管理有关。如果我手动调用 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()

【问题讨论】:

  • 你得到什么错误?
  • 我认为这是不可能的。
  • 对不起 - 我应该包括结果。我得到了正确数量的帧,但它们都显示为 frameNo 0 和 frame None。 (为什么你认为这是不可能的?)

标签: python multithreading opencv


【解决方案1】:

代码中确实存在错误:跨进程使用相同的VideoCapture 对象。显然文件中当前正在读取的位置存在冲突。

话虽如此,当尝试为每个进程实例化一个 VideoCapture 时,我的解释器崩溃(使用 python3.4.2 + opencv3.0.0-betapython2.7.6 + opencv2.4.8 测试)。如果您想检查它/走得更远,这是我到目前为止的尝试。

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()

【讨论】:

  • 我忘记了,我尝试在主线程上实例化两个 videocapture 对象,但它们似乎也无法很好地读取(尽管没有崩溃)。在他们自己的进程中实例化它们似乎更合乎逻辑,所以这就是我发布的代码。
  • 谢谢 - 我没有意识到这个帖子有新帖子,否则我会早点回复。我想知道这是否可以使用管理器或管理共享内存的东西?现在我决定读入并将图像存储为腌制文件,然后读取腌制文件以节省一点时间。它对短视频没有帮助,但对较长的视频有帮助。
  • 这对我来说适用于 OpenCV 3.3.0 和 Python 2.7.13。两个核心处于满负荷状态,消息确认在两个进程中都读取了帧。
猜你喜欢
  • 2020-06-02
  • 2021-07-17
  • 2016-11-07
  • 1970-01-01
  • 2013-09-28
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 2020-10-18
相关资源
最近更新 更多