2012-04-06 2 views
16

Я хочу искать серфики во всех изображениях в данном каталоге и сохранять их ключевые точки и дескрипторы для дальнейшего использования. Я решил использовать рассол, как показано ниже:Pickling cv2.KeyPoint вызывает PicklingError

#!/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

Спасибо большое

ответ

14

Проблема заключается в том, что вы не можете сбросить cv2.KeyPoint в файл рассола. У меня была такая же проблема, и мне удалось обойти это, по сути, сериализовать и десериализовать ключевые точки, прежде чем сбросить их с помощью Pickle.

Так представляют каждую характерную точку и его дескриптор с кортежем:

temp = (point.pt, point.size, point.angle, point.response, point.octave, 
     point.class_id, desc)  

Append все эти точки в какой-то список, который затем сбросить с соленья.

Затем, когда вы хотите, чтобы снова получить данные, все данные будут загружены с соленья:

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] 

Создать cv2.KeyPoint из этих данных, используя приведенный выше код, а затем вы можете использовать эти пункты, чтобы построить список функций.

Я подозреваю, что есть более аккуратный способ сделать это, но выше все работает отлично (и быстро) для меня. Возможно, вам придется немного поиграть со своим форматом данных, так как мои функции хранятся в списках формата. Я попытался представить выше, используя мою идею на своей общей основе. Я надеюсь, что это может вам помочь.

0

Часть проблемы cv2.KeyPoint является функцией в python, которая возвращает объект cv2.KeyPoint. Рассол запутан, потому что буквально «<type 'cv2.KeyPoint'> [is] not the same object as cv2.KeyPoint». То есть cv2.KeyPoint является функциональным объектом, тогда как тип был cv2.KeyPoint. Почему OpenCV такой, я могу только догадываться, если я не буду копать. У меня есть ощущение, что это связано с тем, что это обертка вокруг библиотеки C/C++.

Python действительно дает вам возможность исправить это самостоятельно. I found the inspiration on this post about pickling methods of classes.

Я использую этот клип кода, сильно модифицированные от оригинала в пост

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) 

Ключевые моменты ноты:

  • В Python 2, вам нужно использовать copy_reg вместо copyreg ,
  • По какой-то причине вы не можете напрямую получить доступ к классу cv2.KeyPoint, поэтому вы создаете временный объект и используете его.
  • Патч copyreg будет использовать в противном случае проблемную функцию cv2.KeyPoint, как я указал в выводе _pickle_keypoints при распаковке, поэтому нам не нужно реализовывать процедуру рассыпания.
  • И чтобы быть тошнотворно завершенным, cv2::KeyPoint::KeyPoint является перегруженной функцией в C++, но в Python это не совсем так. Если в C++ есть функция, которая принимает точку для первого аргумента, в Python, она попытается интерпретировать это как int. * разворачивает точку на два аргумента, x и y, чтобы соответствовать только конструктору аргументов int.

Я использовал casper's excellent solution, пока не понял, что это возможно.

Смежные вопросы