gpt4 book ai didi

python - 如何将视频流从一个 python 传递到另一个?

转载 作者:行者123 更新时间:2023-12-03 15:12:57 25 4
gpt4 key购买 nike

在我之前的文章中,我们找到了一种将图像文件从一个 python 传递到另一个 python 的方法:
pass video data from one python script to another
我现在正在尝试传递视频(连续图像):
写.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)
阅读.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 似乎永远不会得到它。
我的猜测是,读取代码正在等待写入代码“结束”,然后才将数据包打包并称为图像。虽然如果是这样的话,我认为做同花顺可以解决它。

最佳答案

我想我想通了。在 read.py 中, sys.stdin.buffer.read() 读取并等待 stdin 管道关闭,但由于 write.py 循环,stdout 从未真正关闭其 while True。这个概念验证简化示例有效: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" 写入任何内容。如果我们从 while True 中删除 write.py 循环,代码将不再挂起, "Hello World" 将被写入 "output.py" 因为当 write.py 完成写入时,它将关闭其进程并关闭管道。为了解决这个问题,我建议将 read.py 更改为这样的:
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 是否应该等待另一个文件

  • 对于第 1 部分,我们只是将文件的长度编码为一个在前面填充 0 的字符串。注意:确保 MAX_FILE_SIZE 大于最大文件的大小(大的数字会稍微降低性能)。对于第 3 部分,如果我们发送 "1",则意味着没有更多文件要发送。否则 reader.py 将等待并接受下一个文件。所以 write.py 将变成:
    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 传递到另一个?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66353952/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com