How to pass video stream from one Python to another?(如何将视频流从一个 Python 传递到另一个?)
问题描述
在我之前的帖子中,我们找到了一种将图像文件从一个 Python 传递到另一个 Python 的方法:将视频数据从一个 python 脚本传递到另一个
In my previous post, we found a way to pass an image file from one Python to another: pass video data from one python script to another
我现在正在尝试传递视频(连续图像):
I am now trying to pass a video (successive images):
写.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 似乎永远不会得到它.
If I output the write.py data to terminal, it prints. If I manually hand data to read.py that gets read. But put them together (python3 write.py | python3 read.py
) and it just hangs. write.py just writes once, and read.py never seems to get it.
我的猜测是读取代码正在等待写入代码结束"在它包装数据包并将其称为图像之前.虽然如果是这样的话,我认为进行冲洗会解决它.
My guess is that the read code is waiting for the write code to "end" before it wraps up the data package and calls it an image. Though if that were the case, I would think it that doing a flush would fix it.
推荐答案
我想我明白了.在 read.py
中,sys.stdin.buffer.read()
读取并等待 stdin
管道关闭但 写入.由于
从未真正关闭它的 while True
循环,pystdout
.这个概念验证简化示例有效:
I think I figured it out. In read.py
, sys.stdin.buffer.read()
reads and waits until the stdin
pipe is closed but write.py
never actually closes its stdout
because of the while True
loop. This proof of concept simplified example works:
write.py
import sys
import time
sys.stdout.buffer.write(b"Hello world")
sys.stdout.buffer.flush()
# Note if we comment out the code bellow it works again
while True:
# Keep this alive but don't have `while True:pass`
# because my computer might crash :D
time.sleep(10)
和 read.py
import sys
with open("output.txt", "w") as file:
file.write(sys.stdin.read())
这也将挂起,并且永远不会真正向 output.txt"
写入任何内容.如果我们从 write.py
中删除 while True
循环,代码将不再挂起,Hello World"
将写入 "output.py"
因为当 write.py
完成写入时,它将关闭其进程并关闭管道.为了解决这个问题,我建议将 read.py
更改为这样的:
This will also hang and will never actually write anything to "output.txt"
. If we remove the while True
loop from write.py
the code will no longer hang and "Hello World"
will be written to "output.py"
because when write.py
is finished writing it will close its process and that will close the pipe. To fix this issue I recommend changing read.py
to something like this:
import sys
while True:
with open("output.txt", "a") as file:
file.write(sys.stdin.read(1))
解决方案:
write.py
import sys
import time
MAX_FILE_SIZE = 16 # bytes
msg = b"Hello world"
# Tell `reader.py` that it needs to read x number of bytes.
length = len(msg)
# We also need to tell `read.py` how many bytes it needs to read.
# This means that we have reached the same problem as before.
# To fix that issue we are always going to send the number of bytes but
# We are going to pad it with `0`s at the start.
# https://stackoverflow.com/a/339013/11106801
length = str(length).zfill(MAX_FILE_SIZE)
sys.stdout.buffer.write(length.encode())
sys.stdout.buffer.write(msg)
sys.stdout.buffer.flush()
# We also need to tell `read.py` that it was the last file that we send
# Sending `1` means that the file has ended
sys.stdout.buffer.write(b"1")
sys.stdout.buffer.flush()
# Note if we comment out the code bellow it works again
while True:
# Keep this alive but don't have `while True:pass`
# because my computer might crash :D
time.sleep(10)
和 read.py
import sys
import time
MAX_FILE_SIZE = 16 # bytes
while True:
time.sleep(1) # Make sure `write.py` has sent the data
# Read `MAX_FILE_SIZE` number of bytes and convert it to an int
# So that we know the size of the file comming in
length = int(sys.stdin.buffer.read(MAX_FILE_SIZE))
time.sleep(1) # Make sure `write.py` has sent the data
# Here you can switch to a different file every time `writer.py`
# Sends a new file
with open("output.txt", "wb") as file:
file.write(sys.stdin.buffer.read(length))
file_ended = sys.stdin.buffer.read(1)
if file_ended == b"1":
# File has ended
break
else:
# We are going to start reading again for the next file:
pass
解决方法如下:
- 发送文件大小
- 发送实际文件数据
- 发送一个字节,告诉
read.py
是否应该等待另一个文件
- Send the size of the file
- Send the actual file data
- Send a byte that tell
read.py
if it should be expecting another file or not
对于第 1 部分,我们只是将文件的长度编码为一个在前面填充 0 的字符串.注意:确保 MAX_FILE_SIZE
大于最大文件的大小(大的数字会稍微降低性能).对于第 3 部分,如果我们发送 1"
,则意味着没有更多文件要发送.否则 reader.py
将等待并接受下一个文件.所以 write.py
会变成:
For part 1, we just encode the length of the file as a string that is padded with 0s at the front. Note: Make sure that the MAX_FILE_SIZE
is larger than the size of the largest file (large numbers will slightly decrease the performance). For part 3, if we send a "1"
it will mean that there are no more files to be sent. Otherwise reader.py
will wait and accept the next file. So write.py
will become:
from math import log
import time
import sys
import cv2
MAX_FILE_SIZE = 62914560 # bytes
MAX_FILE_SIZE = int(log(MAX_FILE_SIZE, 2)+1)
def write_file(buffer, data, last_file=False):
# Tell `reader.py` that it needs to read x number of bytes.
length = len(data)
# We also need to tell `read.py` how many bytes it needs to read.
# This means that we have reached the same problem as before.
# To fix that issue we are always going to send the number of bytes but
# We are going to pad it with `0`s at the start.
# https://stackoverflow.com/a/339013/11106801
length = str(length).zfill(MAX_FILE_SIZE)
with open("output.txt", "w") as file:
file.write(length)
buffer.write(length.encode())
# Write the actual data
buffer.write(data)
# We also need to tell `read.py` that it was the last file that we send
# Sending `1` means that the file has ended
buffer.write(str(int(last_file)).encode())
buffer.flush()
while True:
img = cv2.imread("img.jpg")
bimg = cv2.imencode(".jpg", img)[1]
# Call write_data
write_file(sys.stdout.buffer, bimg, last_file=False)
# time.sleep(1) # Don't need this
和 read.py
将变成:
from io import BytesIO
from math import log
import numpy as np
import time
import cv2
import sys
MAX_FILE_SIZE = 62914560 # bytes
MAX_FILE_SIZE = int(log(MAX_FILE_SIZE, 2)+1)
def read(buffer, number_of_bytes):
output = b""
while len(output) < number_of_bytes:
output += buffer.read(number_of_bytes - len(output))
assert len(output) == number_of_bytes, "An error occured."
return output
def read_file(buffer):
# Read `MAX_FILE_SIZE` number of bytes and convert it to an int
# So that we know the size of the file comming in
length = int(read(buffer, MAX_FILE_SIZE))
# Here you can switch to a different file every time `writer.py`
# Sends a new file
data = read(buffer, length)
# Read a byte so that we know if it is the last file
file_ended = read(buffer, 1)
return data, (file_ended == b"1")
while True:
print("Reading file")
data, last_file = read_file(sys.stdin.buffer)
img_np = cv2.imdecode(np.frombuffer(BytesIO(data).read(), np.uint8),
cv2.IMREAD_UNCHANGED)
cv2.imshow("image", img_np)
cv2.waitKey(0)
if last_file:
break;
这篇关于如何将视频流从一个 Python 传递到另一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何将视频流从一个 Python 传递到另一个?
基础教程推荐
- 筛选NumPy数组 2022-01-01
- 使用PyInstaller后在Windows中打开可执行文件时出错 2022-01-01
- Python kivy 入口点 inflateRest2 无法定位 libpng16-16.dll 2022-01-01
- 在 Python 中,如果我在一个“with"中返回.块,文件还会关闭吗? 2022-01-01
- 用于分类数据的跳跃记号标签 2022-01-01
- 如何让 python 脚本监听来自另一个脚本的输入 2022-01-01
- 如何在海运重新绘制中自定义标题和y标签 2022-01-01
- 何时使用 os.name、sys.platform 或 platform.system? 2022-01-01
- Dask.array.套用_沿_轴:由于额外的元素([1]),使用dask.array的每一行作为另一个函数的输入失败 2022-01-01
- 线程时出现 msgbox 错误,GUI 块 2022-01-01