Потоковое видео с Raspberry PI - Python против raspivid + netcat - PullRequest
0 голосов
/ 01 марта 2019

Я работаю над решением для потокового сетевого видео с использованием Raspberry PI 3 B +, где ключевым фактором является низкая задержка.

Первый метод, который я использовал, - это передача stdout из raspivid в поток TCP Netcat:

# On the Raspberry:
raspivid -w 640 -h 480 --nopreview -t 0 -o - | nc 192.168.64.104 5000

# On the client:
nc -l -p 5000 | mplayer -nolirc -fps 60 -cache 1024 -

Этот метод имеет довольно низкую задержку, и я был в целом удовлетворен результатами.

Однако мне необходимо выполнить некоторую обработку изображений на стороне клиента.Я попытался повторить описанный выше метод, используя python.Я нашел похожее решение в документации модуля Python 'picamera' :

На Raspberry:

import io
import socket
import struct
import time
import picamera

# Connect a client socket to my_server:8000 (change my_server to the
# hostname of your server)
client_socket = socket.socket()
client_socket.connect(('my_server', 8000))

# Make a file-like object out of the connection
connection = client_socket.makefile('wb')
try:
    camera = picamera.PiCamera()
    camera.resolution = (640, 480)
    # Start a preview and let the camera warm up for 2 seconds
    camera.start_preview()
    time.sleep(2)

    # Note the start time and construct a stream to hold image data
    # temporarily (we could write it directly to connection but in this
    # case we want to find out the size of each capture first to keep
    # our protocol simple)
    start = time.time()
    stream = io.BytesIO()
    for foo in camera.capture_continuous(stream, 'jpeg'):
        # Write the length of the capture to the stream and flush to
        # ensure it actually gets sent
        connection.write(struct.pack('<L', stream.tell()))
        connection.flush()
        # Rewind the stream and send the image data over the wire
        stream.seek(0)
        connection.write(stream.read())
        # If we've been capturing for more than 30 seconds, quit
        if time.time() - start > 30:
            break
        # Reset the stream for the next capture
        stream.seek(0)
        stream.truncate()
    # Write a length of zero to the stream to signal we're done
    connection.write(struct.pack('<L', 0))
finally:
    connection.close()
    client_socket.close()

На клиенте:

import io
import socket
import struct
import cv2
import numpy as np

server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)

# Accept a single connection and make a file-like object out of it
connection = server_socket.accept()[0].makefile('rb')
try:
while True:
    # Read the length of the image as a 32-bit unsigned int. If the
    # length is zero, quit the loop
    image_len = struct.unpack('<L', connection.read(struct.calcsize('<L')))[0]
    if not image_len:
        break
    # Construct a stream to hold the image data and read the image
    # data from the connection
    image_stream = io.BytesIO()
    image_stream.write(connection.read(image_len))
    # Rewind the stream, open it as an image with opencv and do some
    # processing on it
    image_stream.seek(0)

    data = np.fromstring(image_stream.getvalue(), dtype=np.uint8)
    imagedisp = cv2.imdecode(data, 1)

    cv2.imshow("Frame",imagedisp)
finally:
    connection.close()
    server_socket.close()

Этот метод имеет гораздо худшую задержку, и я пытаюсь выяснить причину.Как и первый метод, он использует поток TCP для отправки кадров из буфера памяти.

Цель состоит в том, чтобы как можно быстрее подготовить кадры для обработки с помощью OpenCV на клиенте.Поэтому, если у кого-то есть способ добиться этого лучше, чем приведенный выше, буду признателен, если вы поделитесь им.

...