OpenCV(Python3)_8(程序性能检测及其优化)

目标

在图像处理中,由于您每秒都要进行大量的运算,所以您的代码不仅要提供正确的结果,同时还必须要快。所以在本章中,你将学习

除了OpenCV,Python还提供了一个有助于测量执行时间的模块time另一个模块profile有助于获得有关代码的详细报告,例如代码中每个函数占用了多少时间,函数被调用了多少次等等。但是,如果您使用的是IPython,则所有这些功能都集成在一个用户友好方式。我们会看到一些重要的内容,有关更多详细信息,请查看其他资源部分中的链接

用OpenCV测量性能

cv.getTickCount函数返回从参考点到调用此函数时,被执行的时钟数。所以如果你在一个函数执行前后调用它,你会得到用于执行这个函数的时钟周期数。

cv.getTickFrequency函数返回时钟周期的频率或每秒钟的时钟周期数。因此,您可以按照下面的方式得到一个函数运行了多少秒:

程序:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

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

print(time)

我们将用下面的例子来演示。以下示例应用中值滤波,奇数大小的内核范围为5至49.(不要担心结果如何,这不是我们的目标):

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img1 = cv.imread('lena.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 )

注意你可以用time模块实现上述功能。使用time.time()函数而不是cv.getTickCount。可以比较下两者的区别。

OpenCV中的默认优化

OpenCV很多函数都使用SSE2,AVX等了进行优化。当然它也包含了一些未优化的代码。所以如果我们的系统支持这些优化的话,我们应该利用它们(几乎所有的现代处理器都支持它们)。编译时优化是默认启用的。因此,OpenCV运行的就是优化后的代码,否则它会运行未优化的代码。您可以使用cv.useOptimized()检查优化是否启用,并使用cv.setUseOptimized()启用/禁用它。我们来看一个简单的例子。

程序:

print(cv.useOptimized())
cv.setUseOptimized(False)
print(cv.useOptimized())

带有%等是Ipython专有的命令。

测量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

你可以看到,x = 5; 与Numpy相比,y = x * x是最快的,速度约快20倍。如果您考虑创建数组,它可能会快达100倍。很酷,对吧?*(Numpy开发者正在处理这个问题)*

注意
Python标量操作比Numpy标量操作更快。因此对于包含一个或两个元素的操作,Python标量比Numpy数组要好。当数组的大小稍大一点时,Numpy就会占上风。

我们将再尝试一个例子。这一次,我们将比较同一图像cv.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功能是首选。But, there can be exceptions, especially when Numpy works with views instead of copies.

更多IPython魔术命令

还有其他几个魔术命令来检测程序的效率,profiling,line profiling,内存使用等。它们都有详细记录。所以这里只提供那些文档的链接。建议有兴趣的读者试用一下。

性能优化技术

有几种技术和编码方法可以发挥Python和Numpy的最高性能。这里只注明相关的内容,并将链接提供给重要来源。这里要注意的主要问题是:首先尝试以简单的方式实现算法。当他正常工作后,再使用上面提高的方法找到程序的瓶颈,并优化它们。

  1. 尽可能避免在Python中使用循环,特别是二/三循环等。它们本质上很慢。
  2. 因为Numpy和OpenCV针对向量操作进行了优化,所以可以尽可能地向最大程度地矢量化算法/代码。
  3. 利用缓存一致性。
  4. 除非需要,否则不要复制阵列的副本。尝试使用视图(Views)代替,阵列复制是一项代价高昂的操作。

即使在完成所有这些操作之后,如果代码仍然很慢,或者使用大循环是不可避免的,请使用Cython等其他库来加快速度。

其他资源

  1. Python Optimization Techniques
  2. Scipy Lecture Notes - Advanced Numpy
  3. Timing and Profiling in IPython

猜你喜欢

转载自blog.csdn.net/qq_27806947/article/details/80740180
今日推荐