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

1、目标问题:

在 OpenCV Python 中视频处理是比较耗资源的,从而造成画面卡顿,如果跳帧处理可能造成丢失关键数据。用 Numba对 OpenCV代码加速是1个较好的改进方法。
Numba是1个Python编译器,主要功能是对数组类型(Array, Numpy, bytes等)、数值类型的函数进行加速,支持GPU计算,以及能避开GIP限制。使用只须加入简单的导入与函数装饰器代码即可,非常方便。

实际效果如何呢? 本文将通过实例代码来比较,对于 OpenCV显示与处理视频流的代码,未优化前,与 Numba 优化后的速度来进行对比分析。

2、Numba安装与使用方式简介

2.1 安装Numba库

pip install numba

2.2 Numba 的使用方式

2.2.1 基本使用方式

Numba的使用,间通过在函数代码前加个装饰器,如下

# 导入相当包
from numba import jit
import numpy as np@jit    # jit装饰器
def sum(a, b):return a + b

2.2.2 No GIL模式

如果函数内运算量比较大,而调用者希望尽可能短时间处理,可以采用多CPU来运算, 装饰器内添加参数 nogil=True

@jit(nogil=True)
def sum(a, b):return a + b

2.2.3 No python 模式

即用git装饰的函数在运行时,不需要解释器介入,直接以机器码的方式运行,其实就是按C的方式运行,这种方式最快。装饰器传入参数 nopython=True。 示例

@jit(nopython=True)
def sum(a, b):return a + b

3、项目要求

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

4、对每帧进行计算和修改

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

  • 计算。我们将每帧划分为6×16像素的小区域,并计算每个区域的平均颜色。为了获得平均颜色,我们计算每个通道的平均值(BGR)。
  • 修改。对于每个区域,我们将更改每个区域的颜色,并完全用平均颜色填充它。
    这可以通过添加此功能来处理每一帧来完成。
def process(frame, box_height=6, box_width=16):height, width, _ = frame.shapefor 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_meanroi[:, :, 1] = g_meanroi[:, :, 2] = r_meanreturn frame

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

5、测试处理函数的性能

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

import cv2
import numpy as np
import cProfiledef process(frame, box_height=6, box_width=16):height, width, _ = frame.shapefor 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_meanroi[:, :, 1] = g_meanroi[:, :, 2] = r_meanreturn framedef 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 resolutioncap.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 frameframe = cv2.flip(frame, 1)frame = cv2.resize(frame, (640, 480))frame = process(frame)# Show the frame in a windowcv2.imshow('WebCam', frame)# Check if q has been pressed to quitif cv2.waitKey(1) == ord('q'):break# When everything done, release the capturecap.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 会增加一些开销来测量时间,暂时忽略。

6、引入 Numba 以优化性能

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

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.shapefor 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_meanroi[:, :, 1] = g_meanroi[:, :, 2] = r_meanreturn framedef 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 resolutioncap.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 frameframe = cv2.flip(frame, 1)frame = cv2.resize(frame, (640, 480))frame = process(frame)# Show the frame in a windowcv2.imshow('WebCam', frame)# Check if q has been pressed to quitif cv2.waitKey(1) == ord('q'):break# When everything done, release the capturecap.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)。

7、结论

从网络摄像头捕获实时流并处理及显示,使用 Numba 来加速后。处理速度提升约为 6.5 倍。
上述测试基于集成显卡电脑。如果电脑配置有支持CUDA的显卡,速度提升更加明显,请自行测试。

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

用Numba加速OpenCV Python视频处理代码,提升6.5倍性能相关推荐

  1. python视频处理代码_python如何实现视频转代码视频

    本文实例为大家分享了python如何实现视频转代码视频的具体代码,供大家参考,具体内容如下 # -*- coding:utf-8 -*- #coding:utf-8 import argparse i ...

  2. opencv+python视频实时质心显示

    利用opencv+python实现以下功能: 1)获取实时视频,分解帧频: 2)将视频做二值化处理: 3) 将视频做滤波处理(去除噪点,获取准确轮廓个数): 4)识别图像轮廓: 5)计算质心: 6)描 ...

  3. OpenCV—Python视频的读取及保存

    运行环境 Anaconda=5.3 | python=3.7 一.从摄像头中获取视频 创建一个VideoCapture对象.它的参数可以是设备索引或视频文件的名称(下面会讲到).设备索引只是指定哪台摄 ...

  4. 答题卡识别任务--opencv python(附代码)

    答题卡识别 项目理论和源码来自唐宇迪opencv项目实战 记一篇python-opencv 完成答题卡识别 项目的学习笔记 输入一张特定格式的答题卡图片(答题卡中题目数量和选项个数是固定的),能够输出 ...

  5. OpenCV—python 视频分析背景提取与前景提取

    文章目录 一.算法 二.代码 MOG2(Mixture of Gaussian) 与 KNN对比 Kmeans 行人检测代码 OpenCV中支持的两种背景提取算法都是 基于模型密度评估,然后在 像素级 ...

  6. 光流 | OpenCV中的Lucas-Kanade光流与稠密光流:基于Opencv+Python(附代码)

    ===================================================== github:https://github.com/MichaelBeechan CSDN: ...

  7. 计算机视觉与深度学习 | ORB特征提取:基于OpenCV+Python(附代码)

    ===================================================== github:https://github.com/MichaelBeechan CSDN: ...

  8. 大道至简,仅需4行代码提升多标签分类性能!ICCV21 南大提出Residual Attention

    ▊ 写在前面 多标签图像识别是一项具有挑战性的计算机视觉任务.然而,目前解决这一任务的方法复杂.计算量大.缺乏直观解释 .为了能够有效地感知不同类别物体所占据的空间区域,作者提出了一个非常简单的模块, ...

  9. 运行opencv保存视频时出现错误的解决方法

    运行repo代码时,用opencv保存结果视频的时候,如果出现以下问题: 一.明明有写opencv保存的代码,但是就是没保存视频 解决方法:这时候就要定位到opencv保存视频的代码里去,一般保存视频 ...

最新文章

  1. 【玩转 Angular】1. Angular-CLI 安装与使用
  2. 如何用mysql运行程序_如何在MySQL工作台中创建和执行程序
  3. Java并发控制基础篇 Thread继承类和Runnable实现类
  4. 1_文本处理与词嵌入
  5. python3字典菜鸟教程_Python3 字典(map)
  6. html列表按时间排序代码_把 Linux 上的文件列表和排序玩出花来 | Linux 中国
  7. Net Core 实现谷歌翻译ApI 免费版
  8. MySQL获取汉字拼音首字母
  9. 中小企业适合引入OA办公系统吗?
  10. 腾讯测试岗位的面试经历
  11. 课程设计小组报告——基于ARM实验箱的捕鱼游戏的设计与实现
  12. Battery Historian
  13. 非华为电脑使用EMUI10多屏协同教程
  14. 初识Java-概述与环境搭建
  15. 微软商店、应用、网站无法登录
  16. 基于JSP的物流信息管理系统(MySQL版)
  17. java使用jxl生成excel表格,jsp使用js下载excel文件xls
  18. IT行业吃香技能TOP榜,欢迎补充
  19. 刘强东的代码水平到底有多牛?网友:95年一个晚上赚5万
  20. RabbitMq无法访问http://localhost:1567,Failed to start Ranch listener {acceptor,{0,0,0,0,0,0,0,0},5672解决

热门文章

  1. rtx3090能组成超级计算机吗,惊人的核心怎么来的?RTX3090架构魔术揭秘
  2. C# WinForm 借助Windows API 实现进程间通信
  3. Android 获取软键盘的删除delete事件
  4. 验证码验证失败的那些事
  5. 一键部署openvpn服务端和客户端(已写成脚本)
  6. 什么是盒子模型中的水平方向的布局
  7. python字典对象的方法返回字典的值列表_python对象转字典的两种实现方式示例
  8. 如何将html页面导出到excel,html页面表格导出到excel总结(示例代码)
  9. 练习下csnd博客怎么用
  10. 远程桌面连接出现由于网络错误,连接被中断,请重新连接到远程计算机错误的解决方法