我有一个应用程序处理实时帧从相机,然后喷出结果帧与imshow。在本地机器上运行时,所有操作都很顺利。
但是,我需要通过SSH调用这个应用程序,并以某种方式查看视频(不需要通过ssh)。目前,该应用程序只工作于X11转发,但是帧速率很差,并且存在很大的延迟。
是否有更好的方法来减少延迟和延迟?
发布于 2019-09-12 15:35:33
我尝试了几种方法来提高OpenCV的imshow()在ssh连接上的性能。我使用一个Mac作为我的本地dekstop和一个覆盆子Pi4作为远程机器,我ssh进入并正在生成图像显示在我的Mac上。
禁用ssh连接上的压缩
我试着用:
ssh -o 'Compression no' pi4这导致了大约6%-8%的吞吐量改善,因此很难做到这一点。
使用重量较轻的加密密码
我读到arcfour使用较少的资源,并允许您获得更高的吞吐量。不幸的是,我尝试过,而且它在Raspbian上是不可用的,似乎也没有任何其他轻量级密码。我使用这个命令来检查Raspberry Pi上可用的密码:
ssh -Q cipher在X11隧道外运行ssh显示
由于未能找到提高ssh吞吐量的方法,我决定不加密地发送X11,而不是通过ssh隧道发送。这意味着我在Mac上运行了以下命令,允许X服务器侦听直接连接,并告诉它允许远程主机使用它:
defaults write org.macosforge.xquartz.X11 nolisten_tcp -bool false
xhost +然后,我使用ssh或ssh -Y进入Raspberry Pi 而不使用,然后运行:
export DISPLAY=<MAC_IP_ADDRESS>:0
./opencvScript这导致了一些更好的表现,但它仍然不是突破性的。
然后,我决定使用Redis,这是一个非常高性能的内存数据结构服务器。在Mac或任何其他机器上安装都很简单。它允许您通过网络在任意数量的客户端之间共享原子整数、字符串、列表、散列、队列、集合和有序集。因此,我只是简单地JPEG编码和发送从Raspberry Pi到Redis的每一帧视频,然后尽可能快地在我的Mac上拾取这些帧并显示它们。它工作顺滑,做256帧640x480彩色视频在大约3秒,所以80 fps。
这是我在Mac上运行的DisplayServer。它只是尽可能快地抓取最新的图像并显示出来:
#!/usr/bin/env python3
import ImageTransferService
import numpy as np
import cv2
if __name__ == "__main__":
host = '0.0.0.0'
src = ImageTransferService.ImageTransferService(host)
# Check Redis is running
print(src.ping())
while True:
im = src.receiveImage()
cv2.imshow('Image',im)
cv2.waitKey(1)下面是我在发送图像的Raspberry Pi上运行的代码:
#!/usr/local/bin/python3
import numpy as np
import ImageTransferService
if __name__ == "__main__":
host = '192.168.0.8'
RemoteDisplay = ImageTransferService.ImageTransferService(host)
# Check remote display is up
print(RemoteDisplay.ping())
# Create BGR image
w, h = 640, 480
im = np.zeros((h,w,3),dtype=np.uint8)
for c in range(256):
im[:,:,0] = c
RemoteDisplay.sendImage(im)下面是隐藏Redis并提供发送、接收和缓冲图像的方法的胶水代码:
#!/usr/bin/env python3
import redis
import cv2
import numpy as np
class ImageTransferService:
def __init__(self, host='localhost', port=6379):
self.port = port
self.host = host
self.conn = redis.Redis(host,port)
self.frameNum = 0
def ping(self):
return self.conn.ping()
def sendImage(self,im, name='latest', Q=75):
_, JPEG = cv2.imencode(".JPG", im, [int(cv2.IMWRITE_JPEG_QUALITY), Q])
myDict = { 'frameNum': self.frameNum, 'Data':JPEG.tobytes() }
self.conn.hmset(name, myDict)
self.frameNum += 1
def receiveImage(self,name='latest'):
myDict = self.conn.hgetall(name)
Data = myDict.get(b'Data')
im = cv2.imdecode(np.frombuffer(Data,dtype=np.uint8), cv2.IMREAD_COLOR)
return im由于Redis有许多绑定,您可以访问数据帧,查看Redis,或者从PHP、Python、C/C++、PHP甚至命令行将内容写入Redis。因此,当在shell中运行时,下面的行将获取视频的最新帧,例如:
redis-cli hgetall latest下面是代码的一个小视频,它简单地将蓝色通道从0增加到255,从而产生255帧。正如您所看到的,它在大约3s内从Raspberry Pi (在下终端窗口)到Mac (在运行DisplayServer代码的高端终端窗口中)。

我还做了一个使用套接字传输JPEG编码的图像的版本,这个版本速度几乎一样快,但有点丑陋,而且也不那么灵活,没有缓冲,也不像Redis那样可以从外部控制或调试。
关键词:覆盆子Pi,OpenCV,显示,远程显示,X11,隧道,ssh,显示,Redis,缓冲区,图像,图像处理,性能,XQuartz,侦听,传入,连接。
https://stackoverflow.com/questions/57876639
复制相似问题