提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本文的内容是利用openCV与Socket结合进行远程摄像头实时视频传输并保存图片数据,其原理是由Client客户端采集摄像头图像后经Socket传输到Server服务器端再显示出来。同时服务器端可通过键盘按动截图并保存。
本文内容参考自:
https://blog.csdn.net/qq_43665891/article/details/104362386
https://blog.csdn.net/u012736685/article/details/77131633
一、TCP协议通信步骤
首先了解一下TCP协议的一般通信步骤。
客户端:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
服务器端:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
8、关闭监听;
二、代码实现
1.客户端
代码如下(示例):
import socket
import struct
import time
import traceback
import cv2
import numpy
class Client(object):
"""客户端"""
def __init__(self, addr_port=('192.168.29.1', 11000)):
# 连接的服务器的地址
# 连接的服务器的端口
self.addr_port = addr_port
# 创建套接字
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 地址端口可以复用
self.client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 分辨率
self.resolution = (640, 480)
def connect(self):
"""链接服务器"""
try:
self.client.connect(self.addr_port)
return True
except Exception as e:
traceback.print_exc() # 打印原始的异常信息
print('连接失败')
return False
def send2server(self):
"""读摄像头数据 发送给服务器"""
camera = cv2.VideoCapture(0) # 摄像头对象
print('isOpened:', camera.isOpened())
while camera.isOpened():
try:
# 获取摄像头数据
ret, frame = camera.read()
# 对每一帧图片做大小处理 和大小的压缩
frame = cv2.resize(frame, self.resolution)
# 参1图片后缀名 参2 原图片的数据 参3图片质量 0-100 越大越清晰
ret, img = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
# img 是被压缩后的数据 无法正常显示
print(img)
print('-------------')
print(img.tostring())
# 转换为numpy格式数据
img_code = numpy.array(img)
# 转为二进制数据
img = img_code.tostring()
# 获取数据长度
length = len(img)
# 发送的数据 大小 宽 高 图片数据
# 数据打包变为二进制
# pack方法参数1 指定打包数据的数据大小 i 4字节 h代表2字节
all_data = struct.pack('ihh', length, self.resolution[0], self.resolution[1]) + img
self.client.send(all_data)
time.sleep(0.01)
except:
camera.release() # 释放摄像头
traceback.print_exc()
return
if __name__ == '__main__':
client = Client()
if client.connect():
client.send2server()
客户端说明:
1 init方法完成套接字的初始化,传入地址和端口,设置视频的分辨率
2 connect方法 利用客户端的socket对象的connect方法 连接服务器
3 send方法 读取摄像头拍摄的数据, ( socekt对象只发送二进制的数据 ) 把数据处理成二进制 , struct包的pack方法把里面的参数打包好自动转成二进制 , 再利用send发送出去
2.服务端
代码如下(示例):
import socket
import struct
import threading
import cv2
import numpy
import os
class Server:
def __init__(self):
# 设置tcp服务端的socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置重复使用
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定地址和端口
self.server.bind(('192.168.29.1', 11000))
# 设置被动监听
self.server.listen(128)
def run(self):
while True:
print('等待客户端连接')
# 等待客户端连接
client, addr = self.server.accept()
ProcessClient(client).start()
class ProcessClient(threading.Thread):
def __init__(self, client):
super().__init__()
self.client = client
# 以下内容作用是根据文件夹的图片序号规定'i'的初值,方便下一次保存图片时使用
self.i=0
path = "F:/sample"
for root, dirs, files in os.walk(path, topdown=False):
print(root)
print(dirs)
print(files)
file_list = []
for file in files:
file = int(file.split('.')[0])
file_list.append(file)
if len(file_list) == 0:
self.i = 0
else:
file_list.sort()
self.i = file_list[-1] + 1
def run(self):
while True:
data = self.client.recv(8)
if not data:
break
# 图片的长度 图片的宽高
length, width, height = struct.unpack('ihh', data)
imgg = b'' # 存放最终的图片数据
while length:
# 接收图片
temp_size = self.client.recv(length)
length -= len(temp_size) # 每次减去收到的数据大小
imgg += temp_size # 每次收到的数据存到img里
# 把二进制数据还原
data = numpy.fromstring(imgg, dtype='uint8')
# 还原成矩阵数据
image = cv2.imdecode(data, cv2.IMREAD_UNCHANGED)
print(image)
cv2.imshow('capture', image)
# 保存图片
k = cv2.waitKey(1)
if k == ord('k'):
cv2.imwrite(r"F:\sample\\" + str(self.i) + ".jpg", image) #存储路径
self.i = self.i + 1
print(self.i)
# time.sleep(5)
if k == ord('q'):
break
if __name__ == '__main__':
server = Server()
server.run()
服务端说明:将服务端接受到的视频数据逆操作,即可得到原来的视频,然后用cv2.imshow显示视频。
三、IP设置方法
- 服务端cmd输入ipconfig查看ip地址
2.找到当前使用网络的ipv4地址,将服务端与客户端都设置成该地址,例如:本机现在使用的WIFI
那就将ip地址设置成如上ipv4地址(远程传输服务端需要申请公网ip)。
四、效果演示
切记先打开服务端,再打开客户端。
按’k’截图保存在本地,按‘q’关闭cv。