天天看點

【python-opencv】性能衡量和提升技術

在圖像進行中,由于每秒要處理大量操作,是以必須使代碼不僅提供正确的解決方案,而且還必須以最快的方式提供。是以,在本章中,你将學習

  • 衡量代碼的性能。
  • 一些提高代碼性能的技巧。
  • 你将看到以下功能:cv.getTickCount,cv.getTickFrequency等。

除了OpenCV,Python還提供了一個子產品time,這有助于衡量執行時間。另一個子產品profile有助于擷取有關代碼的詳細報告,例如代碼中每個函數花費了多少時間,調用了函數的次數等。但是,如果你使用的是IPython,則所有這些功能都內建在使用者友好的界面中方式。我們将看到一些重要的資訊,有關更多詳細資訊,請檢視“ 其他資源”部分中的連結。

1、使用opencv衡量性能

cv.getTickCount函數傳回從參考事件(如打開機器的那一刻)到調用此函數那一刻之間的時鐘周期數。是以,如果在函數執行之前和之後調用它,則會獲得用于執行函數的時鐘周期數。

cv.getTickFrequency函數傳回時鐘周期的頻率或每秒的時鐘周期數。是以,要找到執行時間(以秒為機關),你可以執行以下操作:

e1 = cv.getTickCount()
# 你的執行代碼
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()      

我們将通過以下示例進行示範。下面的示例應用中位數過濾,其核心的奇數範圍為5到49。(不必擔心結果會是什麼樣,這不是我們的目标):

img1 = cv.imread('messi5.jpg')
e1 = cv.getTickCount()
for i in range(5,49,2):
    img1 = cv.medianBlur(img1,i)
e2 = cv.getTickCount()
t = (e2 - e1)/cv.getTickFrequency()
print( t )
# 我得到的結果是0.521107655秒      

注意 你可以使用時間子產品執行相同的操作。代替cv.getTickCount,使用time.time()函數。然後取兩次相差。

2、opencv的預設優化

許多 OpenCV 函數都是使用 SSE2、 AVX 等進行優化的。 它還包含未優化的代碼。是以,如果我們的系統支援這些特性,我們就應該利用它們(幾乎所有現代的處理器都支援它們)。在編譯時預設啟用它。是以,如果啟用了 OpenCV,它将運作優化的代碼,否則它将運作未優化的代碼。你可以使用 cvUseoptimized 檢查是否啟用 / 禁用和 cvSetuseoptimized 以啟用 / 禁用它。讓我們看一個簡單的例子。

#檢查是否啟用了優化

# 檢查是否啟用了優化
In [5]: cv.useOptimized()
Out[5]: True
In [6]: %timeit res = cv.medianBlur(img,49)
10 loops, best of 3: 34.9 ms per loop
# 關閉它
In [7]: cv.setUseOptimized(False)
In [8]: cv.useOptimized()
Out[8]: False
In [9]: %timeit res = cv.medianBlur(img,49)
10 loops, best of 3: 64.1 ms per loop      

看,優化的中值濾波比未優化的版本快2倍。如果你檢查其來源,你可以看到中值濾波是 SIMD 優化。是以,你可以使用它在代碼頂部啟用優化(請記住,它是預設啟用的)

3、Ipython中衡量性能

有時你可能需要比較兩個類似操作的性能。IPython為你提供了一個神奇的指令計時器來執行此操作。它會多次運作代碼以獲得更準确的結果。同樣,它們适用于測量單行代碼。

例如,你知道以下哪個加法運算更好,

x = 5; y = x**2, x = 5; y = x*x, x = np.uint8([5]); y = x*x

y = np.square(x)

?我們将在IPython shell中使用timeit得到答案。

In [10]: x = 5

In [11]: %測時 y=x**2
10000000 loops, best of 3: 73 ns per loop

In [12]: %測時 y=x*x
10000000 loops, best of 3: 58.3 ns per loop

In [15]: z = np.uint8([5])

In [17]: %測時 y=z*z
1000000 loops, best of 3: 1.25 us per loop

In [19]: %測時 y=np.square(z)
1000000 loops, best of 3: 1.16 us per loop      

你可以看到x = 5; y = x * x最快,比Numpy快20倍左右。如果你還考慮陣列的建立,它可能會快100倍。酷吧?(大量開發人員正在研究此問題)

注意 Python标量操作比Numpy标量操作快。是以,對于包含一兩個元素的運算,Python标量比Numpy數組好。當數組大小稍大時,Numpy會占優勢。

我們将再嘗試一個示例。這次,我們将比較cv.countNonZero和np.count_nonzero對于同一張圖檔的性能。

In [35]: %測時 z = cv.countNonZero(img) 
100000 loops, best of 3: 15.8 us per loop
In [36]: %測時 z = np.count_nonzero(img) 
1000 loops, best of 3: 370 us per loop      

看,OpenCV 函數比 Numpy 函數快近25倍。

注意 通常,OpenCV函數比Numpy函數要快。是以,對于相同的操作,首選OpenCV功能。但是,可能會有例外,尤其是當Numpy處理視圖而不是副本時。

4、性能優化技術

  1. 盡量避免在Python中使用循環,尤其是雙/三重循環等。它們本來就很慢。
  2. 由于Numpy和OpenCV已針對向量運算進行了優化,是以将算法/代碼向量化到最大程度。
  3. 利用緩存一緻性。
  4. 除非需要,否則切勿建立數組的副本。嘗試改用視圖。數組複制是一項昂貴的操作。
  1. Python優化技術:http://wiki.python.org/moin/PythonSpeed/PerformanceTips
  2. Scipy講義- 進階Numpy:http://scipy-lectures.github.io/advanced/advanced_numpy/index.html#advanced-numpy
  3. IPython中的時序和性能分析:http://pynash.org/2013/03/06/timing-and-profiling/