跳转到主要内容

Linux友好的视频处理库

项目描述

v4l2py

从版本3.0开始,该项目现在是 linuxpy.video 的适配器

请考虑直接使用 linuxpy

V4L2py Python Versions License CI

视频Linux 2 (V4L2) Python库

双用途API

  • 为人类提供的高级设备API来玩耍 :-)
  • 用于v4l2 (video4linux2) 用户空间API的原始Python绑定,使用ctypes(不要浪费时间在这里。你可能不会使用它)

仅适用于Python >= 3.7。

为什么?

那么,为什么还需要一个专门用于视频控制的库?我为什么不能只使用 cv2.VideoCapture

以下是这个库提供的功能列表,这些功能在其他库中找不到

  • 列出可用的V4L2设备
  • 获取设备详细信息(名称、驱动程序、功能、可用格式)
  • 精细控制相机参数(例如:分辨率、格式、亮度、对比度等)
  • 精细控制资源管理以利用内存映射、DMA或用户指针(缓冲区)
  • 关于帧的详细信息(时间戳、帧号等)
  • 写入VideoOutput
  • 与非阻塞的基于协程的应用程序(如 geventasyncio)集成,无需使用 asyncio.to_thread 等常规技巧

安装

在您喜欢的Python环境中

$ pip install v4l2py

使用方法

无需多言

>>> from v4l2py import Device
>>> with Device.from_id(0) as cam:
>>>     for i, frame in enumerate(cam):
...         print(f"frame #{i}: {len(frame)} bytes")
...         if i > 9:
...             break
...
frame #0: 54630 bytes
frame #1: 50184 bytes
frame #2: 44054 bytes
frame #3: 42822 bytes
frame #4: 42116 bytes
frame #5: 41868 bytes
frame #6: 41322 bytes
frame #7: 40896 bytes
frame #8: 40844 bytes
frame #9: 40714 bytes
frame #10: 40662 bytes

获取设备信息

>>> from v4l2py.device import Device, BufferType

>>> cam = Device.from_id(0)
>>> cam.open()
>>> cam.info.card
'Integrated_Webcam_HD: Integrate'

>>> cam.info.capabilities
<Capability.STREAMING|EXT_PIX_FORMAT|VIDEO_CAPTURE: 69206017>

>>> cam.info.formats
[ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'Motion-JPEG',
             flags=<ImageFormatFlag.COMPRESSED: 1>, pixelformat=<PixelFormat.MJPEG: 1196444237>),
 ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'YUYV 4:2:2',
             flags=<ImageFormatFlag.0: 0>, pixelformat=<PixelFormat.YUYV: 1448695129>)]

>>> cam.get_format(BufferType.VIDEO_CAPTURE)
Format(width=640, height=480, pixelformat=<PixelFormat.MJPEG: 1196444237>}

>>> for ctrl in cam.controls.values(): print(ctrl)
<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>
<IntegerControl contrast min=0 max=255 step=1 default=32 value=32>
<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>
<IntegerControl hue min=-180 max=180 step=1 default=0 value=0>
<BooleanControl white_balance_automatic default=True value=True>
<IntegerControl gamma min=90 max=150 step=1 default=120 value=120>
<MenuControl power_line_frequency default=1 value=1>
<IntegerControl white_balance_temperature min=2800 max=6500 step=1 default=4000 value=4000 flags=inactive>
<IntegerControl sharpness min=0 max=7 step=1 default=2 value=2>
<IntegerControl backlight_compensation min=0 max=2 step=1 default=1 value=1>
<MenuControl auto_exposure default=3 value=3>
<IntegerControl exposure_time_absolute min=4 max=1250 step=1 default=156 value=156 flags=inactive>
<BooleanControl exposure_dynamic_framerate default=False value=False>

>>> cam.controls["saturation"]
<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>

>>> cam.controls["saturation"].id
9963778
>>> cam.controls[9963778]
<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>

>>> cam.controls.brightness
<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>
>>> cam.controls.brightness.value = 64
>>> cam.controls.brightness
<IntegerControl brightness min=0 max=255 step=1 default=128 value=64>

(另见 v4l2py-ctl 示例)

asyncio

v4l2py 与 asyncio 兼容

$ python -m asyncio

>>> from v4l2py import Device
>>> with Device.from_id(0) as camera:
...     async for frame in camera:
...         print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...

(检查 基本异步Web 异步 示例)

gevent

v4l2py 也与 gevent 兼容

$ python

>>> from v4l2py import Device, GeventIO
>>> with Device.from_id(0, io=GeventIO) as camera:
...     for frame in camera:
...         print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...

(检查 基本 geventWeb gevent 示例)

额外功能

您已经很有耐心地读到这里了,所以,仅为您准备了一个20行的宝贝:一个 flask Web 服务器,可以在网页上显示您的设备

$ pip install flask
# web.py

import flask
from v4l2py import Device

app = flask.Flask('basic-web-cam')

def gen_frames():
    with Device.from_id(0) as cam:
        for frame in cam:
            yield b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + frame.data + b"\r\n"

@app.route("/")
def index():
    return '<html><img src="/stream" /></html>'

@app.route("/stream")
def stream():
    return flask.Response(
        gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

运行方式

$ FLASK_APP=web flask run -h 0.0.0.0

将浏览器指向 127.0.0.1:5000,您应该能看到相机正在运行!

从 1.x 迁移到 2

帧从简单的字节对象更改为包含数据和所有帧元数据的 Frame。

因此,在从 1.x 迁移到 2 时,您需要使用 bytes 强制转换帧对象或访问 frame.data

之前

with Device.from_id(0) as cam:
    for frame in cam:
        buff = io.BytesIO(frame)

现在

with Device.from_id(0) as cam:
    for frame in cam:
        frame = bytes(frame)  # or frame = frame.data
        buff = io.BytesIO(frame)

改进的设备控制

设备控制已得到改进,以提供更符合 Python 风格的接口。新接口现在是默认设置;然而,旧接口可以通过以下方式请求:Device.from_id(x, legacy_controls=True)

之前

>>> from v4l2py import Device
>>> cam = Device.from_id(0)
>>> cam.open()
>>> for ctrl in cam.controls.values():
...     print(ctrl)
...     for item in ctrl.menu.values():
...             print(f" - {item.index}: {item.name}")
<Control brightness type=integer min=0 max=255 step=1 default=128 value=255>
<Control contrast type=integer min=0 max=255 step=1 default=32 value=255>
<Control saturation type=integer min=0 max=100 step=1 default=64 value=100>
<Control hue type=integer min=-180 max=180 step=1 default=0 value=0>
<Control white_balance_automatic type=boolean min=0 max=1 step=1 default=1 value=1>
<Control gamma type=integer min=90 max=150 step=1 default=120 value=150>
<Control gain type=integer min=1 max=7 step=1 default=1 value=1>
<Control power_line_frequency type=menu min=0 max=2 step=1 default=2 value=2>
 - 0: Disabled
 - 1: 50 Hz
 - 2: 60 Hz
<Control white_balance_temperature type=integer min=2800 max=6500 step=1 default=4000 value=4000 flags=inactive>
<Control sharpness type=integer min=0 max=7 step=1 default=2 value=7>
<Control backlight_compensation type=integer min=0 max=1 step=1 default=0 value=1>
<Control auto_exposure type=menu min=0 max=3 step=1 default=3 value=3>
 - 1: Manual Mode
 - 3: Aperture Priority Mode
<Control exposure_time_absolute type=integer min=10 max=333 step=1 default=156 value=156 flags=inactive>
<Control exposure_dynamic_framerate type=boolean min=0 max=1 step=1 default=0 value=1>

>>> type(cam.controls.exposure_dynamic_framerate.value)
<class 'int'>

现在

>>> from v4l2py.device import Device, MenuControl
>>> cam = Device.from_id(0)
>>> cam.open()
>>> for ctrl in cam.controls.values():
...     print(ctrl)
...     if isinstance(ctrl, MenuControl):
...             for (index, name) in ctrl.items():
...                     print(f" - {index}: {name}")
<IntegerControl brightness min=0 max=255 step=1 default=128 value=255>
<IntegerControl contrast min=0 max=255 step=1 default=32 value=255>
<IntegerControl saturation min=0 max=100 step=1 default=64 value=100>
<IntegerControl hue min=-180 max=180 step=1 default=0 value=0>
<BooleanControl white_balance_automatic default=True value=True>
<IntegerControl gamma min=90 max=150 step=1 default=120 value=150>
<IntegerControl gain min=1 max=7 step=1 default=1 value=1>
<MenuControl power_line_frequency default=2 value=2>
 - 0: Disabled
 - 1: 50 Hz
 - 2: 60 Hz
<IntegerControl white_balance_temperature min=2800 max=6500 step=1 default=4000 value=4000 flags=inactive>
<IntegerControl sharpness min=0 max=7 step=1 default=2 value=7>
<IntegerControl backlight_compensation min=0 max=1 step=1 default=0 value=1>
<MenuControl auto_exposure default=3 value=3>
 - 1: Manual Mode
 - 3: Aperture Priority Mode
<IntegerControl exposure_time_absolute min=10 max=333 step=1 default=156 value=156 flags=inactive>
<BooleanControl exposure_dynamic_framerate default=False value=True>

>>> type(cam.controls.white_balance_automatic.value)
<class 'bool'>
>>> cam.controls.white_balance_automatic.value
<BooleanControl white_balance_automatic default=True value=True>
>>> cam.controls.white_balance_automatic.value = False
<BooleanControl white_balance_automatic default=True value=False>

>>> wba = cam.controls.white_balance_automatic
>>> wba.value = "enable"    # or "on", "1", "true", "yes"
>>> wba
<BooleanControl white_balance_automatic default=True value=True>
>>> wba.value = "off"       # or "disable", "0", "false", "no"
>>> wba
<BooleanControl white_balance_automatic default=True value=False>

现有代码的初始升级路径是请求旧接口,在实例化 Device 对象时传递 legacy_controls=True,使用 LegacyControl 替代 Control 进行实例化,以及使用 BaseControl 进行 isinstance() 检查。在不太可能的情况下,如果您的代码对 MenuItem 进行 isinstance() 检查,应将其更改为 LegacyMenuItem

参考

请参阅 linux/videodev2.h 头文件以获取详细信息。

  • Video for Linux Two 规范 <https://linuxkernel.org.cn/doc/html/v6.2/userspace-api/media/v4l/v4l2.html>

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源分布

v4l2py-3.0.0.tar.gz (24.2 kB 查看哈希值)

上传时间

构建分布

v4l2py-3.0.0-py3-none-any.whl (18.6 kB 查看哈希值)

上传时间 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面