2016-07-05 104 views
4

我是新來的python多處理。我想從每幀長時間的視頻文件中提取功能。處理每個幀的時間大約爲30毫秒。我認爲多處理是一個好主意,因爲每個幀都是獨立處理所有其他幀的。Python中的視頻幀多處理

我想特徵提取的結果存儲在一個自定義類。

我讀了幾個例子,結束了使用多級和隊列的建議here。但結果令人失望,現在每幀需要大約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] 

回答

1

並行處理是一個有點痛:在其他語言中,我們只希望使用線程但GIL使有問題的,並使用多有走動數據一筆大開銷。我發現細粒度並行性(相對)很難做到,而處理在單個進程中花費10秒(或更多)的工作量的「塊」可以更直接。

並行處理您的問題的一個更簡單的途徑 - 如果您在UNIXy系統上 - 將是製作一個python程序,用於處理在命令行中指定的一段視頻(例如,開頭的幀號,和多個要處理的幀),然後使用GNU parallel工具一次處理多個段。第二個Python程序可以合併來自文件集合的結果,或者從標準輸入讀取,從parallel傳送。這意味着處理代碼不需要做它自己的並行處理,但它確實需要對輸入文件進行多次訪問並從中點開始提取幀。 (這也可以擴展到在不改變python的情況下在多臺機器上工作......)

如果您需要一個純粹的python解決方案,可以使用multiprocessing.Pool.map:通過元組列表(例如, (file, startframe, endframe)),然後打開該功能中的文件並處理該段。

+0

我在Windows系統上。我想給chunck處理一個嘗試,但我卡住管理從多個進程的視頻文件的訪問。只是簡單地讓每個進程試圖通過openCV來讀取幀,使python掛起。 – jlarsch

+1

我建議不定期地測試一下。製作一個腳本,用於處理視頻的一部分並檢查它的工作原理(無需在任何地方使用多處理器)。然後嘗試在同一時間運行兩次(即使它們正在處理文件的相同部分),以檢查從輸入文件中讀取多個進程沒有問題。除非有什麼東西在鎖定文件或以其他方式阻止對它的讀取訪問,否則應該沒問題,但值得單獨檢查。然後,最後,擴展腳本以使用多處理。這應該有助於隔離哪裏和爲什麼它掛! – Wuggy

+0

我剛剛發現我可以同時從多個進程讀取同一個視頻文件。看起來問題是,將太大的變量傳入隊列會凍結我的python。我想知道是否有一個參數需要改變隊列大小?或者返回值的另一種方法? – jlarsch

1

多處理爲啓動幾個進程並將它們全部重新組合起來創建了一些開銷。

您的代碼確實,每一個幀

嘗試將您的視頻分成N個大小相同的部分,並將它們並行處理

n放在等於你的機器或類似的東西上的核心數量(您的里程可能會有所不同,但它是一個很好的號碼,開始與試驗)。如果有4個程序正在執行,而其他程序正在等待輪到他們,那麼創建50個進程是毫無意義的。在(常規)蟒蛇

+0

我的建議的問題是,它將需要讀取每個進程內的幀,並崩潰我的python。我認爲這已經描述過了:http://stackoverflow.com/questions/27015792/how-to-get-frames-from-video-in-parallel-using-cv2-multiprocessing-in-python?rq=1 – jlarsch

+0

如何在主進程中讀取與RAM相同數量的幀,然後將這些幀分成N塊並並行處理,漂洗,重複? – Daerdemandt