通过socket发送前的Python帧数据优化

标签 python opencv raspberry-pi

执行 Adrian's guide 的第 6 步和其他一些人一样,我设法以 10 fps 的速度和 0.1 秒的延迟从我的树莓派流式传输到我的笔记本电脑。问题是,当我在我的实验室(配备了一个古董路由器)中测试这个系统时,它只能以 1-1.5 秒的延迟流式传输 1-2 fps,这对于我打算用它们做的事情来说是完全不能接受的帧。

现在,我的方法简单明了:树莓派上的服务器捕获一个帧并将其存储为 320x240x3 矩阵,就像上面提到的指南一样,然后对该矩阵进行 pickle 处理并通过 TCP 套接字继续传输它。笔记本电脑上的客户端不断接收这些帧,对它们进行一些处理,最后用 imshow 显示结果。我的代码对于一篇文章来说相当长(大约 200 行),所以如果可以的话我宁愿避免展示它。

是否有任何方法可以减少每帧数据的大小(pickle 320x240x3 矩阵,其长度为 230 kB)或者是否有更好的方法来传输该数据?

编辑:

好吧,pickled 数组的确切长度是 230563 字节,有效负载数据应该至少是 230400 字节,所以开销应该不超过包总大小的 0.07%。我认为这将问题缩小到无线连接质量和将数据编码为字节的方法(pickling 似乎很慢)。无线问题可以通过创建 ad-hoc 网络(听起来很有趣,但我还没有尝试过)或简单地购买更好的路由器来解决,编码问题可以通过 Aaron 的解决方案来解决。希望这对 future 的读者有所帮助:)

最佳答案

tl;dr:struct实际上很慢..而不是pickle使用 np.ndarray.tobytes()结合np.frombuffer()以消除开销。

我不太精通 opencv ,这可能是最好的答案,但加速传输的一种直接方法可能是使用 struct打包和解包要通过网络发送的数据而不是 pickle .

这是发送 numpy 的示例使用 struct 在套接字上的已知尺寸数组

import numpy as np
import socket
import struct

#----- server ------
conn = socket.socket()
#connect socket somewhere
arr = np.random.randint(0,256,(320,240,3), dtype="B") # unsigned bytes "B": camera likely returns 0-255 pixel values
conn.write(struct.pack('230400B', *arr.flat)) #230400 unsigned bytes

#----- client ------
conn = socket.socket()
#connect socket somewhere
data = conn.read(230400) #read 230400 bytes
arr = np.array(struct.unpack('230400B', data), dtype='B').reshape((320,240,3),)

编辑

一点挖掘显示 numpy 有一个 tobytes将数据的内存 View 公开为 bytes 的函数目的。这基本上完成了 struct 的工作,而无需在函数调用中对参数进行解包以进行编码。这促使我也想看看我们是否也可以进行拆包,只要您愿意稍微凭感觉飞行(中断或错误不会被优雅地发现),我们就可以打包和拆包开销几乎为零的数据是您网络的唯一限制因素。

测试脚本:

arr = np.random.randint(0,256,(320,240,3), dtype="B") # unsigned bytes "B": camera likely returns 0-255 pixel values

t = time()
for _ in range(100):
    arr2 = pickle.loads(pickle.dumps(arr))
print(f'pickle pack, pickle unpack: {time()-t} sec')

t = time()
for _ in range(100):
    arr2 = np.array(struct.unpack('230400B', struct.pack('230400B', *arr.flat)), dtype='B').reshape((320,240,3),)
print(f'struct pack, struct unpack: {time()-t} sec')

t = time()
for _ in range(100):
    arr2 = np.array(struct.unpack('230400B', arr.tobytes()), dtype='B').reshape((320,240,3),)
print(f'numpy pack, struct unpack: {time()-t} sec')

t = time()
for _ in range(100):
    arr2 = np.frombuffer(arr.tobytes(), dtype="B").reshape((320,240,3),)
print(f'numpy pack, numpy unpack: {time()-t} sec')

打印:

pickle pack, pickle unpack: 0.005013704299926758 sec
struct pack, struct unpack: 3.558577299118042 sec
numpy pack, struct unpack: 1.2988512516021729 sec
numpy pack, numpy unpack: 0.0010025501251220703 sec

关于通过socket发送前的Python帧数据优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49784551/

相关文章:

python - 尝试在开始点和结束点之间复制/粘贴文本、转置和交换数据点

python - 成功导入的类是无,但仅在方法内部

c++ - 打印时出现奇怪的像素值?

c++ - OpenCV detectMultiScale() 参数的推荐值

java - 在 "Raspberry Pi"(Windows) 的 QEMU 模拟上设置 Jenkins CI 服务器

Python:bottle.py 的类似 mod_rewrite 的函数

无法找到 Python kivy 入口点 inflateRest2 libpng16-16.dll

python - 如何将 OpenCV 直方图保存到 Python 文件中?

linux - ubuntu 上的内核版本不正确

node.js - Raspberry Pi : MongoError: Server at localhost:27017 reports wire version 0, 但此版本的 Node.js 驱动至少需要 2 个 (MongoDB2.6)