执行 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/