cv::imshow 通过 SSH x11 太慢了。备择方案?
cv::imshow over SSH x11 too slow. alternatives?
我有一个应用程序处理来自相机的实时帧,然后使用 imshow 输出结果帧。当 运行 在本地机器上运行时一切顺利。
但是,我需要通过 SSH 调用此应用程序并且仍能以某种方式看到视频(不需要通过 ssh)。目前该应用程序仅适用于 X11 转发,但帧速率非常糟糕并且存在巨大延迟。
有没有更好的方法可以最大限度地减少滞后和延迟?
我尝试了几种方法来提高 OpenCV imshow()
在 ssh
连接上的性能。我使用 Mac 作为我的本地桌面,使用 Raspberry 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 -X
或 ssh -Y
和 运行 进入 Raspberry Pi 而没有 :
export DISPLAY=<MAC_IP_ADDRESS>:0
./opencvScript
这带来了更好的性能,但仍然不是开创性的。
然后我决定使用 Redis,这是一个非常高性能的内存数据结构服务器。在 Mac 或任何其他机器上安装都很简单。它允许您在网络中任意数量的客户端之间共享原子整数、字符串、列表、散列、队列、集合和有序集合。因此,我只是简单地进行 JPEG 编码并将每个视频帧从 Raspberry Pi 发送到 Redis,然后尽可能快地在我的 Mac 上拾取帧并显示它们。它工作起来如丝般顺畅,并在大约 3 秒内完成 256 帧 640x480 彩色视频,即 80 fps。
所以这是 DisplayServer
我 运行 在我的 Mac 上。它只是尽可能快地抓取最新图像并显示它:
#!/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 甚至命令行。因此,下面的行,当 shell 中的 运行 时,将抓取视频的最新帧,例如:
redis-cli hgetall latest
这是一段代码的小视频,它只是将蓝色通道从 0 增加到 255 以产生 255 帧。如您所见,它从 Raspberry Pi(在较低的终端 window 中)到 Mac(在较高的终端 window 运行 中显示服务器代码) 大约 3 秒。
我还做了一个使用套接字传输 JPEG 编码图像的版本,速度几乎一样快,但有点丑陋,而且灵活性和无缓冲性也较差,也不能从外部控制或调试就像 Redis 一样。
关键字: Raspberry Pi, OpenCV, display, remote display, X11, tunnel, ssh, DISPLAY, Redis, buffer, image, image processing, performance, XQuartz , 听, 传入, 连接。
我有一个应用程序处理来自相机的实时帧,然后使用 imshow 输出结果帧。当 运行 在本地机器上运行时一切顺利。
但是,我需要通过 SSH 调用此应用程序并且仍能以某种方式看到视频(不需要通过 ssh)。目前该应用程序仅适用于 X11 转发,但帧速率非常糟糕并且存在巨大延迟。
有没有更好的方法可以最大限度地减少滞后和延迟?
我尝试了几种方法来提高 OpenCV imshow()
在 ssh
连接上的性能。我使用 Mac 作为我的本地桌面,使用 Raspberry 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 -X
或 ssh -Y
和 运行 进入 Raspberry Pi 而没有 :
export DISPLAY=<MAC_IP_ADDRESS>:0
./opencvScript
这带来了更好的性能,但仍然不是开创性的。
然后我决定使用 Redis,这是一个非常高性能的内存数据结构服务器。在 Mac 或任何其他机器上安装都很简单。它允许您在网络中任意数量的客户端之间共享原子整数、字符串、列表、散列、队列、集合和有序集合。因此,我只是简单地进行 JPEG 编码并将每个视频帧从 Raspberry Pi 发送到 Redis,然后尽可能快地在我的 Mac 上拾取帧并显示它们。它工作起来如丝般顺畅,并在大约 3 秒内完成 256 帧 640x480 彩色视频,即 80 fps。
所以这是 DisplayServer
我 运行 在我的 Mac 上。它只是尽可能快地抓取最新图像并显示它:
#!/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 甚至命令行。因此,下面的行,当 shell 中的 运行 时,将抓取视频的最新帧,例如:
redis-cli hgetall latest
这是一段代码的小视频,它只是将蓝色通道从 0 增加到 255 以产生 255 帧。如您所见,它从 Raspberry Pi(在较低的终端 window 中)到 Mac(在较高的终端 window 运行 中显示服务器代码) 大约 3 秒。
我还做了一个使用套接字传输 JPEG 编码图像的版本,速度几乎一样快,但有点丑陋,而且灵活性和无缓冲性也较差,也不能从外部控制或调试就像 Redis 一样。
关键字: Raspberry Pi, OpenCV, display, remote display, X11, tunnel, ssh, DISPLAY, Redis, buffer, image, image processing, performance, XQuartz , 听, 传入, 连接。