使用numba加速opencvpython视频流代码。提升6.5倍性能(代码片段)

__弯弓__ __弯弓__     2023-03-02     275

关键词:

使用Numba对OpenCV Python视频处理代码加速。性能提升6.5倍

目标问题:

在 OpenCV Python 中视频处理是比较耗资源的,从而造成画面卡顿,如果跳帧处理可能造成丢失关键数据。用 Numba对 OpenCV代码加速是1个较好的改进方法。只须加入简单的导入与函数装饰器代码即可,非常方便。
实际效果如何呢? 本文将通过实例代码来比较,对于 OpenCV显示与处理视频流的代码,未优化前,与 Numba 优化后的速度来进行对比分析。

步骤 1:项目要求

OpenCV中的视频帧都是由NumPy数组表示的图像。在此示例中,使用网络摄像头捕获视频流,并对视频流上实时进行计算和修改,这样对每帧的处理时间提出了很高的要求。
为了保持流畅的视频,需要在 1/25 秒内显示每一帧。这样,每一帧最多需要 0.04 秒,从捕获、处理和使用视频流更新窗口。
虽然捕获和更新窗口需要时间,但它留下了很大的不确定性,帧处理(计算和修改)的速度应该有多快,但上限是每帧 0.04 秒。

第 2 步:对每帧进行计算和修改

为了测试。增加1个对图像处理方法,功能如下。

  • 计算。我们将每帧划分为6×16像素的小区域,并计算每个区域的平均颜色。为了获得平均颜色,我们计算每个通道的平均值(BGR)。
  • 修改。对于每个区域,我们将更改每个区域的颜色,并完全用平均颜色填充它。
    这可以通过添加此功能来处理每一帧来完成。
def process(frame, box_height=6, box_width=16):
    height, width, _ = frame.shape
    for i in range(0, height, box_height):
        for j in range(0, width, box_width):
            roi = frame[i:i + box_height, j:j + box_width]
            b_mean = np.mean(roi[:, :, 0])
            g_mean = np.mean(roi[:, :, 1])
            r_mean = np.mean(roi[:, :, 2])
            roi[:, :, 0] = b_mean
            roi[:, :, 1] = g_mean
            roi[:, :, 2] = r_mean
    return frame

画面将划分为矩形区域(box_height x box_width)。对于每个框(roi:感兴趣区域)3个颜色通道(b_mean,g_mean,r_mean)中每个的平均值,并将该区域覆盖为颜色平均值

步骤 3:测试处理函数的性能

为了估计函数过程中花费的时间,使用了cProfile 库。它提供了每个函数调用所花费时间的分析。

import cv2
import numpy as np
import cProfile

def process(frame, box_height=6, box_width=16):
    height, width, _ = frame.shape
    for i in range(0, height, box_height):
        for j in range(0, width, box_width):
            roi = frame[i:i + box_height, j:j + box_width]
            b_mean = np.mean(roi[:, :, 0])
            g_mean = np.mean(roi[:, :, 1])
            r_mean = np.mean(roi[:, :, 2])
            roi[:, :, 0] = b_mean
            roi[:, :, 1] = g_mean
            roi[:, :, 2] = r_mean
    return frame

def main(iterations=300):
    # Get the webcam (default webcam is 0)
    cap = cv2.VideoCapture(0)
    # If your webcam does not support 640 x 480, this will find another resolution
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    for _ in range(iterations):
        # Read the a frame from webcam
        _, frame = cap.read()
        # Flip the frame
        frame = cv2.flip(frame, 1)
        frame = cv2.resize(frame, (640, 480))
        frame = process(frame)
        # Show the frame in a window
        cv2.imshow('WebCam', frame)
        # Check if q has been pressed to quit
        if cv2.waitKey(1) == ord('q'):
            break
    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()
cProfile.run("main()")

输出

 ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      300    7.716    0.026   50.184    0.167 test_numba.py:8(process)

从输出中可以看出,process函数中每次调用使用 0.026 秒,而主循环中其他函数的开销累积到 0.014 秒。

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      300    5.132    0.017    5.132    0.017 method 'read' of 'cv2.VideoCapture' objects
      300    0.073    0.000    0.073    0.000 resize
      300    2.848    0.009    2.848    0.009 waitKey
      300    0.120    0.000    0.120    0.000 flip
      300    0.724    0.002    0.724    0.002 imshow

另外,每次迭代中从读取、调整大小、翻转、显示和 waitKey 调用中产生大约 0.028 秒 (0.017 + 0.009 + 0.002) 的开销。
每帧处理时间,加起来总共为每帧 0.054 秒,或者只能达到每秒 18.5 帧 (FPS) 的帧速率,这太慢了,无法达到每秒24帧的平滑播放。

当然,cProfile 会增加一些开销来测量时间,暂时忽略。

第 4 步:引入 Numba 以优化性能

Numba 库旨优势在于编译代码,使 NumPy 循环更快。而 opencv-python图像正是以numpy数组与运算为基础,所以非常适合用Numba来加速。下面是添加了number语句的代码。 (Numba的使用本文就略过)

import cv2
import numpy as np
from numba import jit
import cProfile

@jit(nopython=True)
def process(frame, box_height=6, box_width=16):
    height, width, _ = frame.shape
    for i in range(0, height, box_height):
        for j in range(0, width, box_width):
            roi = frame[i:i + box_height, j:j + box_width]
            b_mean = np.mean(roi[:, :, 0])
            g_mean = np.mean(roi[:, :, 1])
            r_mean = np.mean(roi[:, :, 2])
            roi[:, :, 0] = b_mean
            roi[:, :, 1] = g_mean
            roi[:, :, 2] = r_mean
    return frame

def main(iterations=300):
    # Get the webcam (default webcam is 0)
    cap = cv2.VideoCapture(0)
    # If your webcam does not support 640 x 480, this will find another resolution
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    for _ in range(iterations):
        # Read the a frame from webcam
        _, frame = cap.read()
        # Flip the frame
        frame = cv2.flip(frame, 1)
        frame = cv2.resize(frame, (640, 480))
        frame = process(frame)
        # Show the frame in a window
        cv2.imshow('WebCam', frame)
        # Check if q has been pressed to quit
        if cv2.waitKey(1) == ord('q'):
            break
    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()
main(iterations=1)
cProfile.run("main(iterations=300)")

输出。


   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      300    1.187    0.004    1.187    0.004 test_numba.py:7(pixels)

每次调用需要 0.004 秒。这导致每次迭代的总时间为 0.032 秒 (0.028 + 0.004)。这足以保持每秒 24 帧 (FPS) 以上的性能。

此外,这将性能提高了 6.5 倍 (7.717 / 1.187)。

结论

从网络摄像头捕获实时流并处理及显示,使用 Numba 来加速后。处理速度提升约为 6.5 倍。

后续将继续推出 cython对opencv-python代码优化后对性能提升测试, 敬请关注作者

numba安装和使用

numba是针对python加速的包,类似cython,pypy,优势是代码改动少首先要安装llvmliteapt-getinstallllvm-3.8LLVM_CONFIG=/usr/local/llvm38/3.8.1/lib/llvm-3.8/bin/llvm-configpipinstallllvmlite#看自己路径在哪程序里importnumba@numba.jit()装饰要加速的函数 查看详情

我可以使用 Numba、矢量化或多处理加速这种空气动力学计算吗?

】我可以使用Numba、矢量化或多处理加速这种空气动力学计算吗?【英文标题】:CanIspeedupthisaerodynamicscalculationwithNumba,vectorization,ormultiprocessing?【发布时间】:2021-06-1908:52:59【问题描述】:问题:我正在尝试提高Python中空气动力... 查看详情

为啥 np.hypot 和 np.subtract.outer 与香草广播相比非常快?使用 Numba 并行加速 numpy 进行距离矩阵计算

】为啥np.hypot和np.subtract.outer与香草广播相比非常快?使用Numba并行加速numpy进行距离矩阵计算【英文标题】:Whynp.hypotandnp.subtract.outerveryfastcomparedtovanillabroadcast?UsingNumbaforspeedupnumpyinparallelfordistancematrixcalculation为什么np.hypot和np.subtr 查看详情

使用带有 numba njit 功能的字典

】使用带有numbanjit功能的字典【英文标题】:UsingDictionarieswithnumbanjitfunction【发布时间】:2019-07-3109:30:11【问题描述】:当输入和返回是字典时,如何使用numba加速函数?我熟悉将numba用于接受数字并返回数组的函数,如下所示:... 查看详情

Numba 中的稀疏矩阵

...nNumba【发布时间】:2013-10-2513:21:20【问题描述】:我希望使用Numba(http://numba.pydata.org/)加速我的机器学习算法(用Python编写)。请注意,该算法将稀疏矩阵作为其输入数据。在我的纯Python实现中,我使用了来自Scipy的csr_matrix和相... 查看详情

将 numba.jit 与 scipy.integrate.ode 一起使用

】将numba.jit与scipy.integrate.ode一起使用【英文标题】:Usingnumba.jitwithscipy.integrate.ode【发布时间】:2015-12-2101:42:44【问题描述】:使用numba.jit从scipy.integrate加速右侧计算odeint工作正常:fromscipy.integrateimportode,odeintfromnumbaimportjit@jitdefr... 查看详情

对于纯 numpy 代码,使用 numba 的收益在哪里?

】对于纯numpy代码,使用numba的收益在哪里?【英文标题】:Wherearethegainsusingnumbacomingfromforpurenumpycode?【发布时间】:2017-11-2821:01:37【问题描述】:我想了解使用Numba在for循环中加速纯numpy代码时的收益来自哪里。是否有任何分析... 查看详情

将 Python 加速器(Cython、Numba、f2py)与 Numpy einsum 进行比较

】将Python加速器(Cython、Numba、f2py)与Numpyeinsum进行比较【英文标题】:ComparingPythonaccelerators(Cython,Numba,f2py)toNumpyeinsum【发布时间】:2016-05-0713:09:55【问题描述】:我将Python加速器(Numba、Cython、f2py)与针对特定问题的简单For循... 查看详情

为啥同时使用 numba.cuda 和 CuPy 从 GPU 传输数据这么慢?

】为啥同时使用numba.cuda和CuPy从GPU传输数据这么慢?【英文标题】:WhyitissoslowtotransferdatafromGPUwhenusenumba.cudaandCuPyatthesametime?为什么同时使用numba.cuda和CuPy从GPU传输数据这么慢?【发布时间】:2020-07-0923:13:26【问题描述】:我从Cupy... 查看详情

加速python中的元素数组乘法

...发布时间】:2013-10-1607:56:31【问题描述】:我一直在尝试使用numba和numexpr来加快简单的逐元素矩阵乘法。我一直没能得到更好的结果,它们基本上(速度方面)都相当于numpys乘法函数。有没有人在这方面有运气?我是否使用了num... 查看详情

如何使用 python 和 numba 在 RTX GPU 中对 NVIDIA 的张量核心进行编程?

】如何使用python和numba在RTXGPU中对NVIDIA的张量核心进行编程?【英文标题】:HowtoprogramNVIDIA\'stensorcoresinRTXGPUwithpythonandnumba?【发布时间】:2020-10-1015:47:34【问题描述】:我有兴趣在python中使用来自NVIDIARTXGPU的张量核心,以从它在... 查看详情

用于 SciPy 集成和插值的 Numba

...nterpolation【发布时间】:2021-09-3003:09:39【问题描述】:我使用Numba来加速我的代码。它工作得很好,并提供了2-3倍的改进。然而,我的代码中花费的主要时间(大约90%)是在scipyquad积分和插值(线性和三次样条)中。我做了几百... 查看详情

numba.errors.TypingError:在 nopython 模式管道中失败(步骤:nopython 前端)

...frontend)【发布时间】:2020-07-1508:26:47【问题描述】:我想使用numba加速我的python代码,如下所示:importnumpyasnpfromnu 查看详情

分配给数组时Numba慢吗?

...?【发布时间】:2013-08-0622:26:01【问题描述】:Numba似乎是加速数字代码执行的绝佳解决方案。但是,当对数组进行赋值时,Numba似乎比标准Python代码慢。考虑这个例子,比较四个替代方案,有/没有Numba,写入一个数组/标量:(故... 查看详情

如何使 numba @jit 使用所有 cpu 内核(并行化 numba @jit)

】如何使numba@jit使用所有cpu内核(并行化numba@jit)【英文标题】:Howtomakenumba@jituseallcpucores(parallelizenumba@jit)【发布时间】:2018-01-1812:01:37【问题描述】:我正在使用numbas@jit装饰器在python中添加两个numpy数组。如果我使用@jit与pytho... 查看详情

如何安装和导入openmp通过numba使用?

】如何安装和导入openmp通过numba使用?【英文标题】:Howtoinstallandimportopenmptouseitthroughnumba?【发布时间】:2022-01-1908:42:07【问题描述】:我正在python中使用numba构建程序,我需要使用openmp作为numba线程层。我正在努力让它启动并运... 查看详情

理解 CUDA、Numba、Cupy 等的扩展示例

...示例都是简单的数组添加,显示了从cpu单核/线程到gpu的加速。并且命令文档大多缺乏好的例子。这篇文章旨在提供一个更全面的示例。提供初始代码here。它是经典元胞自动机的简单模型。最初 查看详情

使用 Numba 求解 ODE

】使用Numba求解ODE【英文标题】:SolveODEswithNumba【发布时间】:2021-11-2406:54:56【问题描述】:我正在尝试使用Numba使我的ODE求解器更快,但以下代码会引发键入错误:importnumpyasnpimportmatplotlib.pyplotaspltfromnumbaimportnjit@njitdefpend(t,y,b,c)... 查看详情