使用Numba加速OpenCV Python视频流代码。提升6.5倍性能
Posted __弯弓__
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Numba加速OpenCV Python视频流代码。提升6.5倍性能相关的知识,希望对你有一定的参考价值。
使用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 倍。
以上是关于使用Numba加速OpenCV Python视频流代码。提升6.5倍性能的主要内容,如果未能解决你的问题,请参考以下文章