tags:

views:

177

answers:

1

I've got a series of OpenCv generated YAML files and would like to parse them with yaml-cpp

I'm doing okay on simple stuff, but the matrix representation is proving difficult.

# Center of table
tableCenter: !!opencv-matrix
   rows: 1
   cols: 2
   dt: f
   data: [ 240,    240]

This should map into the vector

240
240

with type float. My code looks like:

#include "yaml.h"
#include <fstream>
#include <string>

struct Matrix {
    int x;
};

void operator >> (const YAML::Node& node, Matrix& matrix) {
   unsigned rows;
   node["rows"] >> rows;
}

int main()
{
   std::ifstream fin("monsters.yaml");
   YAML::Parser parser(fin);
   YAML::Node doc;

    Matrix m;
    doc["tableCenter"] >> m;

   return 0;
}

But I get

terminate called after throwing an instance of 'YAML::BadDereference'
  what():  yaml-cpp: error at line 0, column 0: bad dereference
Abort trap

I searched around for some documentation for yaml-cpp, but there doesn't seem to be any, aside from a short introductory example on parsing and emitting. Unfortunately, neither of these two help in this particular circumstance.

As I understand, the !! indicate that this is a user-defined type, but I don't see with yaml-cpp how to parse that.

+1  A: 

You have to tell yaml-cpp how to parse this type. Since C++ isn't dynamically typed, it can't detect what data type you want and create it from scratch - you have to tell it directly. Tagging a node is really only for yourself, not for the parser (it'll just faithfully store it for you).

I'm not really sure how an OpenCV matrix is stored, but if it's something like this:

class Matrix {
public:
   Matrix(unsigned r, unsigned c, const std::vector<float>& d): rows(r), cols(c), data(d) { /* init */ }
   Matrix(const Matrix&) { /* copy */ }
   ~Matrix() { /* delete */ }
   Matrix& operator = (const Matrix&) { /* assign */ }

private:
   unsigned rows, cols;
   std::vector<float> data;
};

then you can write something like

void operator >> (const YAML::Node& node, Matrix& matrix) {
   unsigned rows, cols;
   std::vector<float> data;
   node["rows"] >> rows;
   node["cols"] >> cols;
   node["data"] >> data;
   matrix = Matrix(rows, cols, data);
}

Edit It appears that you're ok up until here; but you're missing the step where the parser loads the information into the YAML::Node. Instead, se it like:

std::ifstream fin("monsters.yaml");
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc); // <-- this line was missing!

Matrix m;
doc["tableCenter"] >> m;

Note: I'm guessing dt: f means "data type is float". If that's the case, it'll really depend on how the Matrix class handles this. If you have a different class for each data type (or a templated class), you'll have to read that field first, and then choose which type to instantiate. (If you know it'll always be float, that'll make your life easier, of course.)

Jesse Beder