2012-06-21 25 views
18

Attualmente sto usando FileStorage classe per la memorizzazione di matrici XML/YAML utilizzando OpenCV C++ API.FileStorage per OpenCV Python API

Tuttavia, devo scrivere uno script Python che legge i file XML/YAML.

Sto cercando OpenCV Python API in grado di leggere i/YAML file XML generati da OpenCV C++ API

+2

nella sua ultima versione (dopo 3.1.0) binding Python per FileStorage/FileNode sono stati aggiunti: https://github.com/Itseez/opencv/pull/6482 –

risposta

22

È possibile utilizzare PyYAML per analizzare il file YAML esistente.

Poiché PyYAML non comprende i tipi di dati OpenCV, è necessario specificare un costruttore per ogni tipo di dati OpenCV che si sta tentando di caricare. Per esempio:

import yaml 
def opencv_matrix(loader, node): 
    mapping = loader.construct_mapping(node, deep=True) 
    mat = np.array(mapping["data"]) 
    mat.resize(mapping["rows"], mapping["cols"]) 
    return mat 
yaml.add_constructor(u"tag:yaml.org,2002:opencv-matrix", opencv_matrix) 

Una volta fatto questo, il caricamento del file YAML è semplice:

with open(file_name) as fin: 
    result = yaml.load(fin.read()) 

risultato sarà un dict, dove le chiavi sono i nomi di qualsiasi salvati nella YAML .

+0

+1: è fantastico. –

+0

@misha sai perché dà questo avviso? 'Il confronto con 'Nessuno' comporterà un confronto di oggetti elementwise in futuro. se i dati sono in [Nessuno,()]: ' – Yamaneko

+0

Aggiungi il consiglio di @ vishal sulla rimozione della prima riga e questa risposta sarebbe perfetta. Altrimenti, python non sarà in grado di leggere il file. – orodbhen

8

In aggiunta alla risposta di @ misha, gli YAML di OpenCV sono in qualche modo incompatibili con Python.

Poche cause di incompatibilità sono:

  1. Yaml creato da OpenCV non hai spazio dopo ":". Mentre Python lo richiede. [Es: Deve essere a: 2 e non per Python]
  2. La prima riga del file YAML creata da OpenCV è errata. Convertire "% YAML: 1.0" in "% YAML 1.0". O salta la prima riga durante la lettura.

La seguente funzione si occupa della fornitura di detto:

import yaml 
import re 
def readYAMLFile(fileName): 
    ret = {} 
    skip_lines=1 # Skip the first line which says "%YAML:1.0". Or replace it with "%YAML 1.0" 
    with open(scoreFileName) as fin: 
     for i in range(skip_lines): 
      fin.readline() 
     yamlFileOut = fin.read() 
     myRe = re.compile(r":([^ ])") # Add space after ":", if it doesn't exist. Python yaml requirement 
     yamlFileOut = myRe.sub(r': \1', yamlFileOut) 
     ret = yaml.load(yamlFileOut) 
    return ret 

outDict = readYAMLFile("file.yaml") 

NOTA: Sopra risposta è applicabile solo per YAML di. Gli XML hanno la loro parte di problemi, qualcosa che non ho esplorato completamente.

+0

Suggerimento utile. Ho provato a cambiare la linea in "YAML 1.0", e non funziona. Quindi devi togliere la prima riga. – orodbhen

4

ho scritto un piccolo frammento di leggere e scrivere YAMLs compatibili FileStorage in Python:

# A yaml constructor is for loading from a yaml node. 
# This is taken from @misha 's answer: http://stackoverflow.com/a/15942429 
def opencv_matrix_constructor(loader, node): 
    mapping = loader.construct_mapping(node, deep=True) 
    mat = np.array(mapping["data"]) 
    mat.resize(mapping["rows"], mapping["cols"]) 
    return mat 
yaml.add_constructor(u"tag:yaml.org,2002:opencv-matrix", opencv_matrix_constructor) 

# A yaml representer is for dumping structs into a yaml node. 
# So for an opencv_matrix type (to be compatible with c++'s FileStorage) we save the rows, cols, type and flattened-data 
def opencv_matrix_representer(dumper, mat): 
    mapping = {'rows': mat.shape[0], 'cols': mat.shape[1], 'dt': 'd', 'data': mat.reshape(-1).tolist()} 
    return dumper.represent_mapping(u"tag:yaml.org,2002:opencv-matrix", mapping) 
yaml.add_representer(np.ndarray, opencv_matrix_representer) 

#examples 

with open('output.yaml', 'w') as f: 
    yaml.dump({"a matrix": np.zeros((10,10)), "another_one": np.zeros((2,4))}, f) 

with open('output.yaml', 'r') as f: 
    print yaml.load(f) 
1

di migliorare la risposta precedente @Roy_Shilkrot ho aggiunto il supporto per i vettori NumPy così come matrici:

# A yaml constructor is for loading from a yaml node. 
# This is taken from @misha 's answer: http://stackoverflow.com/a/15942429 
def opencv_matrix_constructor(loader, node): 
    mapping = loader.construct_mapping(node, deep=True) 
    mat = np.array(mapping["data"]) 
    if mapping["cols"] > 1: 
     mat.resize(mapping["rows"], mapping["cols"]) 
    else: 
     mat.resize(mapping["rows"],) 
    return mat 
yaml.add_constructor(u"tag:yaml.org,2002:opencv-matrix", opencv_matrix_constructor) 


# A yaml representer is for dumping structs into a yaml node. 
# So for an opencv_matrix type (to be compatible with c++'s FileStorage) we save the rows, cols, type and flattened-data 
def opencv_matrix_representer(dumper, mat): 
    if mat.ndim > 1: 
     mapping = {'rows': mat.shape[0], 'cols': mat.shape[1], 'dt': 'd', 'data': mat.reshape(-1).tolist()} 
    else: 
     mapping = {'rows': mat.shape[0], 'cols': 1, 'dt': 'd', 'data': mat.tolist()} 
    return dumper.represent_mapping(u"tag:yaml.org,2002:opencv-matrix", mapping) 
yaml.add_representer(np.ndarray, opencv_matrix_representer) 

Esempio:

with open('output.yaml', 'w') as f: 
    yaml.dump({"a matrix": np.zeros((10,10)), "another_one": np.zeros((5,))}, f) 

with open('output.yaml', 'r') as f: 
    print yaml.load(f) 

uscita:

0.123.
a matrix: !!opencv-matrix 
    cols: 10 
    data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
    0.0, 0.0, 0.0, 0.0, 0.0] 
    dt: d 
    rows: 10 
another_one: !!opencv-matrix 
    cols: 1 
    data: [0.0, 0.0, 0.0, 0.0, 0.0] 
    dt: d 
    rows: 5 

Anche se non riuscivo a controllare l'ordine di righe, colonne, dt, dati.

3

Usando le funzioni FileStorage disponibili in OpenCV 3.2, ho usato questo con successo:

import cv2 
fs = cv2.FileStorage("calibration.xml", cv2.FILE_STORAGE_READ) 
fn = fs.getNode("Camera_Matrix") 
print (fn.mat()) 
+0

Sai come ottenere l'elenco di tutti i nodi disponibili? – mkuse