通过TCP远程显示图像RDI

在我们使用docker、wsl或者使用ssh连接linux服务器处理图像时,由于只存了命令行,无法在调试代码的过程中直观的显示图像辅助调试。为了解决这个痛点,可以将图像实时发送到本地带图像界面的电脑上并且显示图像!原理就是在本地建立一个tcp服务器一直接收发送过来的图像。python(c++后续有需要会写)例程代码如下:

"""
Remote display image
远程显示图像的库
"""
import socket
import cv2
import numpy


class RDIs():
    """
    Remote display image server 远程显示图像的服务端
    通过传入 address = ('0.0.0.0', 8001) 来改变本地ip的地址和端口
    """
    localAddress = ''
    connect = ''
    frame = ''
    sock = ''

    def __init__(self, address=('0.0.0.0', 8001)):
        # 首先检查输入参数是否正确
        if not (isinstance(address, tuple) and isinstance(address[0], str) and isinstance(address[1], int)):
            print(
                "\033[31m错误: 请输入正确的ip:port, 例如: address=('0.0.0.', 8002)\033[0m")
            return
        # 配置本地socket
        self.localAddress = address
        # socket.AF_INET:服务器之间网络通信   socket.SOCK_STREAM:流式socket , for TCP
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(address)
        self.sock.listen(1)

    def __del__(self):
        self.sock.close()

    def recvFrame(self):
        """ 开始接收图像并显示 """
        self.connect, self.localAddress = self.sock.accept()
        print(self.localAddress[0]+':',
              self.localAddress[1], " 连接成功!\n正在接收数据并显示图像...")

        cv2.namedWindow('ReceivedImage', cv2.WINDOW_NORMAL)
        cv2.resizeWindow('ReceivedImage', 1600, 900)
        cv2.moveWindow('ReceivedImage', 0, 0)
        # 循环接收图像,socket.MSG_WAITALL参数保证每次必须接收到足够的数据才返回
        while True:
            length = self.connect.recv(16, socket.MSG_WAITALL)
            if length is not b'':
                strData = self.connect.recv(
                    int(length), socket.MSG_WAITALL)  # 根据获得的文件长度,获取图片文件
                if strData is not b'':
                    imgData = numpy.frombuffer(
                        strData, numpy.uint8)  # 将获取到的字符流数据转换成1维数组
                    frame = cv2.imdecode(imgData, cv2.IMREAD_COLOR)  # 将数组解码成图像
                    self.frame = frame
            cv2.imshow('ReceivedImage', self.frame)  # 显示图像
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break  # 退出
        cv2.destroyAllWindows()
        self.sock.close()


class RDIc():
    """
    Remote display image client 远程显示图像的客户端
    通过传入 address = ('127.0.0.1', 8001) 来改变本地ip的地址和端口
    """
    address = ''
    frame = ''
    sock = ''

    def __init__(self, address=('127.0.0.1', 8001)):
        # 首先检查输入参数是否正确
        if not (isinstance(address, tuple) and isinstance(address[0], str) and isinstance(address[1], int)):
            print(
                "\033[31m错误: 请输入正确的ip:port, 例如: address=('127.0.0.1', 8001)\033[0m")
            return
        self.address = address
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 连接失败的话会一直尝试重连
        while True:
            try:
                self.sock.connect(self.address)
                print(self.address[0]+':', self.address[1], " 连接成功!")
                break
            except:
                print('\033[31m', self.address[0]+':',
                      self.address[1], " 连接失败,尝试重连!\033[0m")

    def __del__(self):
        self.sock.close()

    def sendFrame(self, frame, encode_param=[int(cv2.IMWRITE_JPEG_QUALITY), 10]):
        """ 发送一帧图像 """
        self.frame = frame
        retval, imgencode = cv2.imencode('.jpg', frame, encode_param)
        if retval is True:
            data = numpy.array(imgencode)
            stringData = data.tobytes()
            self.sock.send(str.encode(str(len(stringData)).ljust(16)))
            self.sock.send(stringData)


# 使用例程
if __name__ == '__main__':
    # 开启另一个线程来开启RDI服务端用于接收和显示图像
    # 实际使用过程中,两行代码就行了。实例化对象后运行recvFrame
    # server = RDIs(address=('0.0.0.0', 8001))
    # server.recvFrame()
    import threading
    server = RDIs(address=('0.0.0.0', 8001))
    serverThread = threading.Thread(target=server.recvFrame)
    serverThread.start()

    # 开启RDI客户端,然后用sendFrame来发送图像
    import datetime
    rdic = RDIc(address=('127.0.0.1', 8001))
    while True:
        # 使用Numpy创建一张A4(1600*900)图像
        img = numpy.zeros((900, 1600, 3), numpy.uint8)
        cv2.putText(img, str(datetime.datetime.now()), (200, 400),
                    cv2.FONT_HERSHEY_COMPLEX, 2, (255, 255, 255))
        rdic.sendFrame(img)

由于这里是单项通信,所以要求客户端主机能够ping通服务端主机就行。也就是说,可以将服务端部署在有公网ip的服务器上的,客户端在本地,也是同样能工作的。但是反过来不行。

如果要云端服务器向本地发送图像的话,由于本地没有公网ip,可以采用先本地去连接云端,然后连接建立之后再从服务器发送图像到本地。(请自行修改代码)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值