Как получить изображения от Raspberry Pi через ZeroMQ PUB / SUB в Python? - PullRequest
1 голос
/ 26 апреля 2020

Я хочу отправить изображения, сделанные Picamera на Raspberry Pi, на мой windows компьютер.

Я написал некоторый код следующим образом (они здесь упрощены), но он застрял в
frame = footage_socket.recv_string() в client.py.

Я не получаю никакой ошибки, но она всегда застревает в коде, как будто зависает и не может go перейти к следующей строке. server.py работает нормально и печатает 'test' непрерывно. Если вы посмотрите на jpg_as_text, вы можете увидеть закодированные тексты.

Было бы здорово, если бы вы могли исправить эту ошибку.

server.py:

import picamera
import socket
import threading
import zmq
import cv2
import base64
from picamera.array import PiRGBArray

if __name__ == "__main__":

    addr = 'ip_address'

    camera = picamera.PiCamera()                 # Camera initialization
    camera.resolution = (640, 480)
    camera.framerate = 7
    rawCapture = PiRGBArray(camera, size=(640, 480))

    # FPV initialization
    context = zmq.Context()
    footage_socket = context.socket(zmq.PUB)
    footage_socket.connect('tcp://%s:5555'%addr)
    print(addr)

    font = cv2.FONT_HERSHEY_SIMPLEX
    for frame in camera.capture_continuous( rawCapture,
                                            format         = "bgr",
                                            use_video_port = True ):
        image = frame.array
        print('test')
        image = cv2.resize(image, (640, 480))    # resize the frame
        encoded, buffer = cv2.imencode('.jpg', image)
        jpg_as_text = base64.b64encode(buffer)
        footage_socket.send(jpg_as_text)
        rawCapture.truncate(0)

client.py:

from socket import *
import sys
import time
import threading as thread
import tkinter as tk
import math
import os
import cv2
import zmq
import base64
import numpy as np


if __name__ == "__main__":

    context = zmq.Context()
    footage_socket = context.socket(zmq.SUB)
    footage_socket.bind('tcp://*:5555')
    footage_socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))

    font = cv2.FONT_HERSHEY_SIMPLEX

    while 100:
        try:
            frame = footage_socket.recv_string() # This line of code is the problem.

            print('next successfuly connected')
            img = base64.b64decode(frame)
            npimg = np.frombuffer(img, dtype=np.uint8)
            source = cv2.imdecode(npimg, 1)
            cv2.imshow("Stream", source)
            cv2.waitKey(1)

        except KeyboardInterrupt:
            break
        except:
            pass

1 Ответ

0 голосов
/ 26 апреля 2020

Q : Как получать изображения от Raspberry Pi через ZeroMQ PUB/SUB в Python?

Во-первых, добро пожаловать в Страны Искусств Дзэн-Зеро.


В случае, если никто никогда не работал с ZeroMQ ,
, можно здесь приятно сначала взглянуть на " ZeroMQ Принципы менее чем за Пять секунд "
, прежде чем углубляться в дальнейшие детали



НАБЛЮДЕНИЕ:

Нет ошибок.

Вы должны использовать другую стратегию сбора данных + настроить некоторые параметры самообороны.

.recv_string() -метод вызывается в режиме блокировки (он блокирует выполнение кода и даже навсегда блокирует выполнение кода до тех пор, пока что-либо правдоподобное не будет соответствовать правилам, чтобы стать доставляемым

Использование * Флаг 1043 * позволяет вам избежать такого режима блокировки + использование .poll() -метода может помочь вам в создании приватных управляемых событиями циклов 'logi c, которые вызывают .recv( zmq.NOBLOCK ) на всякий случай, действительно, что-то готово к доставке.

SUB - сторона не получит ничего, если не подписана должным образом на получение чего-либо, состояние по умолчанию, как в газетах, - это ничего не получать, если явно не подписан на «Асахи Симбун» или другое название. Самый безопасный режим подписки на любой контент, согласно документированной стратегии API, - это подписка на строку нулевой длины, используя для этого .setsockopt( zmq.SUBSCRIBE, "" ) -метод.

Последний, но не менее важный, если желая осуществлять потоковую передачу RPi-Win, может существовать стратегия тисков, поскольку не имеет смысла ставить в очередь / публиковать / транспортировать / получать / удалять очередь, кроме самой последней frame, для которой готов .setsockopt( zmq.CONFLATE, 1 ).

Вам может потребоваться дополнительная настройка ресурсов, будь то для повышения производительности .Context( nIOthreads ) экземпляра, зарезервированной глубины очереди, параметров стека L3 и многих других возможных улучшений.

Всегда устанавливать .setsockopt( zmq.LINGER, 0 ) потому что вы никогда не знаете, какие версии будут подключаться и какие значения по умолчанию могут иметь место, здесь, с возможностью позволить вашим сбойным экземплярам сокетов зависать навсегда (чаще всего до перезагрузки O / S), что кажется немного диким, необработанным фактором риска для любого программного обеспечения промышленного уровня, не так ли?


СОВЕТЫ РЕШЕНИЯ:

  • Избегайте риска пропустил Unicode-соглашения, которые отличаются, не совпадая друг с другом между Linux стороной-источником и Windows стороной O / S.

    +
    Так как объекты Unicode имеют широкий диапазон представлений, они не сохраняются как байты в соответствии с их кодированием, а скорее в формате, называемом UCS (более старый Unicode фиксированной ширины формат). На некоторых платформах (OS X, Windows) хранилище - UCS-2, которое составляет 2 байта на символ. В большинстве ix систем это UCS-4 или 4 байта на символ. Содержимое буфера объекта Unicode не зависит от кодировки (всегда UCS-2 или UCS-4), но оно зависит от платформы .
    ...
    +
    Проблема эффективности связана с тем, что простые строки ascii имеют в 4 раза больший объем памяти, чем необходимо (на большинстве Linux, в 2 раза на других платформах). Кроме того, для перевода в / из C кода, который работает с char
    , вам всегда нужно копировать данные и кодировать / декодировать байты. Это действительно ужасно неэффективно с точки зрения памяти. По сути, там, где эффективность памяти важна для вас, вы никогда не должны использовать строки; использовать байты. Проблема в том, что пользователи почти всегда будут использовать str, а в 2.x они эффективны, а в 3.x - нет. Мы хотим убедиться, что мы не помогаем пользователю совершить эту ошибку, поэтому мы гарантируем, что методы zmq не пытаются скрыть, какие строки действительно существуют.

  • Узнайте больше об избежании задержек в ZeroMQ, если вы пытаетесь передавать постоянные и априорно известные изображения ( 640 x 480 x <colordepth> ) - преобразования стоят дорого, получая небольшое изображение с низким разрешением и низким FPS RGB / IR-изображением в формат JPEG-файла просто для передачи не имеет смысла, если между RPi и Win-устройством используется локальная ЛВС или выделенный сегмент WLAN. Проект, основанный на задержке, может тестировать и, возможно, избегать любого типа сжатия данных с помощью cPickle.dumps() или dill.dumps(), но скорее отправлять данные настолько компактно, насколько это возможно в двоичном блоке BLOB, чаще всего достаточно использовать утилиту aNumpyObject.data для отправки прямо с <read-write buffer for 0x7fa3cbe3f8a0, size 307200, offset 0 at 0x7f632bb2cc30> или выполнением некоторого бинарного искажения с использованием struct.pack() / .unpack() -методов, если необходимо go за пределами доступного numpy доступного трюка с доступом .data. Все данные с учетом .setsockopt( zmq.CONFLATE, 1 ) были активированы с обеих сторон во избежание чрезмерной глубины буферизации данных потокового вещания.

  • По причинам, связанным с производительностью и задержкой, вы можете избежать PUB/SUB пару архетипов, поскольку ZeroMQ API v3. + переместил рабочую нагрузку фильтра TOPI C на сторону PUB, которая является вашим более слабым узлом (в то время как RPi имеет несколько ядер, и вы можете повысить .Context( nIOthreads ) -экземпляр на стероидах, чтобы иметь больше мощности для ввода / вывода, но RPi имеет долю ГГц по сравнению с вашим Windows -объединенным локальным хостом, и роботизированные c -контурные контрольные циклы, возможно, уже съели большую часть что за контроль). Использование PUSH/PULL будет подходить точно так же для топологии 1-к-1, плюс меньшие издержки на обработку и задержку E2E из-за избежания обработки на стороне RPi.

Для .poll() обработчиков событий с различными приоритетами и нескольких замечаний о плодотворной работе миссис Маргарет Хэмилтон и ее команды MIT, возможно, захочется прочитать this & this .

...