C++图片传输中可能存在的问题及解决办法

最近在折腾C++与Python之间图像传输的问题,踩了一些坑,记录之以飨后来者。

需求&原有做法

总的需求是要实现这样一个功能:发送端连接摄像头,发送端实时将摄像头画面采用RTSP协议传输到接收端,接收端进行处理后再发回。最开始发送端和接收端都通过Python实现。Python语言虽然简单易上手,但其缺陷也很明显,效率低下。因此需要将其改为C++。因为Python发送端涉及内容较多,难以一次改为C++,所以考虑采用Python发送图像,C++ 接收图像的方式。

改进出现的问题及解决

目前Python端先对图像进行水平切割,然后调用cv2.imencode对图片进行编码,然后调用tobytes函数转化为字节流进行传输,C++端接收字节流后进行逆处理。

  • 第一个坑是C++接收后如何将字节流进行转化的问题。Python中to_bytesfrom_bytes函数,C++没有。通过阅读Python源码发现,这两个函数使用的是bytes类型,这是Python3中特有的类型。bytes类型其实就是通过十六进制表示和存储的二进制数据流,因此c++接收到的数据流为十六进制字符流,所以只需要将其按顺序放入一段连续的内存空间中,即可使用指针等方式进行访问读取,不需要进行转换

  • 第二个坑是发送时的顺序问题。计算机硬件中存储数据的方式有两种:大段字节序(big endian)和小端字节序(little endian)。大端字节序为高位字节在前,低位字节在后,小端字节序为高位字节在后,低位字节在前。例如0x1122用大端序表示即为1122,如果改用小端序则为2211。大端序为人类习惯的顺序,然而小端序为计算机习惯的顺序。因为计算机如果采用大端序,则会有先读取到高位字节再读取到低位字节的问题,正好与期望顺序相反,因此其更习惯于小端序。不同的环境对于大小端序的使用不同,本文所用为小端序。

  • 第三个坑是关于逆处理的顺序。即C++接收后先拼接再解码还是先解码再拼接的问题。因为发送的时候是先对图像进行水平切割,然后进行编码,即相当于图像被分成若干新的图像然后进行编码,每份图像编码后的数据包含该份图像的尺寸,RGB等数据,因此需要先进行调用imdecode进行解码,将每份图像还原为切割前的图像,再调用vconcat将图像拼接为完整的图像(若图像为垂直切割则调用hconcat)。

总结

综上,Python(发)与C++(收)之间发送图片的流程为:

  1. Python创建套接字

  2. Python进行图像切割(利用列表分片)

  3. Python对分片进行imencode编码

  4. Python将编码后的数据使用to_bytes转换为字节数据流

  5. Python发送数据,指定小端序

  6. C++创建套接字

  7. C++接收字节流数据并存储

  8. 对接收的数据进行imdecode解码还原切割后的图像

  9. 将图像进行vconcat拼接还原图像

Python(收),C++(发)同理,将上述过程做对应修改即可。


2022年第一篇,希望自己今年能有空多写。既要注意知识输入,也要通过注意知识输出,闭环调整输入,希望借此达到保持技术能力与表达能力不退化的目的。勉之勉之!