最近在折腾C++与Python之间图像传输的问题,踩了一些坑,记录之以飨后来者。
需求&原有做法
总的需求是要实现这样一个功能:发送端连接摄像头,发送端实时将摄像头画面采用RTSP协议传输到接收端,接收端进行处理后再发回。最开始发送端和接收端都通过Python实现。Python语言虽然简单易上手,但其缺陷也很明显,效率低下。因此需要将其改为C++。因为Python发送端涉及内容较多,难以一次改为C++,所以考虑采用Python发送图像,C++ 接收图像的方式。
改进出现的问题及解决
目前Python端先对图像进行水平切割,然后调用cv2.imencode
对图片进行编码,然后调用tobytes
函数转化为字节流进行传输,C++端接收字节流后进行逆处理。
-
第一个坑是C++接收后如何将字节流进行转化的问题。Python中
to_bytes
和from_bytes
函数,C++没有。通过阅读Python源码发现,这两个函数使用的是bytes
类型,这是Python3中特有的类型。bytes
类型其实就是通过十六进制表示和存储的二进制数据流,因此c++接收到的数据流为十六进制字符流,所以只需要将其按顺序放入一段连续的内存空间中,即可使用指针等方式进行访问读取,不需要进行转换。 -
第二个坑是发送时的顺序问题。计算机硬件中存储数据的方式有两种:大段字节序(big endian)和小端字节序(little endian)。大端字节序为高位字节在前,低位字节在后,小端字节序为高位字节在后,低位字节在前。例如
0x1122
用大端序表示即为1122
,如果改用小端序则为2211
。大端序为人类习惯的顺序,然而小端序为计算机习惯的顺序。因为计算机如果采用大端序,则会有先读取到高位字节再读取到低位字节的问题,正好与期望顺序相反,因此其更习惯于小端序。不同的环境对于大小端序的使用不同,本文所用为小端序。 -
第三个坑是关于逆处理的顺序。即C++接收后先拼接再解码还是先解码再拼接的问题。因为发送的时候是先对图像进行水平切割,然后进行编码,即相当于图像被分成若干新的图像然后进行编码,每份图像编码后的数据包含该份图像的尺寸,RGB等数据,因此需要先进行调用
imdecode
进行解码,将每份图像还原为切割前的图像,再调用vconcat
将图像拼接为完整的图像(若图像为垂直切割则调用hconcat
)。
总结
综上,Python(发)与C++(收)之间发送图片的流程为:
-
Python创建套接字
-
Python进行图像切割(利用列表分片)
-
Python对分片进行
imencode
编码 -
Python将编码后的数据使用
to_bytes
转换为字节数据流 -
Python发送数据,指定小端序
-
C++创建套接字
-
C++接收字节流数据并存储
-
对接收的数据进行
imdecode
解码还原切割后的图像 -
将图像进行
vconcat
拼接还原图像
Python(收),C++(发)同理,将上述过程做对应修改即可。
2022年第一篇,希望自己今年能有空多写。既要注意知识输入,也要通过注意知识输出,闭环调整输入,希望借此达到保持技术能力与表达能力不退化的目的。勉之勉之!