2-3 性能测试和提升技术—OpenCV-Python教程翻译

目标

在图像处理中,因为我们需要每秒中进行大量的算术运算,因此必须在保证代码在可以提供正确结果的同时采用速度更快的方法。因此这一节中,我们需要掌握:

  • 测试代码性能
  • 提示代码性能的一些小技巧
  • 掌握函数cv2.getTickCount, cv2.getTickFrequency等

除了OpenCV外,python还提供了一个time模块用于测量程序执行时间。另一个模块profile用于获取详细的代码报告,比如代码中每一个函数耗费的时间,每一个函数调用的次数等等。

OpenCV测量性能

 cv2.getTickCount函数可以返回一个时钟周期数,这个周期数表示当一个参考事件(比如打开一个开关)发生到这个函数被调用的时刻之间的事件。因此,如果可以在一个函数执行前后调用这个函数,那么就可以获得这个函数执行所需要的时钟周期。

cv2.getTickFrequency函数返回时钟周期的频率,或者是每秒有多少时钟周期。因此如果想获得一个函数执行了多少秒,可以参考下面的代码:

e1 = cv2.getTickCount()
# 你要执行的代码
e2 = cv2.getTickCount()
# 代码前后的时钟数之差除以频率就是代码执行的时间
time = (e2 - e1)/ cv2.getTickFrequency()

下面的代码将展示究竟如何获得执行时间,代码将读入一张照片,对照片进行循环中值滤波,循环对象是卷积核,卷积核从5变化到49。

import cv2 as cv
img1 = cv.imread('messi5.jpg')
e1 = cv.getTickCount()
for i in xrange(5,49,2):
    img1 = cv.medianBlur(img1,i)
e2 = cv.getTickCount()
t = (e2 - e1)/cv.getTickFrequency()
print( t )
# Result I got is 0.521107655 seconds

注意:同样可以使用Python自带的time模块实现上面的功能。函数time.time()可以获得时间,两个时间之差即程序执行时间。

OpenCV默认优化

很多OpenCV函数使用SSE2、AVX等进行优化,但同时包含一些没有优化的代码。我们需要检测自己所使用的系统是否支持执行特征。如果系统支持,OpenCV则运行优化的代码,否则运行没有优化的代码。我们可以使用cv2.useOptimized()检测是否可以支持,也可以使用函数cv2.setUseOptimized()切换支持状态。

# 检测是否支持优化代码
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

可以看到,使用优化代码要比不优化代码快两倍。因此,我们要使用这两个函数确定代码是否在使用优化的代码。

在IPython中测试性能

有时候我们需要对比两个相似操作的性能,在IPython中则可以很好的执行单行代码的测试,使用命令timeit可以将代码进行多次循环从而红的准确的结果。

例如,你能确定x = 5; y = x**2, x = 5; y = x*x, x = np.uint8([5]); y = x*x or y = np.square(x)这四种方法哪一种最好?

In [10]: x = 5
In [11]: %timeit y=x**2
10000000 loops, best of 3: 73 ns per loop
In [12]: %timeit y=x*x
10000000 loops, best of 3: 58.3 ns per loop
In [15]: z = np.uint8([5])
In [17]: %timeit y=z*z
1000000 loops, best of 3: 1.25 us per loop
In [19]: %timeit y=np.square(z)
1000000 loops, best of 3: 1.16 us per loop

结果表明x = 5 ; y = x*x更快,相对于Numpy要快20倍。

注意:python的标量运算要比Numpy的标量运算快。因此,当数据量比较小的时候,使用python进行计算更有合适,只有当数据量比较大时,使用Numpy才凸显优势。

下面我们再展示一个案例,这里我们将对比函数cv2.countNonZero()和np.count_nonzero()对同一张照片进行操作的性能。

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

可见,OpenCV函数要比Numpy函数快接近25倍。

注意:通常,OpenCV函数要比Numpy函数快。因此,对于同一个操作,建议使用OpenCV函数。但是,也会有例外,当使用Numpy函数查看图片而不是复制的时候会更快。

性能优化技术

有很多种技术和编程方法可以发掘python和Numpy的最大性能。这里只推荐一个方法,就是首先试图使用简单方法实现算法。一旦实现功能,再剖析代码,找到瓶颈,之后优化它们。

  • 在python中避免使用循环,尤其是多层循环;
  • 将算法和代码最大可能性的向量化运算,因为Numpy和OpenCV为向量运算进行了优化;
  • 注意缓存一致性;
  • 除非必须,不要复制数组,使用参看代替,因为矩阵复制十分耗时。

如果上面的方法都采用了,但是代码还是很慢,或者要使用大量的循环,可以使用其他的库比如Cython来加速代码。

其他参考

1 Python Optimization Techniques

2 Scipy Lecture Notes - Advanced Numpy

你可能感兴趣的:(图像处理,openCV)