2017-04-26 47 views
1

我目前正試圖從一篇論文在Python 2.7上使用OpenCV 3.1實現一個算法,但是這個過程花費的時間太長了。OpenCV 3.1優化

我的代碼,竟然放棄了我麻煩的部分看起來是這樣的:

width, height = mr.shape[:2] 
Pm = [] 
for i in d: 
    M = np.float32([[1,0,-d[i]], [0,1,1]]) 
    mrd = cv2.warpAffine(mr, M, (height,width)) 
    C = cv2.subtract(ml, mrd) 
    C = cv2.pow(C,2) 
    C = np.divide(C, sigma_m) 
    C = p0 + (1-p0)**(-C) 
    Pm.append(C) 

mlmrmrd是CV2對象和dp0sigma_m是整數。

最後3行中的劃分和最終方程是這裏真正的麻煩製造者。這個循環的每一次迭代都是獨立的,所以理論上我可以通過幾個處理器來分割'for循環',但這似乎是一種懶惰的方法,我只是繞過這個問題而不是修復它。

有誰知道更快地執行這些計算的方法嗎?

+0

它也取決於你如何構建OpenCV,所以你可以發佈'getBuildInformation()'的輸出。 –

+0

@MarkSetchell'cv2.getBuildInformation()'的輸出太大而無法在評論中寫入。你是否在想這個輸出的具體內容? – Mira

回答

1

我們可以利用numexpr module有效地執行所有後面的算術運算作爲一個評估表達式。

因此,下列步驟操作:

C = cv2.subtract(ml, mrd) 
C = cv2.pow(C,2) 
C = np.divide(C, sigma_m) 
C = p0 + (1-p0)**(-C) 

可以通過一個表達式替換 -

import numexpr as ne 
C = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 

讓我們確定的事情。原來的做法是FUNC -

def original_app(ml, mrd, sigma_m, p0): 
    C = cv2.subtract(ml, mrd) 
    C = cv2.pow(C,2) 
    C = np.divide(C, sigma_m) 
    C = p0 + (1-p0)**(-C) 
    return C 

驗證 - 整個數據集的大小不同

In [28]: # Setup inputs 
    ...: S = 1024 # Size parameter 
    ...: ml = np.random.randint(0,255,(S,S))/255.0 
    ...: mrd = np.random.randint(0,255,(S,S))/255.0 
    ...: sigma_m = 0.45 
    ...: p0 = 0.56 
    ...: 

In [29]: out1 = original_app(ml, mrd, sigma_m, p0) 

In [30]: out2 = ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 

In [31]: np.allclose(out1, out2) 
Out[31]: True 

計時 -

In [19]: # Setup inputs 
    ...: S = 1024 # Size parameter 
    ...: ml = np.random.randint(0,255,(S,S))/255.0 
    ...: mrd = np.random.randint(0,255,(S,S))/255.0 
    ...: sigma_m = 0.45 
    ...: p0 = 0.56 
    ...: 

In [20]: %timeit original_app(ml, mrd, sigma_m, p0) 
10 loops, best of 3: 67.1 ms per loop 

In [21]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
100 loops, best of 3: 12.9 ms per loop 

In [22]: # Setup inputs 
    ...: S = 512 # Size parameter 

In [23]: %timeit original_app(ml, mrd, sigma_m, p0) 
100 loops, best of 3: 15.3 ms per loop 

In [24]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
100 loops, best of 3: 3.39 ms per loop 

In [25]: # Setup inputs 
    ...: S = 256 # Size parameter 

In [26]: %timeit original_app(ml, mrd, sigma_m, p0) 
100 loops, best of 3: 3.65 ms per loop 

In [27]: %timeit ne.evaluate('p0 +(1-p0)**(-((ml-mrd)**2)/sigma_m)') 
1000 loops, best of 3: 878 µs per loop 

圍繞5x跨越各種尺寸加速與更大的陣列更好的加速!

此外,作爲一個側面說明,我會建議使用初始化數組,而不是像最後一步那樣追加。因此,我們可以在進入循環之前初始化out = np.zeros((len(d), width, height))/np.empty之類的內容,並在最後一步將輸入數組分配到:out[iteration_ID] = C

+0

感謝您的詳細解答。我試着用numexpr快速實現,大約有4倍的加速。 – Mira

+0

@Mira真棒!在大多數情況下很難擊敗'cv2',所以很高興看到'numexpr'給它一個很好的比賽並贏得比賽! – Divakar

+0

關於np.empty()的答案只是一個簡短的問題。我真的不明白你會如何使用它。是不是np.zeros()初始化? 另外,嘗試了np.zeros()方法,並且性能可能會有小的提升,但我們正在談論的是以秒爲單位測量程序的執行時間的差異。任何如何感謝你的建議;) – Mira