2012-06-21 1 views
18

настоящее время я использую FileStorage класс для хранения двух матриц XML/YAML с использованием OpenCV C++ API.FileStorage для OpenCV Python API

Однако мне нужно написать скрипт Python, который читает эти файлы XML/YAML.

Я ищу существующих OpenCV Python API, который может читать/YAML файлы XML, генерируемые OpenCV C++ API

+2

в последней версии (после 3.1.0) питона креплений для FileStorage/FileNode были добавлено: HTTPS://github.com/Itseez/opencv/pull/6482 –

ответ

22

Вы можете использовать PyYAML для разбора файла YAML.

Поскольку PyYAML не понимает типы данных OpenCV, вам нужно указать конструктор для каждого типа данных OpenCV, который вы пытаетесь загрузить. Например:

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) 

После того, как вы сделали это, загрузив файл YAML прост:

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

Результат будет Dict, где ключи имена все, что вы сохранили в YAML ,

+0

+1 - это здорово. –

+0

@misha Знаете ли вы, почему это дает это предупреждение? «сравнение с« Нет »приведет к сравнению элементарных объектов в будущем. если данные в [Нет,()]: ' – Yamaneko

+0

Добавьте совет @ vishal о том, чтобы удалить первую строку, и этот ответ был бы идеальным. В противном случае python не сможет прочитать файл. – orodbhen

8

В дополнение к ответу @ misha, OpenCV YAML несколько несовместимы с Python.

Несколько причин несовместимости являются:

  1. YAML создатель OpenCV не имеет пробел после ":". В то время как Python этого требует. [Ех: это должно быть a: 2, а не a:2 для Python]
  2. Неверная первая строка файла YAML, созданного OpenCV. Либо переведите «% YAML: 1.0» в «% YAML 1.0». Или пропустите первую строку во время чтения.

Следующая функция заботится при условии, что:

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") 

Примечание: Выше ответ применим только для YAML-х годов. У XML есть своя доля проблем, чего я не изучил полностью.

+0

Полезный совет. Я попытался изменить строку на «YAML 1.0», но это не сработает. Поэтому вам нужно снять первую строку. – orodbhen

4

Я написал небольшой фрагмент кода для чтения и записи FileStorage-совместимые YAMLs в 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

Чтобы улучшить предыдущий ответ по @Roy_Shilkrot я добавил поддержку Numpy векторов, а также матриц:

# 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) 

Пример:

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) 

Выход:

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 

Хотя я не мог контролировать порядок строк, cols, dt, data.

3

Используя функцию FileStorage доступной в OpenCV 3.2, я использовал это с успехом:

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

Вы знаете, как получить список всех доступных узлов? – mkuse

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

  • Нет связанных вопросов^_^