Search code examples
c++xmlopencv

Using OpenCV FileStorage to read a XML file


I am trying to use FileStorage to read a XML file with this code:

#include <opencv2/opencv.hpp>

int main(int argc, const char * argv[]) {    
  cv::FileStorage fs("/Users/thewoz/Desktop/01.xml", cv::FileStorage::READ);  
  return 0;  
}

The gives me the following error:

persistence.cpp:706: error: (-5:Bad argument) Input file is invalid in function 'open'

This is the xml file:

<?xml version="1.0"?>
<images>
"20170720_024951.jpg"
"20170720_025001.jpg"
"20170720_025014.jpg"
"20170720_025023.jpg"
"20170720_025034.jpg"
"20170720_025048.jpg"
"20170720_025103.jpg"
"20170720_025115.jpg"
"20170720_025124.jpg"
"20170720_025133.jpg"
"20170720_025147.jpg"
"20170720_025155.jpg"
"20170720_025211.jpg"
</images>

I don't understand what the problem is.


Solution

  • OpenCV does not read arbitrary XML. With some changes to your file, it could read the file. If you can't change your file, you'll need to use a generic XML library.

    cv::FileStorage is made specifically to store and read OpenCV types (e.g. cv::Mat). It assumes a specific structure to the file. This is specific to cv::FileStorage. One such requirement is that all the data is contained in a <opencv_storage> tag.


    If you can change your file's format to fit cv::FileStorage, then sure, you can use it to read the file.

    cv:FileStorage to write a list of strings:

    # images = ['20170720_024951.jpg', '20170720_025001.jpg', '20170720_025014.jpg', '20170720_025023.jpg', '20170720_025034.jpg', '20170720_025048.jpg', '20170720_025103.jpg', '20170720_025115.jpg', '20170720_025124.jpg', '20170720_025133.jpg', '20170720_025147.jpg', '20170720_025155.jpg', '20170720_025211.jpg']
    
    fs = cv.FileStorage(
        "opencv-filestorage.xml",
        cv.FileStorage_WRITE | cv.FileStorage_FORMAT_XML)
    fs.write("images", images)
    fs.release()
    

    Pardon the Python, C++ would be mostly equivalent.

    The XML file:

    <?xml version="1.0"?>
    <opencv_storage>
    <images>
      "20170720_024951.jpg" "20170720_025001.jpg" "20170720_025014.jpg"
      "20170720_025023.jpg" "20170720_025034.jpg" "20170720_025048.jpg"
      "20170720_025103.jpg" "20170720_025115.jpg" "20170720_025124.jpg"
      "20170720_025133.jpg" "20170720_025147.jpg" "20170720_025155.jpg"
      "20170720_025211.jpg"</images>
    </opencv_storage>
    

    That format you can read with cv::FileStorage.

    fs = cv.FileStorage(
        "opencv-filestorage.xml",
        cv.FileStorage_READ | cv.FileStorage_FORMAT_XML)
    node = fs.getNode("images")
    assert node.isSeq()
    print(node.size(), "images")
    assert all(
        node.at(i).isString() for i in range(node.size()))
    images = [
        node.at(i).string()
        for i in range(node.size())
    ]