整这个的目的是,最近有个小项目希望能采用局域网实现树莓派和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()
执行时先启动服务器端,再启动客户端
传输结果