Python2与Python3间ROS图像ndarray传输Pickle反序列化报错求助
解决Python2(ROS)与Python3跨版本传输OpenCV ndarray的序列化问题
这个报错_pickle.UnpicklingError: the STRING opcode argument must be quoted本质是Python2和Python3的字符串类型(str/bytes)差异,加上你用了protocol=0(ASCII兼容的旧协议),导致ndarray的二进制数据在序列化/反序列化时出现解析冲突。下面给你几个可靠的解决方案:
方案一:用Numpy原生序列化(推荐,最稳定)
既然传输的是OpenCV的ndarray,直接用Numpy自带的序列化工具是最靠谱的,它的格式跨Python版本兼容,完全避开pickle的版本陷阱。
Python2端(ROS机器):
import numpy as np from io import BytesIO import struct # 1. 将ROS图像转为ndarray(你的原有代码) img = CvBridge().imgmsg_to_cv2(img_data, desired_encoding='bgr8') # 2. 序列化ndarray到字节流 buffer = BytesIO() np.save(buffer, img) buffer.seek(0) img_bytes = buffer.getvalue() # 3. 先发送数据长度(避免socket粘包) length = struct.pack('!I', len(img_bytes)) sock.sendall(length) # 4. 发送图像数据 sock.sendall(img_bytes)
Python3端:
import numpy as np from io import BytesIO import struct # 1. 先接收数据长度 length_data = sock.recv(4) length = struct.unpack('!I', length_data)[0] # 2. 完整接收图像字节数据 img_bytes = b'' while len(img_bytes) < length: chunk = sock.recv(min(length - len(img_bytes), 4096)) if not chunk: raise ConnectionError("连接中断") img_bytes += chunk # 3. 反序列化得到ndarray buffer = BytesIO(img_bytes) img = np.load(buffer)
方案二:调整Pickle协议与反序列化参数
如果你坚持用pickle,可以调整协议版本和编码参数,减少跨版本冲突:
Python2端:
把序列化协议从0换成2(Python2支持的最高协议,Python3完全兼容):
import pickle import struct img = CvBridge().imgmsg_to_cv2(img_data, desired_encoding='bgr8') # 用protocol=2序列化 data = pickle.dumps(img, protocol=2) # 同样先发送长度,再发数据 length = struct.pack('!I', len(data)) sock.sendall(length) sock.sendall(data)
Python3端:
反序列化时指定encoding='bytes'来处理Python2的字符串:
import pickle import struct # 先接收长度和数据(步骤同方案一) length_data = sock.recv(4) length = struct.unpack('!I', length_data)[0] data_in = b'' while len(data_in) < length: chunk = sock.recv(min(length - len(data_in), 4096)) if not chunk: raise ConnectionError("连接中断") data_in += chunk # 反序列化 response = pickle.loads(data_in, encoding='bytes')
关键注意事项
- 避免粘包:图像数据体积大,socket传输时会自动拆分数据包,必须先发送数据长度,再按长度接收完整数据,否则不完整的字节流会导致任何反序列化方法失败。
- 编码一致性:确保ROS转OpenCV时的编码是
bgr8,Python3端后续处理时也要对应这个编码(比如显示时用cv2.imshow不需要转,因为OpenCV默认是BGR)。
内容的提问来源于stack exchange,提问作者Nexos
相关产品推荐
相关产品推荐

