OpenCV Python API 的 FileStorage
Posted
技术标签:
【中文标题】OpenCV Python API 的 FileStorage【英文标题】:FileStorage for OpenCV Python API 【发布时间】:2012-06-23 21:00:21 【问题描述】:我目前正在使用 FileStorage 类来使用 OpenCV C++ API 存储矩阵 XML/YAML。
但是,我必须编写一个 Python 脚本来读取那些 XML/YAML 文件。
我正在寻找可以读取 OpenCV C++ API
生成的 XML/YAML 文件的现有 OpenCV Python API【问题讨论】:
在最新版本(3.1.0 之后)中为 FileStorage/FileNode 添加了 python 绑定:github.com/Itseez/opencv/pull/6482 【参考方案1】:pip install opencv-contrib-python 视频支持安装特定版本使用 pip install opencv-contrib-python
【讨论】:
【参考方案2】:使用 OpenCV 3.2 中可用的 FileStorage 函数,我成功地使用了它:
import cv2
fs = cv2.FileStorage("calibration.xml", cv2.FILE_STORAGE_READ)
fn = fs.getNode("Camera_Matrix")
print (fn.mat())
【讨论】:
你知道如何获取所有可用节点的列表吗?【参考方案3】:为了改进@Roy_Shilkrot 之前的回答,我添加了对 numpy 向量和矩阵的支持:
# A yaml constructor is for loading from a yaml node.
# This is taken from @misha 's answer: http://***.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
虽然我无法控制行、列、dt、数据的顺序。
【讨论】:
【参考方案4】:我写了一个小 sn-p 来用 Python 读写 FileStorage 兼容的 YAML:
# A yaml constructor is for loading from a yaml node.
# This is taken from @misha 's answer: http://***.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)
【讨论】:
这不再起作用了:File "/usr/lib/python2.7/dist-packages/yaml/representer.py", line 142, in ignore_aliases if data in [None, ()]: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
【参考方案5】:
除了@misha 的回复,OpenCV YAML 有点与 Python 不兼容。
不兼容的几个原因是:
-
OpenCV 创建的 Yaml 在“:”之后没有空格。而 Python 需要它。 [例如:它应该是
a: 2
,而不是 Python 的 a:2
]
OpenCV 创建的 YAML 文件的第一行错误。将“%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 有自己的问题,我还没有完全探索过。
【讨论】:
有用的提示。我尝试将行更改为“YAML 1.0”,但它不起作用。所以你必须去掉第一行。 @orodbhen:你把%
放在YAML
之前了吗?
是的。对不起,这只是我评论中的一个错字。使用%YAML 1.0
我得到一个 ParseError。这是PyYAML 3.12
用于Python 3.6
。
请查看@TimSC 的正确答案 - 该问题专门要求 Python OpenCV API,它适用于 C++ 生成的 YAML。【参考方案6】:
您可以使用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())
结果将是一个字典,其中的键是您保存在 YAML 中的任何内容的名称。
【讨论】:
@misha 你知道它为什么会发出这个警告吗?comparison to 'None' will result in an elementwise object comparison in the future. if data in [None, ()]:
添加@vishal关于剥离第一行的建议,这个答案将是完美的。否则,python 将无法读取该文件。
另外,设置数据类型。幸运的是,numpy 数据类型代码与 OpenCV 相同,至少对于 float 和 double 等简单类型而言。
这对我不起作用。我用 c++ 编写 .yml 并按上述方式阅读它们。生成的 numpy 数组与原始(多维) cv::Mat 不同
请查看@TimSC 的正确答案 - 该问题专门要求 Python OpenCV API,此答案提供了一种复杂的 PyYAML 方法。以上是关于OpenCV Python API 的 FileStorage的主要内容,如果未能解决你的问题,请参考以下文章
Google Drive API 客户端(Python):files().insert() 的权限不足