OpenCV竟然可以这样学!成神之路终将不远(八)

简介: OpenCV竟然可以这样学!成神之路终将不远(八)

 返回目录

目录

8 性能衡量和提升技术

8.1 目标

8.2 使用OpenCV衡量性能

8.3 OpenCV中的默认优化

8.4 在IPython中衡量性能

8.5 更多IPython魔术命令

8.6 性能优化技术

8.7 其他资源


8 性能衡量和提升技术

8.1 目标

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

    • 衡量代码的性能。
    • 一些提高代码性能的技巧。
    • 你将看到以下功能:cv.getTickCountcv.getTickFrequency等。

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

    8.2 使用OpenCV衡量性能

    cv.getTickCount函数返回从参考事件(如打开机器的那一刻)到调用此函数那一刻之间的时钟周期数。因此,如果在函数执行之前和之后调用它,则会获得用于执行函数的时钟周期数。

    cv.getTickFrequency函数返回时钟周期的频率或每秒的时钟周期数。因此,要找到执行时间(以秒为单位),你可以执行以下操作:

    import cv2 as cv
    e1 = cv.getTickCount()
    # 你的执行代码
    e2 = cv.getTickCount()
    time = (e2 - e1)/ cv.getTickFrequency()

    image.gif

    我们将通过以下示例进行演示。下面的示例应用中位数过滤,其内核的奇数范围为5到49。(不必担心结果会是什么样,这不是我们的目标):

    import cv2 as cv
    img = cv.imread('../girl6/00.jpg')
    start_time = cv.getTickCount()  # 开始时间
    for i in range(5, 49, 2):
        img = cv.medianBlur(img, i)
    end_time = cv.getTickCount()  # 结束时间
    # 将结束时间减去开始时间,再除以频率就得到执行时间
    time = (end_time - start_time) / cv.getTickFrequency()
    print(time)

    image.gif

    我的结果如下:

    0.355942

    image.gif

    注意:你可以使用时间模块执行相同的操作。代替cv.getTickCount,使用time.time()函数。然后取两次相差。

    8.3 OpenCV中的默认优化

    许多 OpenCV 函数都是使用 SSE2、 AVX 等进行优化的。 它还包含未优化的代码。因此,如果我们的系统支持这些特性,我们就应该利用它们(几乎所有现代的处理器都支持它们)。在编译时默认启用它。因此,如果启用了 OpenCV,它将运行优化的代码,否则它将运行未优化的代码。你可以使用 cv.Useoptimized 检查是否启用 / 禁用和cv.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

    image.gif

    官方文档说优化的中值滤波比未优化的版本快2倍,我自己写了一遍,发现并没有快那么多,难道是我电脑有问题?具体代码如下:

    import cv2 as cv
    img = cv.imread('../girl6/02.jpg')
    # 检查是否启用了优化
    optimized_open = cv.useOptimized()
    print('开启(True)/关闭(False)优化效果:{}'.format(optimized_open))  # True
    total = 0
    for i in range(0, 10):
        e1 = cv.getTickCount()
        res = cv.medianBlur(img, 49)
        e2 = cv.getTickCount()
        time = (e2 - e1) / cv.getTickFrequency()
        # print('第{}次时间为:{}s'.format(i, time))
        total += time
    average_10_time = total / 10 * 1000
    print('开启优化连续十次的平均值为:{}ms'.format(average_10_time))
    print('=================================================')
    cv.setUseOptimized(False)  # 关闭优化
    optimized_close = cv.useOptimized()
    print('开启(True)/关闭(False)优化效果:{}'.format(optimized_close))  # False
    total = 0
    for i in range(0, 10):
        e1 = cv.getTickCount()
        res = cv.medianBlur(img, 49)
        e2 = cv.getTickCount()
        time = (e2 - e1) / cv.getTickFrequency()
        # print('第{}次时间为:{}s'.format(i, time))
        total += time
    average_10_time = total / 10 * 1000
    print('关闭优化连续十次的平均值为:{}ms'.format(average_10_time))

    image.gif

    运行结果如下:

    开启(True)/关闭(False)优化效果:True
    开启优化连续十次的平均值为:16.220610000000004ms
    =================================================
    开启(True)/关闭(False)优化效果:False
    关闭优化连续十次的平均值为:15.97507ms

    image.gif

    于是我跟他一样,在ipython中调用,发现也没有快2倍啊,到底是哪里的问题,难道真的是电脑配置太差了吗?

    image.gif编辑

    如果你检查其来源,你可以看到中值滤波是 SIMD 优化。因此,你可以使用它在代码顶部启用优化(请记住,它是默认启用的)

    8.4 在IPython中衡量性能

    有时你可能需要比较两个类似操作的性能。IPython为你提供了一个神奇的命令计时器来执行此操作。它会多次运行代码以获得更准确的结果。同样,它们适用于测量单行代码。

    例如,你知道以下哪个加法运算更好, 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]: %测时 y=x**2
    10000000 loops, best of 3: 73 ns per loop
    In [12]: %测时 y=x*x
    10000000 loops, best of 3: 58.3 ns per loop
    In [15]: z = np.uint8([5])
    In [17]: %测时 y=z*z
    1000000 loops, best of 3: 1.25 us per loop
    In [19]: %测时 y=np.square(z)
    1000000 loops, best of 3: 1.16 us per loop

    image.gif

    我的代码如下:

    image.gif编辑

    你可以看到x = 5; y = x * x最快,比Numpy快20倍左右(我这里只快10倍左右,果然是电脑的问题)。如果你还考虑阵列的创建,它可能会快100倍。酷吧?(大量开发人员正在研究此问题)

    注意:Python标量操作比Numpy标量操作快。因此,对于包含一两个元素的运算,Python标量比Numpy数组好。当数组大小稍大时,Numpy会占优势。

    我们将再尝试一个示例。这次,我们将比较cv.countNonZeronp.count_nonzero对于同一

    张图片的性能。

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

    image.gif

    上面这段代码是opencv官方文档的运行结果,下面这段是我的运行结果。

    注意:这里直接用opencv的countNonZero会报错,网上查阅相关资料,说这里必须转换为灰色图像才行。

    image.gif编辑

    看,OpenCV 函数比 Numpy 函数快近25倍???我这里opencv比numpy快了将近60倍啊。他们换垃圾电脑跑的?

    。。。。。。

    注意:通常,OpenCV函数比Numpy函数要快。因此,对于相同的操作,首选OpenCV功能。但是,可能会有例外,尤其是当Numpy处理视图而不是副本时。

    8.5 更多IPython魔术命令

    还有其他一些魔术命令可以用来测量性能,性能分析,行性能分析,内存测量等。它们都有很好的文档记录。因此,此处仅提供指向这些文档的链接。建议有兴趣的读者尝试一下。

    8.6 性能优化技术

    有几种技术和编码方法可以充分利用 Python 和 Numpy 的最大性能。这里只注明相关信息,并提供重要信息来源的链接。这里要注意的主要事情是,首先尝试以一种简单的方式实现算法。一旦它运行起来,分析它,找到瓶颈并优化它们。

      1. 尽量避免在Python中使用循环,尤其是双/三重循环等。它们本来就很慢。
      2. 由于Numpy和OpenCV已针对向量运算进行了优化,因此将算法/代码向量化到最大程度。
      3. 利用缓存一致性。
      4. 除非需要,否则切勿创建数组的副本。尝试改用视图。数组复制是一项昂贵的操作。

      即使执行了所有这些操作后,如果你的代码仍然很慢,或者不可避免地需要使用大循环,请使用Cython等其他库来使其更快。

      8.7 其他资源


        欢迎评论区留言,一起探讨OpenCV成神之路的奥秘。

        顺便给我加个关注,点个赞,加个收藏,让我们一起登上神坛。

        image.gif编辑


        相关文章
        |
        机器学习/深度学习 编解码 计算机视觉
        OpenCV竟然可以这样学!成神之路终将不远(十六)
        OpenCV竟然可以这样学!成神之路终将不远(十六)
        |
        计算机视觉 Python
        OpenCV竟然可以这样学!成神之路终将不远(十)
        OpenCV竟然可以这样学!成神之路终将不远(十)
        |
        算法 计算机视觉 Python
        OpenCV竟然可以这样学!成神之路终将不远(二十六)
        OpenCV竟然可以这样学!成神之路终将不远(二十六)
        |
        算法 计算机视觉 索引
        OpenCV竟然可以这样学!成神之路终将不远(二十五)
        OpenCV竟然可以这样学!成神之路终将不远(二十五)
        |
        计算机视觉 Python
        OpenCV竟然可以这样学!成神之路终将不远(二十四)
        OpenCV竟然可以这样学!成神之路终将不远(二十四)
        |
        计算机视觉 Python
        OpenCV竟然可以这样学!成神之路终将不远(二十三)
        OpenCV竟然可以这样学!成神之路终将不远(二十三)
        |
        计算机视觉 索引 Python
        OpenCV竟然可以这样学!成神之路终将不远(二十二)
        OpenCV竟然可以这样学!成神之路终将不远(二十二)
        |
        安全 计算机视觉 索引
        OpenCV竟然可以这样学!成神之路终将不远(二十一)
        OpenCV竟然可以这样学!成神之路终将不远(二十一)
        |
        文字识别 计算机视觉 索引
        OpenCV竟然可以这样学!成神之路终将不远(二十)
        OpenCV竟然可以这样学!成神之路终将不远(二十)
        |
        定位技术 计算机视觉 Python
        OpenCV竟然可以这样学!成神之路终将不远(十九)
        OpenCV竟然可以这样学!成神之路终将不远(十九)