Подтвердить что ты не робот

FileStorage для OpenCV Python API

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

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

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

4b9b3361

Ответ 1

Вы можете использовать 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.

Ответ 2

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

Немногие причины несовместимости:

  • Ямл, созданный OpenCV, не имеет пробела после ":". В то время как Python этого требует. [Ex: Это должно быть a: 2, а не a:2 для Python]
  • Первая строка файла 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 есть своя доля проблем, что я не изучил полностью.

Ответ 3

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

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

Ответ 4

Я написал небольшой фрагмент для чтения и записи совместимых с FileStorage YAML в Python:

# A yaml constructor is for loading from a yaml node.
# This is taken from @misha  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++ 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)

Ответ 5

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

# A yaml constructor is for loading from a yaml node.
# This is taken from @misha  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++ 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.