You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Python imageio实现嵌入式Linux与PC间TCP低延迟视频传输?

问题

在嵌入式Linux板(如树莓派)和PC上分别运行Python程序,需求如下:

  • 用imageio库从Linux板的Pi Camera捕获帧
  • 通过TCP连接将帧发送到PC,PC端将帧转为numpy数组
  • 追求最低延迟

此前用OpenCV将帧压缩为低质量JPEG传输,本地网络延迟0.25-0.5s,但不想依赖OpenCV;目前用pickle直接序列化帧传输,延迟超过1s,效率不足,现有代码如下:

Linux板端代码

for idx, frame in enumerate(iio.imiter("<video0>", size=(resolution[0], resolution[1]), fps=fps)):
    data = pkl.dumps(frame, 0)
    framelen = len(data)
    connection.write(struct.pack('<L', framelen))
    connection.flush()
    connection.write(data)

PC端代码

while True:
    framelen = struct.unpack('<L', connection.read(struct.calcsize('<L')))[0]
    if not framelen:
        break

    data = connection.read(framelen)  # raw undecoded pickle bytestring
    frame = pkl.loads(data, fix_imports=True, encoding="bytes")

想知道有没有更高效的实现方式,比如借助imageio编码压缩后再通过Socket发送、PC端解码?


优化方案

核心思路是用轻量级图像压缩替代pickle序列化,imageio本身支持JPEG/PNG等编码,结合高效的TCP传输逻辑,能大幅降低延迟:

1. 用imageio直接编码为JPEG(无OpenCV依赖)

JPEG压缩能大幅减小传输数据量,imageio的编码速度快,且无需额外依赖。

Linux板端(发送端)代码

import imageio.v3 as iio
import struct
import socket

# 初始化TCP连接
HOST = 'PC的IP地址'
PORT = 12345
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 关闭Nagle算法,减少小数据包延迟
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.connect((HOST, PORT))
connection = sock.makefile('wb')

resolution = (640, 480)
fps = 30

try:
    # 捕获摄像头帧,直接编码为JPEG(质量可调,越低延迟越低)
    for frame in iio.imiter("<video0>", size=resolution, fps=fps):
        # 编码为JPEG字节流,质量设为30(平衡画质和延迟)
        jpeg_data = iio.imwrite("<bytes>", frame, format="jpeg", quality=30)
        # 发送帧长度 + JPEG数据
        connection.write(struct.pack('<L', len(jpeg_data)))
        connection.write(jpeg_data)
        connection.flush()  # 强制发送缓冲区数据,避免攒帧延迟
finally:
    connection.close()
    sock.close()

PC端(接收端)代码

import imageio.v3 as iio
import struct
import socket
import numpy as np

HOST = '0.0.0.0'  # 监听所有地址
PORT = 12345

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)

print("等待连接...")
conn, addr = sock.accept()
connection = conn.makefile('rb')

try:
    while True:
        # 读取帧长度
        len_data = connection.read(struct.calcsize('<L'))
        if not len_data:
            break
        framelen = struct.unpack('<L', len_data)[0]
        # 读取JPEG数据并解码为numpy数组
        jpeg_data = connection.read(framelen)
        frame = iio.imread(jpeg_data, format="jpeg")
        # frame为numpy数组,可直接处理
        print(f"接收帧形状: {frame.shape}")
finally:
    connection.close()
    conn.close()
    sock.close()

2. 进一步压低延迟的技巧

  • 降低分辨率/帧率:如果对画质要求不高,用320x240+15fps能进一步减少数据量
  • 使用TCP_NODELAY:如代码中所示,关闭Nagle算法避免小数据包等待合并
  • 优先单帧即时发送:不要攒帧,每捕获一帧就立即编码发送,保证实时性
  • 启用硬件加速编码:树莓派上imageio默认会优先调用libjpeg-turbo后端,可加速JPEG编码

为什么比pickle方案高效?

pickle序列化的是原始numpy数组(比如640x480x3的帧,原始大小约900KB),而JPEG压缩后(质量30)仅10-20KB,数据量减少90%以上,传输时间大幅缩短,延迟自然降低。


内容的提问来源于stack exchange,提问作者Yann Bouteiller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:00:57