前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >opencv(4.5.3)-python(九)--性能度量和优化

opencv(4.5.3)-python(九)--性能度量和优化

作者头像
用户9875047
发布2022-07-04 14:18:30
4610
发布2022-07-04 14:18:30
举报
文章被收录于专栏:机器视觉全栈er机器视觉全栈er

翻译及二次校对:cvtutorials.com

目标

在图像处理中,由于你要每秒处理大量操作,你的代码不仅要提供正确的解决方案,而且要以最快的方式提供,这是必须的。因此,在本章中,你将学习:

  • 测试代码的性能。
  • 一些提高代码性能的技巧。
  • 你会看到这些函数:cv.getTickCount, cv.getTickFrequency,等等。

除了OpenCV之外,Python还提供了一个模块time,这对测量执行时间很有帮助。另一个模块profile有助于获得代码的详细报告,比如代码中每个函数花了多少时间,函数被调用了多少次,等等。但是,如果你使用的是IPython,所有这些功能都以一种用户友好的方式整合在一起。我们将看到一些重要的功能,更多的细节,请查看附加资源部分的链接。

用OpenCV测量性能

cv.getTickCount函数返回一个参考事件(比如机器被打开的那一刻)到这个函数被调用的那一刻之后的时钟周期的数量。因此,如果你在函数执行之前和之后调用它,你可以得到执行一个函数所使用的时钟周期数。

cv.getTickFrequency函数返回时钟周期的频率,或每秒的时钟周期数。所以要找到以秒为单位的执行时间,你可以做以下工作。

代码语言:javascript
复制
e1 = cv.getTickCount()
# your code execution
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()

我们将用下面的例子来证明。下面的例子应用中值滤波,其内核大小从5到49不等。不要担心结果会是什么样子--那不是我们的目标:

代码语言:javascript
复制
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 )
# Result I got is 0.521107655 seconds

你可以用时间模块做同样的事情。不使用cv.getTickCount,而使用time.time()函数。然后取这两个时间的差值。

OpenCV中的默认优化

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

代码语言:javascript
复制
# check if optimization is enabled
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
# Disable it
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优化的。因此,你可以用它来在你的代码顶部启用优化(记住它是默认启用的)。

在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来找出答案。

代码语言:javascript
复制
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倍。如果你也考虑到数组的创建,它可能达到100倍的速度。(Numpy的开发者们正在解决这个问题)。

注意:Python的标量操作要比Numpy的标量操作快。所以对于包括一个或两个元素的操作,Python标量比Numpy数组更好。当数组的大小稍微大一点时,Numpy有优势。

我们将再试一个例子。这一次,我们将比较cv.countNonZero()和np.count_nonzero()对同一图像的性能:

代码语言:javascript
复制
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使用视图而不是拷贝时。

更多的IPython魔法命令

还有其他一些神奇的命令来测量性能、剖析、行剖析、内存测量等等。它们都有很好的文档。所以这里只提供这些文档的链接。建议有兴趣的读者可以尝试一下。

性能优化技术

有几种技术和编码方法可以发挥Python和Numpy的最大性能。这里只指出了相关的技术和方法,并给出了重要来源的链接。这里需要注意的是,首先尝试以一种简单的方式实现算法。一旦它开始工作,对它进行剖析,找到瓶颈,并对其进行优化。

  1. 尽可能避免在Python中使用循环,特别是双倍/三倍循环等。它们本身就很慢。
  2. 尽可能地将算法/代码矢量化,因为Numpy和OpenCV是为矢量操作而优化的。
  3. 利用高速缓存的一致性。
  4. 除非有必要,否则不要对数组进行复制。尽量使用视图来代替。阵列的复制是一个昂贵的操作。

如果你的代码在做完所有这些操作后仍然很慢,或者不可避免地要使用大的循环,请使用额外的库,如Cython,使其更快。

额外的资源

  • Python优化技术
  • Scipy讲义--高级Numpy
  • IPython中的计时和剖析
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器视觉全栈er 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档