通过前两篇博客,我们已经成功通过scrcpy获得了手机屏幕的yuv数据([Ubuntu]Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放——(一)(图文+代码解析)_又是谁在卷的博客-CSDN博客)
之后我们又实现了通过消息中间件Zeromq对提取到的yuv数据进行传输([Ubuntu]Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放——(二)(思路+代码解析)_又是谁在卷的博客-CSDN博客)
那么我们终于来到最后一个环节啦,创建python脚本,用于接收Zeromq传输的yuv数据,并对其进行解包最后通过opencv实现连续播放。
目录
1.在python中创建Zeromq的订阅端
2. 对接收的消息进行解包
2.1处理宽高数据
2.2处理yuv数据,并转换格式用于opencv的播放
3.使用opencv进行播放
1.在python中创建Zeromq的订阅端
这里我们需要注意的是,如果想要实现连续播放,请将本文剩下的所有代码放入while循环中才能实现。
# 创建订阅端接收对象
context = zmq.Context()
print("Connecting to server…")
# 选择订阅发布者模式
socket = context.socket(zmq.SUB)
# 设置端口属性,zmq.SUBSCRIBE为设置消息过滤项,我们这里选择接收所有消息
socket.setsockopt_string(zmq.SUBSCRIBE,'')
# 选择端口号
socket.connect("tcp://127.0.0.1:5565")
# 接收消息
message = socket.recv()
#关闭端口,这里解释为什么要在此处关闭端口。
因为我们想要实现连续播放,
#每次while循环我们建议都对端口进行重新连接,这样获取的数据较为流畅。
socket.close()
2. 对接收的消息进行解包
在这里我们会使用到python的Struct模块。
我们知道,我们先前创建的结构体在Zeromq中是通过字节流(binary data二进制流)的格式传输的。
如果我们传输的是字符串,我们就不用担心那么多问题。
但是在结构体中,我们有int,char之类的数据类型。
我们在解包时也要将其从字节流还原为原来的数据类型才能正常使用。
我们先来看看结构体被传输之前的结构,如下图所示:
在这里我选择将传输过来的结构体分为两个部分处理。
第一部分是宽和高(cxt_width, cxt_height),第二部分就是剩下的yuv数据了
2.1处理宽高数据# 创建Struct实例,这里的参数‘2i’表示我们要将数据解压为int类型,长度为2个字节
#其他类型的数据对应的字符如下图所示
c_struct = Struct('2i')
# 进行解压,解压对象为我们message[0:8]也就是宽和高对象
unpacked = c_struct.unpack(message[0:8])
cxt_width = unpacked[0]
cxt_height = unpacked[1]
2.2处理yuv数据,并转换格式用于opencv的播放
这里我们将会使用到numpy和opencv的相关方法,具体如下:
numpy.frombuffer():将字节流数据类型转换为ndarray对象
cv_formate:这里是指opencv识别对应数据类型的格式。
因为我们是yuv420数据类型,所以我们这里的cv_formate = I420
numpy.reshape:这里我们可以回想一下,当初提取yuv数据时,我们知道yuv提取是有顺序,并且u和v数据的大小分别是y的1/4。
所以我们要通过reshape还原它的形状。
cv2.cvtColor:颜色空间转换函数。
对传入的图片进行染色
# 获取yuv字节流类型的数据
data_yuv = message[8:]
# 解析yuv数据:np.frombuffer的作用是将字节流数据转化为ndarray对象
nparr = np.frombuffer(data_yuv,dtype=np.uint8)
# yuv数据类型:I420
cv_formate = cv_format = cv2.COLOR_YUV2BGR_I420
# 重组像素点:我们假设y的高是1,那么u,v的高就是1/4。
那么三者加起来的总和就是3/2。
所以这里的高为cxt_height*3//2
bgr_img = nparr.reshape((cxt_height*3//2,cxt_width))
# 色彩渲染:
bgr_img = cv2.cvtColor(bgr_img,cv_formate)
3.使用opencv进行播放
这里可能有小伙伴会尝试cv2.imwrite或者cv2.imread进行保存图片再读取的 *** 作,这样播放的效果是很卡顿的,我们这里是直接从内存中读取数据,这样显示的效果延迟低,不卡顿。
cv2.imshow('result.jpg',bgr_img)
cv2.waitKey(1)
至此,我们就完全实现Scrcpy+Zeromq实现手机屏幕yuv数据传输,并通过OpenCV实现连续播放的全过程啦。
如果有帮助,期待你的一键三连哈
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)