【Socket编程】利用Socket实现局域网内opecv格式图片传输

整这个的目的是,最近有个小项目希望能采用局域网实现树莓派和pc端的数据传输,只能现学现卖了。。。
因此采用Socket对opencv格式的图片在服务器端进行编码、传输。之后在客户端进行解码,显示输出,实现了局域网内的opencv图传。
代码如下

首先进行服务器端和客户端的Socket初始化
文件名transfer_init.py

import socket

host='127.0.0.1'
port=8000

def server_init():#服务器端初始化
    server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#Ipv4协议与TCP传输
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#允许端口复用
    server.bind((host,port))
    server.listen(5)
    print('主机IP:',host)
    print('端口号:',port)
    print('正在等待客户端连接。。。')
    print('\n')
    return server

def client_init(server_host,server_port):#客户端初始化
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#Ipv4协议与TCP传输
    client.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#允许端口复用
    print('正在尝试连接至服务器 host:',server_host)
    client.connect((server_host,server_port))
    
    return client

接下来以服务器端作为图片发送端,以客户端作为图片接收端,实现单张图片的传输
文件名transfer_img.py

import struct
import io
import cv2 as cv
import numpy as np

def send_img(server,frame):#用于服务器端发送opencv格式图片

    connection,client_addr=server.accept()#等待连接,并返回连接套接字和IP地址
    print('已连接客户端:',client_addr)
    try:
        connect=connection.makefile('wb')#创建传输文件,格式为二进制写
        stream=io.BytesIO()#创建一个io流,用于存放二进制数据

        img_encode=cv.imencode('.jpg',frame)[1]#图像编码
        data_encode=np.array(img_encode)#将编码数据转换为二进制数据
        stream.write(data_encode)#将二进制数据存放进io流
        print('正在传输图片')
        connect.write(struct.pack('<L',stream.tell()))#准备帧头数据,写入图片数据总长度
        connect.flush()#刷新并发送帧头

        stream.seek(0)
        connect.write(stream.read())#发送图片数据
        stream.seek(0)
        stream.truncate()#删除指针后的数据?
        connect.write(struct.pack('<L',0))#发送结尾数据,用于表示本次图片传输结束
    except:
        print(' ')
        print('Error:传输失败,客户端失去连接')
        raise

    finally:
        connection.close()
        print('连接断开')


def recv_img(client):#用于客户端接收opencv格式图片
    connection=client.makefile('rb')
    try:
        stream_bytes=b' '
        while True:
            msg=connection.read(1024)
            stream_bytes += msg
            first = stream_bytes.find(b'\xff\xd8')	# 检测帧头位置
            last = stream_bytes.find(b'\xff\xd9')	#检查jpg文件结尾标识
            if first != -1 and last != -1:
                jpg = stream_bytes[first:last + 2]					# 帧头和帧尾中间的数据就是二进制图片数据(编码后的二进制图片数据,需要解码后使用)
                stream_bytes = stream_bytes[last + 2:]				# 更新stream_bytes数据
                image = cv.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv.IMREAD_COLOR)			# 将二进制图片数据转换成numpy.uint8格式(也就是图片格式)数据,然后解码获得图片数据
                cv.imshow('image', image)							# 打开一个窗口显示图片 
                cv.waitKey(0)
                break
    except:
        print('Error:接收失败,与服务器失去连接')
        raise
    finally:
        cv.destroyAllWindows()
        connection.close()
        print('连接断开')




接下来对代码进行测试,采用opencv读取摄像头的一帧图片,并将这帧图片传送至客户端
服务器端代码:
test_server.py

import cv2 as cv
import time
from transfer_init import server_init
from transfer_img import send_img
class Server():#先有图像,再进行传输
    def __init__(self):
        self.server=server_init()
        cam=cv.VideoCapture(0)
        a=time.time()
        b=time.time()
        while b-a<1:
            ret,frame=cam.read()
            if not ret:
                print('摄像头状态异常')
                break
            b=time.time()
        if ret:
            send_img(self.server,frame)


if __name__=='__main__':
    Server()

客户端代码:
test_client.py

from transfer_init import client_init
from transfer_img import recv_img

class Client():
    def __init__(self):
        self.client=client_init('127.0.0.1',8000)
        recv_img(self.client)

if __name__=='__main__':
    Client()

执行时先启动服务器端,再启动客户端
服务器端启动
客户端启动
传输结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_56662453/article/details/129747450