在图像处理中,由于每秒要处理大量操作,因此代码不仅必须提供正确的解决方案,而且必须以最快的方式提供。
本章将学习内容如下:
- 衡量代码的性能
- 一些提高代码性能的提示
- 介绍如下函数:
cv2.getTickCount
、cv2.getTickFrequency
等。
除了OpenCV,Python还提供了一个模块时间,这有助于测量执行时间。 另一个模块配置文件有助于获得关于代码的详细报告,比如代码中每个函数花费了多少时间,函数被调用了多少次等。 但是,如果使用的是IPython,所有这些功能都以用户友好的方式集成在一起。 我们将看到一些重要的资源,有关更多详细信息,请查看“扩展阅读”部分中的链接。
使用OpenCV衡量性能
cv2.getTickCount
函数返回从参考事件(如机器打开的时刻)到调用此函数的时刻的时钟周期数。
因此,如果在函数执行前后调用,将获得用于执行函数的时钟周期数。
cv2.getTickFrequency
函数返回时钟周期的频率,或每秒的时钟周期数。
因此,要查找以秒为单位的执行时间,可以执行以下操作:
import cv2
e1 = cv2.getTickCount()
# your code execution
e2 = cv2.getTickCount()
time = (e2 - e1)/ cv2.getTickFrequency()
接下来将通过以下示例进行演示。 以下示例应用中值滤波,其核大小为5到49的奇数。(不要担心结果会是什么样子,这不是我们的目标):
img1 = cv2.imread('/data/cvdata/messi5.jpg')
e1 = cv2.getTickCount()
for i in range(5,49,2):
img1 = cv2.medianBlur(img1,i)
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
t
# Result I got is 0.521107655 seconds
0.910646825
# check if optimization is enabled
cv2.useOptimized()
True
%timeit res = cv2.medianBlur(img1,49)
24.2 ms ± 2.32 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
cv2.setUseOptimized(False)
cv2.useOptimized()
False
%timeit res = cv2.medianBlur(img1,49)
34.1 ms ± 8.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
x = 5
%timeit y=x**2
67.1 ns ± 14.1 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%timeit y=x*x
45.3 ns ± 12.3 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
import numpy as np
z = np.uint8([5])
%timeit y=z*z
955 ns ± 123 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit y=np.square(z)
985 ns ± 202 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
可以看到,x=5;y=x*x
是最快的,与Numpy相比大约快20倍。
如果考虑阵列创建,它可能会快100倍。
注意:
Python标量运算比Numpy标量运算快。因此,对于包含一个或两个元素的操作,Python标量比Numpy数组更好。
当数组的大小稍微大一点时,Numpy会发挥作用。
我们再举一个例子。比较cv2.countNonZero()
和np.count_nonzero()
对同一图像的性能。
# cv2.countNonZero(img1)
# %timeit z = cv2.countNonZero(img1)
%timeit z = np.count_nonzero(img1)
79.9 μs ± 17.8 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
由此可见,OpenCV函数比Numpy函数快近25倍。
注意: 通常,OpenCV函数比Numpy函数快。因此,对于相同的操作,OpenCV函数是首选。 但是,也可能有例外,尤其是当Numpy使用视图而不是副本时。
更多IPython魔术命令
还有其他几个神奇的命令来测量性能、分析、行分析、内存测量等。它们都有很好的记录。 因此,这里只提供了这些文档的链接。有兴趣的读者可以尝试一下。
性能优化技术
有几种技术和编码方法可以利用Python和Numpy的最大性能。 此处仅注明相关内容,并提供重要来源的链接。这里要注意的主要事情是,首先尝试以简单的方式实现算法。 一旦它开始工作,分析它,找到瓶颈并对其进行优化。
- 尽量避免在Python中使用循环,尤其是双/三重循环等。它们天生就很慢。
- 将算法/代码矢量化到最大可能的程度,因为Numpy和OpenCV针对矢量操作进行了优化。
- 利用缓存一致性。
- 除非需要,否则不要复制数组。请尝试使用视图。数组复制是一项成本高昂的操作。
即使在完成所有这些操作后,如果代码仍然很慢,或者不可避免地会使用大循环,请使用Cython等其他库来提高速度。
扩展阅读
- Python优化技术
- Scipy讲义-高级Numpy
- IPython中的时序和性能分析