如何在OpenCV 3与Python 3中正确加载cv2.KeyPoint和描述符?
解决Python3中加载Python2保存的OpenCV关键点与描述符的Pickle问题
我刚处理过几乎一模一样的Python2→Python3迁移问题,这本质是两个版本在pickle序列化规则、字节/字符串处理逻辑上的差异,再结合numpy数组的存储特性导致的。下面是针对性的修复方案:
一、修复关键点加载的TypeError
你遇到的TypeError: a bytes-like object is required,是因为Python3中pickle.loads()要求传入字节对象,但你用文本模式读取文件得到的是字符串。直接改用二进制模式读取文件就能解决:
import numpy as np import pickle import cv2 # 用二进制模式打开文件('rb'),避免字符串/字节的转换问题 with open(keypoints_path, 'rb') as f: keypoints_list = pickle.load(f) # 直接用pickle.load更简洁,替代loads+read的组合 kp = [] for point in keypoints_list: temp = cv2.KeyPoint( x=point[0][0], y=point[0][1], _size=point[1], _angle=point[2], _response=point[3], _octave=point[4], _class_id=point[5] ) kp.append(temp)
二、修复描述符加载的UnicodeDecodeError
描述符的UnicodeDecodeError是因为Python2中pickle保存numpy数组时,会将数组的原始字节以字符串形式存储;而Python3的pickle默认用ASCII解码这些内容,遇到非ASCII字节就会报错。解决方法是在pickle.load()时指定encoding='latin1'——latin1是单字节编码,能完美映射所有字节值,刚好匹配numpy数组的原始存储格式:
import numpy as np import pickle # 加载描述符时指定encoding='latin1'处理numpy兼容问题 with open(descriptors_path, 'rb') as f: descriptors_list = pickle.load(f, encoding='latin1') # 无需循环复制,直接转为numpy数组即可 descriptors = np.asarray(descriptors_list)
关键原因总结
- 字节/字符串差异:Python2的
str等价于Python3的bytes,而Python3的str是Unicode字符串。用'rb'模式打开文件,能直接读取到pickle需要的字节对象,避免类型不匹配。 - numpy序列化兼容:Python2中numpy数组通过pickle保存时,内部用latin1编码存储原始字节;Python3中必须显式指定这个编码,才能正确解析数组内容,否则会触发ASCII解码错误。
内容的提问来源于stack exchange,提问作者Suaro
相关产品推荐
相关产品推荐

