我想在给定目录下的所有图像中搜索冲浪,并保存它们的关键点和描述符以备将来使用。我决定使用pickle,如下所示:
#!/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()
当我尝试执行时,我得到以下错误:
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
有谁知道,这是什么意思,如何修复它?我使用Python 2.6和OpenCV 2.3.1
多谢了
4条答案
按热度按时间xuo3flqw1#
问题是你不能将cv2.KeyPoint转储到pickle文件中。我也遇到了同样的问题,并设法解决了这个问题,在用Pickle转储之前,我自己基本上序列化和重新序列化了关键点。
所以用一个元组来表示每个关键点及其描述符:
将所有这些点添加到某个列表中,然后使用Pickle转储。
然后,当你想再次检索数据时,用Pickle加载所有数据:
使用上面的代码从这个数据创建一个cv2.KeyPoint,然后你可以使用这些点来构造一个特征列表。
我怀疑有一种更简洁的方法来做到这一点,但上面的工作对我来说很好(而且很快)。你可能需要稍微摆弄一下你的数据格式,因为我的功能存储在特定格式的列表中。我试图在其通用基础上使用我的想法来呈现上面的内容。我希望这可以帮助你。
qybjjes12#
问题的一部分是
cv2.KeyPoint
是python中的一个函数,它返回一个cv2.KeyPoint
对象。Pickle感到困惑,因为从字面上看,“<type 'cv2.KeyPoint'>
[是]not the same object as cv2.KeyPoint
“。也就是说,cv2.KeyPoint
是一个函数对象,而类型是cv2.KeyPoint
。为什么OpenCV是这样的,我只能猜测,除非我去挖掘。我有一种感觉,这与它是一个C/C++库的 Package 器有关。Python确实给了你给予自己修复这个问题的能力。
我实际上使用了这段代码,在帖子中对原始代码进行了高度修改
注意要点:
copy_reg
而不是copyreg
,使用point.pt[0], point.pt[1]
而不是*point.pt
。cv2.KeyPoint
类,因此您创建一个临时对象并使用它。copyreg
补丁程序将使用我在_pickle_keypoints
的输出中指定的有问题的cv2.KeyPoint
函数,所以我们不需要实现一个unpickle例程。cv2::KeyPoint::KeyPoint
在C中是一个重载函数,但在Python中,这并不完全是一个东西。而在C中,有一个函数将第一个参数作为点,在Python中,它会尝试将其解释为int
。*
将点展开为两个参数,x
和y
匹配唯一的int
参数构造函数。我一直在使用casper's excellent solution,直到我意识到这是可能的。
2jcobegt3#
一个类似于Poik提供的解决方案。在腌制之前调用一次。
除了代码之外,这是因为那里有非常清晰的解释:https://stackoverflow.com/a/50394788/11094914
请注意,如果你想将这个想法扩展到openCV的其他“不可拾取”类,你只需要构建一个类似于“_pickle_keypoint”的函数。确保你存储属性的顺序与构造函数相同。你可以考虑复制C构造函数,即使是在Python中,就像我做的那样。大多数情况下,C和Python构造函数似乎没有太大区别。
我对“pt”元组有问题。但是,C++构造函数存在X和Y分隔坐标,因此,允许此修复/解决方案。
kqqjbcuj4#
在我的实现中,我将Keypoints存储在我的一个类中,这会阻止整个类正确地pickle。扩展@hjweide answer,像这样解构和重构关键点对我来说很有效:
这让我可以很好地腌制,同时保持我的界面不变。