簡體   English   中英

如何在 Python 中通過 ZeroMQ PUB/SUB 從 Raspberry Pi 接收圖像?

[英]How to receive images from Raspberry Pi over ZeroMQ PUB/SUB in Python?

我想將 Picamera 在 Raspberry Pi 上拍攝的圖像發送到我的 windows 計算機。

我寫了一些代碼,如下(它們在這里被簡化了),但它卡在了
client.py中的frame = footage_socket.recv_string()

我沒有收到任何錯誤,但它總是卡在代碼中,就像它凍結一樣,不能 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
    

Q :如何在 Python 中通過 ZeroMQ PUB/SUB從樹莓派接收圖像?

觀察:

沒有錯誤。

您應該使用其他數據采集策略+設置一些自衛參數。

.recv_string() -方法在阻塞模式下被調用(它確實並且將永遠阻塞代碼執行,直到任何合理的符合規則成為可交付

使用zmq.NOBLOCK標志可以讓您避免這種阻塞模式 + 使用.poll()方法可以幫助您設計私有事件驅動循環的邏輯,在某些情況下調用.recv( zmq.NOBLOCK ) ,確實存在是准備交付的東西。

SUB -side 將不會收到任何東西,除非正確訂閱以接收某些東西,默認的 state - 與報紙一樣 - 將不會收到任何東西,除非明確訂閱。 根據 API 記錄的策略,訂閱任何內容的最安全模式是使用.setsockopt( zmq.SUBSCRIBE, "" )方法訂閱零長度字符串。

最后但並非最不重要的一點是,如果願意進行 RPi-Win 流式傳輸,可能會有一個虎鉗策略,因為除了最新的frame之外,將任何內容入隊/發布/傳輸/接收/出隊都沒有任何價值,對於.setsockopt( zmq.CONFLATE, 1 )已准備就緒。

您可能需要對資源進行更多調整,以提高.Context( nIOthreads )性能、保留隊列深度、L3 堆棧參數以及許多進一步可能的增強功能。

始終設置.setsockopt( zmq.LINGER, 0 )因為您永遠不知道哪些版本將連接以及可能發生哪些默認設置,在這里,有機會讓您崩潰的 sockets 實例永遠掛起(通常直到操作系統重新啟動),對於任何生產級軟件來說,這似乎有點瘋狂、未處理的風險因素,不是嗎?


解決方案提示:

  • 避免錯過 unicode 約定的風險,這些約定在 Linux 端發起者和 Windows O/S 端之間是不同的,彼此不匹配。

+
由於 unicode 對象具有廣泛的表示形式,因此它們不會根據其編碼存儲為字節,而是以稱為 UCS 的格式(較舊的固定寬度 Unicode 格式)存儲。 在某些平台(OS X、Windows)上,存儲是 UCS-2,即每個字符 2 個字節。 在大多數ix 系統上,它是 UCS-4,即每個字符 4 個字節。 unicode object 的緩沖區內容不依賴於編碼(總是 UCS-2 或 UCS-4),但它們依賴於平台
...
+
這里的效率問題來自這樣一個事實,即簡單的 ascii 字符串在 memory 中是所需大小的 4 倍(在大多數 Linux 上,在其他平台上是 2 倍)。 此外,要轉換到/從 C 代碼與 char 一起使用,您始終必須復制數據並對字節進行編碼/解碼。 從 memory 的角度來看,這確實是非常低效的。 本質上,在 memory 效率對您很重要的地方,您永遠不應該使用字符串; 使用字節。 問題是用戶幾乎總是使用str ,並且在 2.x 中它們是有效的,但在 3.x 中它們不是。 我們想確保我們不會幫助用戶犯這個錯誤,所以我們確保zmq方法不會試圖隱藏字符串的真正含義。

  • 閱讀有關 ZeroMQ 中延遲避免的更多信息,如果嘗試 stream 常量和先驗已知圖像( 640 x 480 x <colordepth> ) - 轉換是昂貴的,轉換小規模、低分辨率、低 FPS RGB / IR 圖片如果 RPi 和 Win 設備之間使用本地 LAN 或專用 WLAN 網段,則將其轉換為 JPEG 文件格式僅用於傳輸是沒有意義的。 延遲驅動的設計可以通過使用cPickle.dumps()dill.dumps()測試並可能避免任何類型的數據壓縮,而是在二進制塊 BLOB 中盡可能緊湊地發送數據,通常足以使用aNumpyObject.data utility to send straight from <read-write buffer for 0x7fa3cbe3f8a0, size 307200, offset 0 at 0x7f632bb2cc30> or doing some binary mangling using struct.pack() / .unpack() -methods, if in a need to go beyond the numpy可用的.data訪問技巧。 所有給定的.setsockopt( zmq.CONFLATE, 1 )在兩側都被激活,以避免緩沖實時流數據的任何過度深度。

  • 出於性能和延遲的原因,您可以避免使用PUB/SUB對原型,因為 ZeroMQ API v3.+ 已將 TOPIC 過濾的工作負載轉移到PUB側,這是您較弱的節點(而 RPi 有幾個核心,您可以提升.Context( nIOthreads )類固醇上的實例,以獲得更多的 I/O 功能,但與 Windows 端 localhost 相比,RPi 的頻率僅為 GHz 的一小部分,並且機器人緊密控制循環可能為了控制已經吃掉了大部分)。 使用PUSH/PULL以完全相同的方式適用於 1 對 1 拓撲,並且由於在 RPi 端避免了處理,因此具有更少的處理和 E2E 延遲開銷。

對於基於.poll()的、不同優先級的事件處理程序,以及關於 Margaret HAMILTON 夫人和她的 MIT 團隊的開創性工作的一些評論,可能喜歡閱讀this & this

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM