2012-04-06 14 views
16

Desidero cercare le immagini in tutte le immagini in una determinata directory e salvare i loro punti chiave e descrittori per uso futuro. Ho deciso di usare salamoia come illustrato di seguito:Decapaggio cv2.KeyPoint causa 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() 

Quando provo ad eseguire, ottengo un errore seguente:

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 

Qualcuno sa, che cosa significa e come risolvere il problema? Sto usando Python 2.6 e 2.3.1 Opencv

Grazie molto

risposta

14

Il problema è che non si può scaricare cv2.KeyPoint in un file salamoia. Ho avuto lo stesso problema e sono riuscito a risolvere il problema essenzialmente serializzando e deserializzando i keypoints prima di scaricarli con Pickle.

Così rappresentare ogni punto chiave e il suo descrittore con una tupla:

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

Append tutti questi punti a qualche lista che poi il dump con Pickle.

Poi, quando si desidera recuperare nuovamente i dati, caricare tutti i dati 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] 

Creare un cv2.KeyPoint da questi dati utilizzando il codice di cui sopra, e si può quindi utilizzare questi punti per costruire un elenco di funzionalità.

Ho il sospetto che ci sia un modo più ordinato per farlo, ma quanto sopra funziona bene (e veloce) per me. Potrebbe essere necessario giocare un po 'con il formato dei dati, poiché le mie funzionalità sono memorizzate in elenchi specifici per formato. Ho provato a presentare quanto sopra usando la mia idea nella sua base generica. Spero che questo possa aiutarti.

0

Parte del problema è cv2.KeyPoint è una funzione in python che restituisce un oggetto cv2.KeyPoint. Pickle si sta confondendo perché, letteralmente, "<type 'cv2.KeyPoint'> [è] not the same object as cv2.KeyPoint". Cioè, cv2.KeyPoint è un oggetto funzione, mentre il tipo era cv2.KeyPoint. Perché OpenCV è così, posso solo fare ipotesi a meno che non vada a scavare. Ho la sensazione che abbia qualcosa a che fare con il fatto di essere un wrapper attorno a una libreria C/C++.

Python ti dà la possibilità di risolvere da solo questo problema. I found the inspiration on this post about pickling methods of classes.

Io in realtà uso questo clip di codice, altamente modificato dall'originale nel post

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) 

Punti chiave di nota:

  • In Python 2, è necessario utilizzare copy_reg invece di copyreg .
  • Non è possibile accedere direttamente alla classe cv2.KeyPoint per qualche motivo, quindi creare un oggetto temporaneo e utilizzarlo.
  • Il patch copyreg utilizza la funzione altrimenti problematica di cv2.KeyPoint come ho specificato nell'output di _pickle_keypoints quando si deseleziona, quindi non è necessario implementare una routine di annullamento.
  • E per essere nauseantemente completo, cv2::KeyPoint::KeyPoint è una funzione sovraccaricata in C++, ma in Python, questo non è esattamente una cosa. Mentre nel C++ c'è una funzione che prende il punto per il primo argomento, in Python, cercherebbe invece di interpretarlo come uno int. Lo * srotola il punto in due argomenti, x e in modo che corrisponda all'unico costruttore di argomenti int.

Ho utilizzato casper's excellent solution fino a quando ho realizzato che era possibile.

Problemi correlati