Pickling cv2.KeyPoint hace que PicklingError

Quiero buscar surfea en todas las imágenes en un directorio dado y guardar sus puntos clave y descriptores para uso futuro. Decidí usar pickle como se muestra a continuación:

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

Cuando bash ejecutarlo, obtengo el siguiente error:

 File "src/pickle_test.py", line 23, in  pickle.dump(frame_base,Fdb,-1) ... pickle.PicklingError: Can't pickle : it's not the same object as cv2.KeyPoint 

¿Alguien sabe, qué significa y cómo solucionarlo? Estoy usando Python 2.6 y Opencv 2.3.1

Muchas gracias

El problema es que no puede volcar cv2.KeyPoint en un archivo pickle. Tuve el mismo problema, y ​​logré solucionarlo esencialmente mediante la serialización y deserialización de los puntos clave antes de deshacerme de ellos con Pickle.

Entonces represente cada punto clave y su descriptor con una tupla:

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

Agregue todos estos puntos a alguna lista que luego descargue con Pickle.

Luego, cuando desee recuperar los datos nuevamente, cargue todos los datos con 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] 

Cree un cv2.KeyPoint a partir de estos datos utilizando el código anterior, y luego puede usar estos puntos para construir una lista de características.

Sospecho que hay una forma más ordenada de hacer esto, pero lo anterior funciona bien (y rápido) para mí. Puede que tenga que jugar un poco con el formato de sus datos, ya que mis funciones se almacenan en listas de formatos específicos. Traté de presentar lo anterior usando mi idea en su base genérica. Espero que esto te pueda ayudar.

Parte del problema es cv2.KeyPoint es una función en python que devuelve un objeto cv2.KeyPoint . Pickle se confunde porque, literalmente, ” [ not the same object as cv2.KeyPoint “. Es decir, cv2.KeyPoint es un objeto de función, mientras que el tipo era cv2.KeyPoint . Por qué OpenCV es así, solo puedo hacer conjeturas a menos que vaya a cavar. Tengo la sensación de que tiene algo que ver con que sea una envoltura alrededor de una biblioteca C / C ++.

Python te da la habilidad de arreglar esto por ti mismo. He encontrado la inspiración en este post acerca de los métodos de decapado de las clases .

De hecho, uso este clip de código, altamente modificado del original en la publicación.

 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) 

Puntos clave de la nota:

  • En Python 2, debe usar copy_reg lugar de copyreg y point.pt[0], point.pt[1] lugar de *point.pt .
  • No puede acceder directamente a la clase cv2.KeyPoint por algún motivo, por lo que cv2.KeyPoint un objeto temporal y lo utiliza.
  • El parche copyreg utilizará la función cv2.KeyPoint otro modo sería problemática, como he especificado en la salida de _pickle_keypoints cuando se desempaquetan, por lo que no necesitamos implementar una rutina de despeje.
  • Y para ser nauseabundo, cv2::KeyPoint::KeyPoint es una función sobrecargada en C ++, pero en Python, esto no es exactamente una cosa. Mientras que en C ++, hay una función que toma el punto para el primer argumento, en Python, intentaría interpretarlo como un int lugar. El * desenrolla el punto en dos argumentos, x e y para coincidir con el único constructor de argumento int .

Había estado usando la excelente solución de Casper hasta que me di cuenta de que esto era posible.