一、说明

让我们谈谈在Python中使用网络摄像头。我有一个简单的任务,从相机读取帧,并在每一帧上运行神经网络。对于一个特定的网络摄像头,我在设置目标 fps 时遇到了问题(正如我现在所理解的——因为相机可以用 mjpeg 格式运行 30 fps,但不能运行原始),所以我决定深入研究 FFmpeg 看看它是否有帮助。

二、OpenCV和FFmpeg两个选项

我最终让OpenCV和FFmpeg都工作了,但我发现了一件非常有趣的事情:FFmpeg性能优于OpenCV是我的主要用例。事实上,使用 FFmpeg,我读取帧的速度提高了 15 倍,整个管道的加速提高了 32%。我简直不敢相信结果,并多次重新检查了所有内容,但它们是一致的。

注意:当我只是一帧一帧地读取时,性能完全相同,但是当我在读取帧后运行某些内容时,FFmpeg 速度更快(这需要时间)。我将在下面确切地说明我的意思。

2.1 openCV的代码实现

现在,让我们看一下代码。首先 — 使用 OpenCV 读取网络摄像头帧的类:

class VideoStreamCV:def __init__(self, src: int, fps: int, resolution: Tuple[int, int]):self.src = srcself.fps = fpsself.resolution = resolutionself.cap = self._open_camera()self.wait_for_cam()def _open_camera(self):cap = cv2.VideoCapture(self.src)cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.resolution[0])cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.resolution[1])fourcc = cv2.VideoWriter_fourcc(*"MJPG")cap.set(cv2.CAP_PROP_FOURCC, fourcc)cap.set(cv2.CAP_PROP_FPS, self.fps)return capdef read(self):ret, frame = self.cap.read()if not ret:return Nonereturn framedef release(self):self.cap.release()def wait_for_cam(self):for _ in range(30):frame = self.read()if frame is not None:return Truereturn False

2.2 使用FFmpeg

我使用功能,因为相机通常需要时间“热身”。FFmpeg 类使用相同的预热:wait_for_cam

class VideoStreamFFmpeg:def __init__(self, src: int, fps: int, resolution: Tuple[int, int]):self.src = srcself.fps = fpsself.resolution = resolutionself.pipe = self._open_ffmpeg()self.frame_shape = (self.resolution[1], self.resolution[0], 3)self.frame_size = np.prod(self.frame_shape)self.wait_for_cam()def _open_ffmpeg(self):os_name = platform.system()if os_name == "Darwin":  # macOSinput_format = "avfoundation"video_device = f"{self.src}:none"elif os_name == "Linux":input_format = "v4l2"video_device = f"{self.src}"elif os_name == "Windows":input_format = "dshow"video_device = f"video={self.src}"else:raise ValueError("Unsupported OS")command = ['ffmpeg','-f', input_format,'-r', str(self.fps),'-video_size', f'{self.resolution[0]}x{self.resolution[1]}','-i', video_device,'-vcodec', 'mjpeg',  # Input codec set to mjpeg'-an', '-vcodec', 'rawvideo',  # Decode the MJPEG stream to raw video'-pix_fmt', 'bgr24','-vsync', '2','-f', 'image2pipe', '-']if os_name == "Linux":command.insert(2, "-input_format")command.insert(3, "mjpeg")return subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)def read(self):raw_image = self.pipe.stdout.read(self.frame_size)if len(raw_image) != self.frame_size:return Noneimage = np.frombuffer(raw_image, dtype=np.uint8).reshape(self.frame_shape)return imagedef release(self):self.pipe.terminate()def wait_for_cam(self):for _ in range(30):frame = self.read()if frame is not None:return Truereturn False

For timing function, I used decorator:run

def timeit(func):def wrapper(*args, **kwargs):t0 = time.perf_counter()result = func(*args, **kwargs)t1 = time.perf_counter()print(f"Main function time: {round(t1-t0, 4)}s")return resultreturn wrapper

作为一个繁重的合成任务,我使用了这个简单的函数来代替神经网络(它也可以只是)。这是一个非常重要的部分,因为没有任何任务,OpenCV和FFmpeg的读取速度是相同的:time.sleep

def computation_task():for _ in range(5000000):9999 * 9999

现在功能与我读取框架的循环,它的时间,运行:computation_task

@timeit
def run(cam: VideoStreamCV | VideoStreamFFmpeg, run_task: bool):timer = []for _ in range(100):t0 = time.perf_counter()cam.read()timer.append(time.perf_counter() - t0)if run_task:computation_task()cam.release()return round(np.mean(timer), 4)

最后,我设置了几个参数,使用 OpenCV 和 FFmpeg 初始化 2 个视频流,并在没有和使用它的情况下运行它们。maincomputation_task

def main():fsp = 30resolution = (1920, 1080)for run_task in [False, True]:ff_cam = VideoStreamFFmpeg(src=0, fps=fsp, resolution=resolution)cv_cam = VideoStreamCV(src=0, fps=fsp, resolution=resolution)print(f"FFMPEG, task {run_task}:")print(f"Mean frame read time: {run(cam=ff_cam, run_task=run_task)}s\n")print(f"CV2, task {run_task}:")print(f"Mean frame read time: {run(cam=cv_cam, run_task=run_task)}s\n")

这是我得到的:

FFMPEG, task False:
Main function time: 3.2334s
Mean frame read time: 0.0323sCV2, task False:
Main function time: 3.3934s
Mean frame read time: 0.0332sFFMPEG, task True:
Main function time: 4.461s
Mean frame read time: 0.0014sCV2, task True:
Main function time: 6.6833s
Mean frame read time: 0.023s

因此,如果没有合成任务,我可以获得相同的阅读时间:,。但是对于合成任务:和,所以FFmpeg要快得多。美妙之处在于,我的神经网络应用程序得到了真正的加速,而不仅仅是综合测试,所以我决定分享结果。0.03230.03320.00140.023

下图显示了 1 次迭代所需的时间:读取帧,使用 yolov8s 模型(在 CPU 上)处理它,并使用检测到的对象保存帧:

三 完整脚本

以下是包含综合测试的完整脚本:

import platform
import subprocess
import time
from typing import Tuple
import cv2
import numpy as npclass VideoStreamFFmpeg:def __init__(self, src: int, fps: int, resolution: Tuple[int, int]):self.src = srcself.fps = fpsself.resolution = resolutionself.pipe = self._open_ffmpeg()self.frame_shape = (self.resolution[1], self.resolution[0], 3)self.frame_size = np.prod(self.frame_shape)self.wait_for_cam()def _open_ffmpeg(self):os_name = platform.system()if os_name == "Darwin":  # macOSinput_format = "avfoundation"video_device = f"{self.src}:none"elif os_name == "Linux":input_format = "v4l2"video_device = f"{self.src}"elif os_name == "Windows":input_format = "dshow"video_device = f"video={self.src}"else:raise ValueError("Unsupported OS")command = ['ffmpeg','-f', input_format,'-r', str(self.fps),'-video_size', f'{self.resolution[0]}x{self.resolution[1]}','-i', video_device,'-vcodec', 'mjpeg',  # Input codec set to mjpeg'-an', '-vcodec', 'rawvideo',  # Decode the MJPEG stream to raw video'-pix_fmt', 'bgr24','-vsync', '2','-f', 'image2pipe', '-']if os_name == "Linux":command.insert(2, "-input_format")command.insert(3, "mjpeg")return subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)def read(self):raw_image = self.pipe.stdout.read(self.frame_size)if len(raw_image) != self.frame_size:return Noneimage = np.frombuffer(raw_image, dtype=np.uint8).reshape(self.frame_shape)return imagedef release(self):self.pipe.terminate()def wait_for_cam(self):for _ in range(30):frame = self.read()if frame is not None:return Truereturn Falseclass VideoStreamCV:def __init__(self, src: int, fps: int, resolution: Tuple[int, int]):self.src = srcself.fps = fpsself.resolution = resolutionself.cap = self._open_camera()self.wait_for_cam()def _open_camera(self):cap = cv2.VideoCapture(self.src)cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.resolution[0])cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.resolution[1])fourcc = cv2.VideoWriter_fourcc(*"MJPG")cap.set(cv2.CAP_PROP_FOURCC, fourcc)cap.set(cv2.CAP_PROP_FPS, self.fps)return capdef read(self):ret, frame = self.cap.read()if not ret:return Nonereturn framedef release(self):self.cap.release()def wait_for_cam(self):for _ in range(30):frame = self.read()if frame is not None:return Truereturn Falsedef timeit(func):def wrapper(*args, **kwargs):t0 = time.perf_counter()result = func(*args, **kwargs)t1 = time.perf_counter()print(f"Main function time: {round(t1-t0, 4)}s")return resultreturn wrapperdef computation_task():for _ in range(5000000):9999 * 9999@timeit
def run(cam: VideoStreamCV | VideoStreamFFmpeg, run_task: bool):timer = []for _ in range(100):t0 = time.perf_counter()cam.read()timer.append(time.perf_counter() - t0)if run_task:computation_task()cam.release()return round(np.mean(timer), 4)def main():fsp = 30resolution = (1920, 1080)for run_task in [False, True]:ff_cam = VideoStreamFFmpeg(src=0, fps=fsp, resolution=resolution)cv_cam = VideoStreamCV(src=0, fps=fsp, resolution=resolution)print(f"FFMPEG, task {run_task}:")print(f"Mean frame read time: {run(cam=ff_cam, run_task=run_task)}s\n")print(f"CV2, task {run_task}:")print(f"Mean frame read time: {run(cam=cv_cam, run_task=run_task)}s\n")if __name__ == "__main__":main()

注意:此脚本已在Apple的M1 Pro芯片上进行了测试。希望这是有帮助的!阿尔戈·萨基扬

 

使用 Python 的高效相机流相关推荐

  1. python dpkt解析ssl流

    用法:python extract_tls_flow.py -vr  white_pcap/11/2018-01-10_13-05-09_2.pcap  -o pcap_ssl_flow.txt  & ...

  2. python自学多久可以找到工作-自学Python的高效方法,学Python多久能找到工作?

    原标题:自学Python的高效方法,学Python多久能找到工作? 相信有了解的人都知道,Python目前是首选的AI语言,在数据科学和AI中占据主导地位,而且随着互联网的发展,Python的应用越来 ...

  3. Intel Realsense D435 python 从深度相机realsense生成pcl点云

    引用文章:python 从深度相机realsense生成pcl点云 从深度相机realsense生成pcl点云 一.通过realsense取得深度信息和彩色信息 二.获取坐标和色彩信息 三.通过pcl ...

  4. 旋流式沉砂池计算_以高效旋流器为核心的超低成本选煤技术

    最近研究了一些选煤案例,有一个重要的发现,那就是在厂型一定的情况下,不同的设计差距太大,一些指标差距范围在10~40%不等,这是很可怕的.比如说新星选煤厂,在总煤泥含量达到40%,不脱泥全粒级入选的情 ...

  5. 标准输入流和输出流分别是啥,高效字符流的方法

    标准输入流的书System.in,默认是指向键盘的,可以接受用户键盘录入的数据 标准输出流是System.out,默认指向控制台,可以将结果打印到控制台. 高效字符流: readLine() 读取一行 ...

  6. 用python开启相机_如何用Python打开realsenseD435相机并获取相机参数

    如何用Python打开realsenseD435相机 import pyrealsense2 as rs import numpy as np import cv2 if __name__ == &q ...

  7. python高效处理文件_使用Python语言高效地处理一个文本文件

    使用Python语言高效地处理一个文本文件: # -- encoding: utf-8 -- # 脚本功能:在指定的文件中查找指定的字符串 # 此脚本接受两个参数 # 参数1:指定一个文件名,在这个文 ...

  8. python json操作_4个小窍门,让你在Python中高效使用JSON

    字典和列表是 Python的两种数据类型,也是用来处理JSON的完美工具.本文将主要分享以下内容: 如何载入.编写JSON? 如何在命令行上优化.校验JSON? 如何通过使用JMESPath对JSON ...

  9. linux和python哪个工资高,关于树莓派:用它来学习Linux及Python真的高效?

    姓名:冯子豪 学号:16020199001 转载自https://blog..net/sfM06sqVW55DFt1/article/details/79293166 [嵌牛导读]树莓派是一种便宜的卡 ...

  10. python要学多久可以找到工作-自学Python的高效方法,学Python多久能找到工作?

    原标题:自学Python的高效方法,学Python多久能找到工作? 相信有了解的人都知道,Python目前是首选的AI语言,在数据科学和AI中占据主导地位,而且随着互联网的发展,Python的应用越来 ...

最新文章

  1. 如何定义中文转语音的语气
  2. TypeScript Type Assertions - 类型断言
  3. java 什么时候进行垃圾回收_java什么时候进行垃圾回收,垃圾回收的执行流程
  4. 在线画 有穷状态自动机 的软件_怎么画思维导图?不用下载软件,在线就能操作...
  5. 清华计算机自主招生试题,2017年清华大学自主招生笔试题
  6. 1.Python数据类型、方法
  7. 6系A卡笔记本移动版:HD6470/6550/6630/6650/6730/6770M
  8. php隐藏api,PHP 在 Laravel 中动态隐藏 API 字段
  9. cnn神经网络_神经网络之CNN和RNN
  10. 哪款浏览器速度最快_全球知名度非常高的火狐浏览器,它好在哪呢?
  11. 某大型网络社区传播性XSS分析
  12. Java 输入输出流 解决中文乱码问题【不一定详细但一定实用篇】【全文4800字】
  13. Ext.Net配色方案
  14. 如何快速的切换EXCEL
  15. java流浪救助站公益志愿者管理系统
  16. 小米/红米手机刷第三方rom(红米5 plus为例)
  17. 卷死我了,终于毕业了!!
  18. 日本房产泡沫的崩塌,虽然很长,希望80后仔细阅读
  19. 鸿蒙初判陶镕铁,大禹治水为何还要求雨?他用金箍棒到底做什么用?
  20. 发布上线前,先小秀一把俺的64位浏览器,速度那觉对是杠杠滴,上youtube,上google不费劲

热门文章

  1. 开学第一堂线下课——计算机系统结构
  2. 2022年,我45岁,一息尚存不落征帆,静稳前行未来可期
  3. spring boot网络空间安全实验教学示范中心网站 毕业设计源码111454
  4. 关于微信小程序,那些开发文档没有告诉你的
  5. python要求所有浮点数必须带有小数部分_第2章 基本数据类型
  6. 数据库应用——MySQL数据库初体验及5.7版本部署
  7. 斐波那契数列Python实现
  8. 斐波那契数列(python实现)
  9. java水果超市课程设计_【笔记】学习java第十三天,水果超市
  10. Golang的一些功能函数——Slice