我想在给定目录中的所有图像中搜索冲浪并保存其关键点和描述符以供将来使用.我决定使用如下所示的泡菜:
#!/usr/bin/env python
import os
import pickle
import cv2
class Frame:
def __init__(self, filename):
surf = cv2.SURF(500, 4, 2, True)
self.filename = filename
self.keypoints, self.descriptors = surf.detect(cv2.imread(filename, cv2.CV_LOAD_IMAGE_GRAYSCALE), None, False)
if __name__ == '__main__':
Fdb = open('db.dat', 'wb')
base_path = "img/"
frame_base = []
for filename in os.listdir(base_path):
frame_base.append(Frame(base_path+filename))
print filename
pickle.dump(frame_base,Fdb,-1)
Fdb.close()
Run Code Online (Sandbox Code Playgroud)
当我尝试执行时,出现以下错误:
File "src/pickle_test.py", line 23, in <module>
pickle.dump(frame_base,Fdb,-1)
...
pickle.PicklingError: Can't pickle <type 'cv2.KeyPoint'>: it's not the same object as cv2.KeyPoint
Run Code Online (Sandbox Code Playgroud)
有谁知道,它意味着什么以及如何解决它?我使用的是Python 2.6和Opencv 2.3.1
非常感谢
hjw*_*ide 19
问题是你不能将cv2.KeyPoint转储到pickle文件.我遇到了同样的问题,并且在使用Pickle转储它们之前,通过自己对关键点进行基本序列化和反序列化来设法解决它.
因此,使用元组表示每个关键点及其描述符:
temp = (point.pt, point.size, point.angle, point.response, point.octave,
point.class_id, desc)
Run Code Online (Sandbox Code Playgroud)
将所有这些点附加到您随后使用Pickle转储的列表中.
然后,当您想要再次检索数据时,使用Pickle加载所有数据:
temp_feature = 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])
temp_descriptor = point[6]
Run Code Online (Sandbox Code Playgroud)
使用上面的代码从这些数据创建一个cv2.KeyPoint,然后您可以使用这些点来构建一个功能列表.
我怀疑有一个更简洁的方法来做到这一点,但上面的工作对我来说很好(和快).您可能需要稍微调整一下数据格式,因为我的功能存储在特定于格式的列表中.我尝试在其通用基础上使用我的想法来呈现上述内容.我希望这可以帮到你.
Poi*_*oik 10
问题的一部分是cv2.KeyPointpython中的一个返回cv2.KeyPoint对象的函数。Pickle感到困惑,因为从字面上看,“ <type 'cv2.KeyPoint'>[是] not the same object as cv2.KeyPoint”。也就是说,cv2.KeyPoint是一个函数对象,而类型是cv2.KeyPoint。为什么使用OpenCV这样的话,除非去挖掘,否则我只能猜测。我觉得它与C / C ++库的包装有关。
Python确实使您能够自己解决此问题。我从这篇文章中发现了有关类的酸洗方法的灵感。
我实际上使用的是这段代码剪辑,该代码剪辑与帖子中的原始内容进行了高度修改
import copyreg
import cv2
def _pickle_keypoints(point):
return cv2.KeyPoint, (*point.pt, point.size, point.angle,
point.response, point.octave, point.class_id)
copyreg.pickle(cv2.KeyPoint().__class__, _pickle_keypoints)
Run Code Online (Sandbox Code Playgroud)
注意事项:
copy_reg代替copyreg和point.pt[0], point.pt[1]代替*point.pt。cv2.KeyPoint由于某种原因,您不能直接访问该类,因此您可以创建一个临时对象并使用它。copyreg补丁将使用,否则问题cv2.KeyPoint的功能,因为我在输出已指定_pickle_keypoints取储存的时候,所以我们并不需要实现在unpickle程序。cv2::KeyPoint::KeyPoint是,它是C ++中的重载函数,但是在Python中,这并不是一回事。而在C ++中,有一个函数将第一个参数作为要点,而在Python中,它将尝试将其解释为一个int代替。将*点展开为两个参数,x并y与唯一的int参数构造函数匹配。在我意识到这是可能的之前,我一直在使用casper的出色解决方案。