python中视频帧的多处理

python中视频帧的多处理,python,multiprocessing,Python,Multiprocessing,我不熟悉python中的多处理。我想从每一帧长达一小时的视频文件中提取特征。处理每一帧需要30毫秒。我认为多重处理是个好主意,因为每一帧的处理独立于所有其他帧 我想将特征提取的结果存储在自定义类中 我阅读了一些示例,最后按照建议使用了多处理和队列。虽然结果令人失望,但现在每帧处理大约需要1000毫秒。我猜我制造了一吨的开销 有没有更有效的方法来并行处理帧并收集结果 为了举例说明,我放了一个虚拟示例 import multiprocessing as mp from multiprocessing

我不熟悉python中的多处理。我想从每一帧长达一小时的视频文件中提取特征。处理每一帧需要30毫秒。我认为多重处理是个好主意,因为每一帧的处理独立于所有其他帧

我想将特征提取的结果存储在自定义类中

我阅读了一些示例,最后按照建议使用了多处理和队列。虽然结果令人失望,但现在每帧处理大约需要1000毫秒。我猜我制造了一吨的开销

有没有更有效的方法来并行处理帧并收集结果

为了举例说明,我放了一个虚拟示例

import multiprocessing as mp
from multiprocessing import Process, Queue
import numpy as np
import cv2

def main():
    #path='path\to\some\video.avi'
    coordinates=np.random.random((1000,2))
    #video = cv2.VideoCapture(path)
    listOf_FuncAndArgLists=[]

    for i in range(50):
        #video.set(cv2.CAP_PROP_POS_FRAMES,i)
        #img_frame_original = video.read()[1]
        #img_frame_original=cv2.cvtColor(img_frame_original, cv2.COLOR_BGR2GRAY)
        img_frame_dummy=np.random.random((300,300)) #using dummy image for this example
        frame_coordinates=coordinates[i,:]
        listOf_FuncAndArgLists.append([parallel_function,frame_coordinates,i,img_frame_dummy])

    queues=[Queue() for fff in listOf_FuncAndArgLists] #create a queue object for each function
    jobs = [Process(target=storeOutputFFF,args=[funcArgs[0],funcArgs[1:],queues[iii]]) for iii,funcArgs in enumerate(listOf_FuncAndArgLists)]
    for job in jobs: job.start() # Launch them all
    for job in jobs: job.join() # Wait for them all to finish
    # And now, collect all the outputs:
    return([queue.get() for queue in queues])         

def storeOutputFFF(fff,theArgs,que): #add a argument to function for assigning a queue
    print 'MULTIPROCESSING: Launching %s in parallel '%fff.func_name
    que.put(fff(*theArgs)) #we're putting return value into queue

def parallel_function(frame_coordinates,i,img_frame_original):
    #do some image processing that takes about 20-30 ms
    dummyResult=np.argmax(img_frame_original)
    return(resultClass(dummyResult,i))

class resultClass(object):
    def __init__(self,maxIntensity,i):
        self.maxIntensity=maxIntensity
        self.i=i

if __name__ == '__main__':
    mp.freeze_support()
    a=main()
    [x.maxIntensity for x in a]

多处理会为启动多个进程并将它们重新组合在一起带来一些开销

您的代码对每一帧都执行此操作

尝试将视频分割成N个大小均匀的片段,并并行处理它们

将N等于机器上的核心数或类似的数字(您的里程数可能会有所不同,但这是一个很好的开始试验的数字)。如果(比如)其中4个进程正在执行,而其余进程只是在等待轮到它们,那么创建50个进程是没有意义的。

在(常规)python中的并行处理有点麻烦:在其他语言中,我们只使用线程,但GIL会造成问题,而使用多处理在移动数据时会有很大的开销。我发现细粒度并行性(相对而言)很难实现,而在单个进程中处理需要10秒(或更多)时间的“大块”工作可能更直接

如果您使用的是UNIXy系统,并行处理您的问题的一个更简单的方法是制作一个python程序,该程序处理命令行上指定的一段视频(即开始时的帧数和要处理的帧数),然后使用该工具一次处理多段视频。第二个python程序可以合并文件集合的结果,或者从
parallel
管道读取stdin。这种方式意味着处理代码不需要自己进行并行处理,但它确实需要对输入文件进行多次访问,并从中点开始提取帧。(这也可以扩展到跨多台机器工作,而无需更改python…)


如果您需要纯python解决方案,可以以类似的方式使用
multiprocessing.Pool.map
:映射元组列表(例如,
(file,startframe,endframe)
)然后打开函数中的文件并处理该段。

我对该建议的问题是,它需要读取每个进程中的帧,这会使我的python崩溃。我想这已经被描述过了:在主进程中读取RAM允许的尽可能多的帧,然后将这些帧分割成N个块并并行处理,冲洗,重复?我在Windows系统上。我想尝试一下chunck处理,但我在管理多个进程对视频文件的访问时遇到了困难。只要让每个进程尝试通过openCV读取帧,python就会挂起。我建议以增量方式进行测试。制作一个脚本来处理视频片段,并检查它是否工作(在任何地方都不使用多处理)。然后尝试同时运行两次(即使它们正在处理文件的同一部分),以检查多个进程读取输入文件是否没有问题。除非有什么东西正在锁定文件或以其他方式阻止对它的读取访问,否则这应该很好,但值得单独检查。然后,最后,扩展脚本以使用多处理。这将有助于隔离它悬挂的位置和原因!我刚刚发现我可以同时从多个进程读取同一个视频文件。问题似乎在于将太大的变量传递到队列中会冻结python。我想知道是否有一个参数可以更改队列大小?或者是返回值的另一种方法?看起来解决这个问题的方法是在主函数中省略上面的join命令,正如文档中“使用队列的连接进程”中所指出的:好点!我尽量避免在多处理中使用较低级别的东西,而是尝试使用
multiprocessing.Pool.map
…map\u async
方法。当我不得不直接使用
进程
队列
时,我创建了自己的
类,并通过向工作进程发送一个特定的“终止”命令来处理清理,然后让它们退出。然后,
Process.join()
实际上是清理过程中的最后一件事,因为知道它们将退出(或者很快就会退出)。