在我之前的文章中,我们找到了一种将图像文件从一个Python脚本传递到另一个脚本的方法:将视频数据从一个python脚本传递到另一个脚本
我现在试图通过一个视频(连续的图像):
write.py
import sys
import numpy as np
import cv2
from PIL import Image
import io
import time
while True:
img = cv2.imread('cat.jpg')
bimg = cv2.imencode('.jpg',img)[1]
sys.stdout.buffer.write(bimg)
sys.stdout.flush()
time.sleep(1)
read.py:
import sys
from PIL import Image
import io
import cv2
import numpy as np
from io import BytesIO
while True:
data = sys.stdin.buffer.read()
img_np = cv2.imdecode(np.frombuffer(BytesIO(data).read(), np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('image', img_np)
cv2.waitKey(0)
如果我将write.py数据输出到终端,它会打印。如果我手动将数据传递到read.py,它会被读取。但将它们放在一起(python3 write.py | python3 read.py
),它就会挂起。write.py只写入一次,而read.py似乎永远不会得到它。
我猜读代码是在等待写代码“结束”,然后才打包数据包并将其称为图像。如果是这样的话,我会认为执行一次刷新就可以修复它。
4条答案
按热度按时间soat7uwm1#
我想我明白了。在
read.py
中,sys.stdin.buffer.read()
读取并等待直到stdin
管道关闭,但是write.py
实际上从未关闭它的stdout
,因为while True
循环。这个概念证明简化的例子是有效的:write.py
和
read.py
之间的关系如果我们从
write.py
中删除while True
循环,代码将不再挂起,并且"Hello World"
将被写入"output.py"
,因为当write.py
完成写入时,它将关闭其进程,从而关闭管道。要解决此问题,我建议将read.py
更改为如下内容:解决方法:
x1米15英寸
和
read.py
之间的关系1.发送文件的大小
1.发送实际文件数据
1.发送一个字节,告诉
read.py
是否应该等待另一个文件对于第1部分,我们只是将文件的长度编码为字符串,并在前面用0填充。注意:请确保
MAX_FILE_SIZE
大于最大文件的大小(大的数字会稍微降低性能)。对于第3部分,如果我们发送一个"1"
,这意味着没有更多的文件要发送。否则reader.py
将等待并接受下一个文件。因此write.py
将变为:和
read.py
将变为:ymdaylpp2#
你提到你要发送的图片大小不一致,但我必须假设它是否来自同一台相机(对于给定的视频流)原始图像的大小不会改变,而只是压缩图像的大小。我可以想象,您可能有足够的内存来一次存储至少一个未压缩的帧,而所有的压缩和解压缩只会带来处理开销。
假设我会使用
multiprocessing.shared_memory
创建一个共享缓冲区,它可以在两个进程之间共享帧(如果你想得到真实的的幻想,你甚至可以创建一个两个帧的循环缓冲区,并防止屏幕撕裂,但在我的测试中这不是一个大问题)假设
cv2.VideoCapture().read()
可以直接读取一个现有的数组,并且你可以创建一个numpy数组,它使用共享内存作为缓冲区,你可以将数据读取到共享内存中,而不需要额外的复制。使用这个方法,我可以每秒读取用H.264编码的1280x688分辨率的视频文件中的近700帧。读取器的过程看起来非常相似,但是我们没有创建视频设备和
read
帧,我们只是构造了共享数组和imshow
。GUI没有转储数据那么快,所以我们没有得到700 fps,但是500 fps也不错...**编辑:**用户的其他问题表明,可能需要python 3.8之前的版本(甚至可以跨版本工作),因此下面是使用
posix_ipc
代替multiprocessing.shared_memory
创建帧缓冲区的示例(以及如何清理它):x33g5p2x3#
两种解决方案:零MQ|磁盘缓存
使用ZeroMQ将帧从一个python文件发送到另一个python文件非常容易。
零MQ
通过PyPI安装:
pip install -U pyzmq
。发送帧的方式有多种。这是使用PUBLISHER和SUBSCRIBER的示例第一个
磁盘缓存
你也可以考虑使用
diskcache
。它允许python对象通过内存传递。它和Redis一样,但都是Python,不需要服务器。注意:pip install --upgrade diskcache
。您可以调整以开始从摄像机发送实时帧|视频第一次
我将按照这些方向而不是
sys
进行操作,因为您可以完全控制流数据。参见diskcache Documentationyr9zkbsy4#
那么使用ROS发布器和订阅器呢?这将是简单的实现和容易察觉。