下面我将为您详细讲解“python使用socket高效传输视频数据帧(连续发送图片)”的完整实例教程,包括示例说明:
1. 简介
在本教程中,我们将使用Python中的socket库实现高效的视频数据帧传输,特别是连续发送图片。实现这种数据流的目标是传输即时视频,并尽可能地减小延迟。
2. 实现
2.1 导入库
我们首先要导入需要的Python库:
import cv2
import numpy as np
import socket
import struct
2.2 创建socket连接
我们将使用TCP/IP协议进行连接,并绑定本地IP地址和端口号。下面是实现代码:
#socket连接的配置项
HOST = '0.0.0.0'
PORT = 9999
#创建socket连接,绑定IP地址和端口号,并监听连接
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
#待完成后续步骤
pass
2.3 捕获并编码摄像头帧
接下来,我们要使用摄像头捕获视频帧,并把每一帧压缩成JPEG图像。这里我们需要使用OpenCV库,完成代码如下:
#使用OpenCV库捕获摄像头帧
cap = cv2.VideoCapture(0)
while True:
# 从摄像头捕获图片
ret, frame = cap.read()
# 如果帧捕获失败就退出
if not ret:
break
# 将JPG数据编码
imgData = cv2.imencode('.jpg', frame)[1].tostring()
# 用struct模块打包数据
#B表示1个字节,L表示4个字节,以"<BL"表示先发1个字节,再发4个字节
#imgLen指数据总长度
imgLen = struct.pack('<BL', 1, len(imgData))
# 待完成后续步骤
pass
2.4 发送图像数据
接下来,我们要将JPEG图像数据发送到服务器上,完成代码如下:
#发送数据长度
conn.sendall(imgLen)
#发送图像数据本身
conn.sendall(imgData)
# 待完成后续步骤
pass
2.5 接收图像数据
最后,我们需要在客户端上接收并显示图像数据。这里我们需要不断循环读取接收到的图像帧,并将其解码为JPEG图像。客户端的代码如下:
#socket连接的配置项
HOST = '192.168.0.1' # 服务器的IP地址
PORT = 9999
# 创建socket连接
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# 不断接收图像
while True:
#读取数据长度
len_str = s.recv(5)
#如果图像帧长度字符串不为空,则解析图像长度
if len(len_str) != 0:
#解包含有1个字节和4个字节的struct数据类型
frameLen = struct.unpack('<BL', len_str)[1]
# 读取图片数据,并解码为图像
data = s.recv(frameLen)
#将JPEG数据解码为图像
imgArray = np.asarray(bytearray(data), dtype=np.uint8)
img = cv2.imdecode(imgArray, cv2.IMREAD_COLOR)
#显示接收的图像
cv2.imshow('frame', img)
#等待用户输入退出键
if cv2.waitKey(1) & 0xFF == ord('q'):
break
这里我们使用了OpenCV的cv2.imshow()函数显示视频帧,并通过等待用户输入"q"来退出接收数据的循环。
3. 示例说明
下面给出两个示例,以说明上述代码的应用场景。
3.1 实例1:在同一台机器上,用python捕获摄像头图像,并在本地上显示图像
在这个示例中,我们要实现在同一台机器上,用python捕获摄像头图像,并在本地上显示图像。在Python 3.6环境中,打开摄像头,捕获图像,并将图像转换为JPEG格式。使用下面的代码:
import cv2, socket, numpy
#捕获摄像头视频流
camera = cv2.VideoCapture(0)
#启动socket连接
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 10086))
sock.listen(1)
conn, addr = sock.accept()
while True:
#捕获一帧图像,并将图像转换为JPG数据格式
ret, frame = camera.read()
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
_, img_data = cv2.imencode('.jpg', frame, encode_param)
#将图像以socket数据流发送到客户端
conn.send(str(img_data.size).ljust(16).encode())
conn.send(img_data.tostring())
# 在本地显示图像
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
camera.release()
cv2.destroyAllWindows()
conn.close()
运行上面的程序,在服务器上输入指令python filename.py
,即可从本地摄像头捕获图像,并在本地上显示图像。
3.2 实例2:在客户端上接收服务器上的摄像头实时图像展示
这个示例中的场景是看一个远程的地方,需要利用夜视摄像头的实时图像。我们在客户端上使用Python连接服务器,接收实时视频数据,并在本地实时展示摄像头实时图像。使用下面的代码:
import socket
from threading import Thread
import numpy as np
import cv2
#视频流接口地址
video_stream_url = 'localhost'
video_stream_port = 10086
#创建socket连接
def create_jpeg_receiver():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((video_stream_url, video_stream_port))
return client_socket
#解码JPEG数据并显示实时视频流
def jpeg_decoder_thread():
client_socket = create_jpeg_receiver()
#循环解析JPEG数据流,并将其解压缩为图像
while True:
#从socket连接缓冲区获取数据长度
length = recvall(client_socket, 16)
#解析图像长度,并从socket连接缓冲区读取实时图像数据
full_image = recvall(client_socket, int(length))
#将JPEG数据解压缩为图像
img = cv2.imdecode(np.frombuffer(full_image, dtype=np.uint8), -1)
#显示实时图像
cv2.imshow('LiveStream', img)
#按'q'键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
#从socket连接缓冲区读取指定长度的数据
def recvall(client_socket, n):
data = b""
while len(data) < n:
packet = client_socket.recv(n - len(data))
if not packet:
return None
data += packet
return data
#主函数启动JPEG解码器线程,并接收视频帧流
if __name__ == '__main__':
Thread(target=jpeg_decoder_thread, args=()).start()
运行上面的程序,在客户端上输入指令python filename.py
,即可从服务器端接收以JPEG格式压缩的视频数据流,并在客户端本地实时展示摄像头实时图像。
4. 结论
这个示例演示了如何使用Python轻松地实现即时数据传输。即使是在传输大量数据时,我们也可以轻松地实现高效数据传输并尽可能减少延迟,从而实现平滑视频流。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python使用socket高效传输视频数据帧(连续发送图片) - Python技术站