【Opencv-Python 官方教程】8.性能评估和性能优化技巧


图像处理时,由于每秒都有大量数据操作,所以代码不仅需要得出正确的结果,同时需要追求执行速度,所以本节,将会学到:

  • 评估代码的性能
  • 一些提高代码性能的小建议
  • 将会使用到一些函数,如cv2.getTickCount, cv2.getTickFrequency

除了OpenCV,Python本身也自带time模块也可以提供执行时间的评估。另一个profile模块可以获取代码的详细报告,比如每个函数的时间开销,函数调用次数等。但是如果你使用的时IPython,所有的这些都以一种用户友好的方式被整合了。本节我们将选取一些重要的内容描述,更多的细节,可以阅读最后的附加资源。

原文地址:Performance Measurement and Improvement Techniques


使用OpenCV评估性能

cv2.getTickCount函数返回从某一参考事件发生后(如开机)的时钟数到当前函数调用时刻的时钟数。所以如果在某个函数的调用前后分别调用这个函数,你可以得到这个函数的执行时钟数。

cv2.getTickFrequency函数返回时钟计数频率,即每秒的时钟数,所以如果你需要计算函数执行的时间(秒),你0可以用下面的代码

e1 = cv2.getTickCount()
# your code execution
e2 = cv2.getTickCount()
time = (e2 - e1)/ cv2.getTickFrequency()

我们将会展示下面的例子。下面的例子中,代码执行一个滤波操作,滤波核为5到49之间的所有奇数,采用中值滤波器。(这里不要纠结滤波结果如何,我们仅仅关系我们的目标——评估代码运行时间)

img1 = cv2.imread('messi5.jpg')

e1 = cv2.getTickCount()
for i in xrange(5,49,2):
    img1 = cv2.medianBlur(img1,i)
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print t

# Result I got is 0.521107655 seconds

你可以使用python的time模块做同样额事,但是需要使用函数time.time()获得两个不同的时间。


OpenCV的默认优化

许多OpenCV函数已经采用了SSE2(Streaming SIMD Extensions 2,Intel官方称为SIMD 流技术扩展2或数据流单指令多数据扩展指令集2 )、AVX(Sandy Bridge和Larrabee架构下的新指令集 )等优化方式(总是就是CPU指令集优化方法)。但它同时有不经过优化的代码。如果我们的系统支持这些指令集优化特性,我们应该利用它们(几乎所有的现代处理器都支持它们)。当编译的时候指令集优化是默认可用的,所以OpenCV能以优化方式运行,否则将采用不优化方式运行。可以调用函数cv2.useOptimized()函数检测是否当前opencv以优化方式运行,同时调用cv2.setUesOptimized()方法可以进行优化方案的开关,简单的例子如下

# check if optimization is enabled
In [5]: cv2.useOptimized()
Out[5]: True

In [6]: %timeit res = cv2.medianBlur(img,49)
10 loops, best of 3: 34.9 ms per loop

# Disable it
In [7]: cv2.setUseOptimized(False)

In [8]: cv2.useOptimized()
Out[8]: False

In [9]: %timeit res = cv2.medianBlur(img,49)
10 loops, best of 3: 64.1 ms per loop

可以看到,优化版本的执行速度是未优化版本的两倍,如果你查看它的源代码,你会看到中值滤波器是经过SIMD优化的,所以可以在代码的最开始设置优化方法开启。


通过IPython评估性能

有时你需要比较两个相似操作的性能,IPython提供了一种魔法命令%timeit。它会执行几次代码获得更准确的结果。队医单行代码的测试这很合适。

比如,你像看下面的这些操作哪个更好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]: %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

可见,y=x*x是最快的,比np的方法快了将近20倍。如果考虑到数组的创建,它可能达到100倍。

Python的标量操作会比Numpy的标量操作更快,所以对于一两个元素的操作,Python的标量性能更好,但是当数据为大的数组的时候,Numpy就会更有优势。

我们再来看一个例子,这次,我们比较cv2.countNonZero() 和 np.count_nonzero()两个函数。

In [35]: %timeit z = cv2.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使用数据的原地操作而不是数据副本的时候。


更多的IPython的魔法指令

Ipython还提供了一些其他的魔法指令,用于测试性能,如profiling,line profiling,内存评估等。并且提供了完整的文档,本文最后贴出文档的连接,有兴趣的读者可以去查阅。


性能优化技术

有不少技术和代码方法可以利用Python和Numpy的最大优化。这里仅提供最贴切的方案,链接再下文中给出。主要需要注意的是,首先先用最简单的方案实现一个算法,测试算法工作正常,再去优化它。

  • 在Python中尽量避免使用循环,尤其是多重循环,它们很慢。
  • 尽量使用向量化的代码(和算法),因为Numpy和OpenCV为这些向量操作实现了很好的优化。
  • 利用好缓存。
  • 若无必要,不要为数组创建副本,而是使用它的视图(view,相当于引用实体),数组的拷贝是一种开销非常大的操作。

如果按上述说的做了之后,你的代码还是运行很慢,或者大量的循环不可避免,可以使用类型Cython等额外的库加速代码。


附加资源

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值