FileStorage for OpenCV Python API

后端 未结 6 1034
面向向阳花
面向向阳花 2020-12-08 15:54

I\'m currently using FileStorage class for storing matrices XML/YAML using OpenCV C++ API.

However, I have to writ

相关标签:
6条回答
  • 2020-12-08 16:09

    I wrote a small snippet to read and write FileStorage-compatible YAMLs 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)
    
    0 讨论(0)
  • 2020-12-08 16:13

    Using the FileStorage functions available in OpenCV 3.2, I've used this with success:

    import cv2
    fs = cv2.FileStorage("calibration.xml", cv2.FILE_STORAGE_READ)
    fn = fs.getNode("Camera_Matrix")
    print (fn.mat())
    
    0 讨论(0)
  • 2020-12-08 16:15

    To improve on the previous answer by @Roy_Shilkrot I added support for numpy vectors as well as matrices:

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

    Example:

    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)
    

    Output:

    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
    

    Though I could not control the order of rows, cols, dt, data.

    0 讨论(0)
  • 2020-12-08 16:26

    In addition to @misha's response, OpenCV YAML's are somewhat incompatible with Python.

    Few reasons for incompatibility are:

    1. Yaml created by OpenCV doesn't have a space after ":". Whereas Python requires it. [Ex: It should be a: 2, and not a:2 for Python]
    2. First line of YAML file created by OpenCV is wrong. Either convert "%YAML:1.0" to "%YAML 1.0". Or skip the first line while reading.

    The following function takes care of providing that:

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

    NOTE: Above response is applicable only for yaml's. XML's have their own share of problems, something I haven't explored completely.

    0 讨论(0)
  • 2020-12-08 16:26

    pip install opencv-contrib-python for video support to install specific version use pip install opencv-contrib-python

    0 讨论(0)
  • 2020-12-08 16:29

    You can use PyYAML to parse the YAML file.

    Since PyYAML doesn't understand OpenCV data types, you need to specify a constructor for each OpenCV data type that you are trying to load. For example:

    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)
    

    Once you've done that, loading the yaml file is simple:

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

    Result will be a dict, where the keys are the names of whatever you saved in the YAML.

    0 讨论(0)
提交回复
热议问题