使用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. Qt设置QLabel的样式
  2. matlab中real函数,Matlab中del2()函数学习笔记
  3. Django生命周期
  4. PyQt5简介及demo
  5. 北风设计模式课程---2、工厂方法模式
  6. 前端判断数据类型的通用方法
  7. JavaScript 第一课 JavaScript简史
  8. arcgis双标准纬线等角圆锥投影_世界地图是怎么制作出来的,各投影算法的来历...
  9. 点击网页跟踪php代码的工具,使用ltrace工具跟踪PHP库函数调用的方法
  10. python调用nacos账号密码_python-nacos-sdk
  11. php表单选择题代码,php 表单代码
  12. Vue3.0 + Ts 项目框架搭建二:路由 Router
  13. 加载JDBC驱动程序
  14. 相似矩阵对角化 | 找到一个可逆矩阵 P 使得 P^(-1)AP 成为一个对角矩阵
  15. YOLACT论文阅读及解析
  16. 罗辑思维2017-2018跨年演讲摘要
  17. 企业邮箱如何发送国外邮件?2021知名企业邮箱网站排名
  18. 惊了,深圳房价比北京还高。。。
  19. 如何在指定网站搜索内容
  20. android代码控制组件的移动,Android自定义控件实现随手指移动的小球

热门文章

  1. 毕业设计 Spring Boot的药品管理系统(含源码+论文)
  2. 查看华为防火墙会话和流量top数据
  3. 如何取消wps中pdf的涂改液_改正液怎么洗
  4. 加密越来越简单——用JavaScript实现数据加密和解密
  5. 5月8日-5月14日
  6. C语言期末编程题题库
  7. 提取PDF每一页,所有表格,并按页码命名保存
  8. 【环境搭建】CentOS上部署Vulhub靶场
  9. JavaScript大作业(餐厅美食网站设计与实现)
  10. DSOframer 的主要事件参考(二)