Permalink
Browse files

Added FileStorage

  • Loading branch information...
kyamagu committed Feb 5, 2012
1 parent f0264e5 commit 07792def2bafcf125384e729bd1e59732bde7512
Showing with 276 additions and 2 deletions.
  1. +28 −0 +cv/FileStorage.m
  2. +8 −2 include/MxArray.hpp
  3. +1 −0 lib/.gitignore
  4. +183 −0 src/+cv/FileStorage.cpp
  5. +27 −0 src/MxArray.cpp
  6. +29 −0 test/unit_tests/TestFileStorage.m
View
@@ -0,0 +1,28 @@
+%FILESTORAGE Reading from or writing to a XML/YAML file storage
+%
+% S = cv.FileStorage(fileName)
+% cv.FileStorage(fileName, S)
+%
+% Input:
+% fileName: Name of the XML/YAML file. The file name should have either .xml
+% or .yml extension.
+% S: Scalar struct to be written to a file
+% Output:
+% S: Scalar struct read from a file
+%
+% The function reads or writes a Matlab object from/to a XML/YAML file. The file
+% is compatible to OpenCV formats. A quick example is shown below:
+%
+% Writing to a file
+%
+% S = struct('field1', randn(2,3), 'field2', 'this is the second field');
+% cv.FileStorage('my.yml',S);
+%
+% Reading from a file
+%
+% S = cv.FileStorage('my.yml');
+%
+% Replace '.yml' to '.xml' for using xml format.
+%
+% See also load save
+%
View
@@ -107,10 +107,16 @@ class MxArray {
inline mwSize ndims() const { return mxGetNumberOfDimensions(p_); }
/// Array of each dimension
inline const mwSize* dims() const { return mxGetDimensions(p_); };
- /// Number of rows in array
+ /// Number of rows in an array
inline mwSize rows() const { return mxGetM(p_); }
- /// Number of columns in array
+ /// Number of columns in an array
inline mwSize cols() const { return mxGetN(p_); }
+ /// Number of fields in a struct array
+ inline int nfields() const { return mxGetNumberOfFields(p_); }
+ std::string fieldname(int index=0) const;
+ std::vector<std::string> fieldnames() const;
+ /// Number of elements in IR, PR, and PI arrays
+ inline mwSize nzmax() const { return mxGetNzmax(p_); }
mwIndex subs(mwIndex i, mwIndex j=0) const;
mwIndex subs(const std::vector<mwIndex>& si) const;
/// Determine whether input is cell array
View
@@ -0,0 +1 @@
+*.a
View
@@ -0,0 +1,183 @@
+/**
+ * @file FileStorage.cpp
+ * @brief mex interface for FileStorage
+ * @author Kota Yamaguchi
+ * @date 2012
+ */
+#include "mexopencv.hpp"
+using namespace std;
+using namespace cv;
+
+namespace {
+/** Check if the node is of a user-defined type
+ * @param _node node.
+ * @param _type_name type name. e.g., "opencv-matrix"
+ * @return flag
+ */
+bool isa(const FileNode& _node, const string& _type_name)
+{
+ const CvFileNode* node = reinterpret_cast<const CvFileNode*>(*_node);
+ if (node->info && node->info->type_name)
+ return string(node->info->type_name)==_type_name;
+ return false;
+}
+
+/** Recursive function to output to a file storage
+ * @param fs FileStorage object
+ * @param x MxArray to be read
+ * @param node FileNode to read
+ */
+void read(FileStorage& fs, MxArray& x, const FileNode& node)
+{
+ if (node.type()==FileNode::SEQ) {
+ int n = node.size();
+ vector<MxArray> v(n, MxArray(static_cast<mxArray*>(NULL)));
+ for (int i=0; i<n; ++i) {
+ const FileNode& elem = node[i];
+ int type = elem.type();
+ if (type==FileNode::INT)
+ v[i] = MxArray(static_cast<int>(elem));
+ else if (type==FileNode::REAL)
+ v[i] = MxArray(static_cast<double>(elem));
+ else if (type==FileNode::STR)
+ v[i] = MxArray(static_cast<string>(elem));
+ else if (type==FileNode::SEQ) {
+ MxArray y(static_cast<mxArray*>(NULL));
+ read(fs, y, elem);
+ v[i] = y;
+ }
+ else if (type==FileNode::MAP) {
+ if (isa(elem,"opencv-matrix")) {
+ Mat m;
+ elem >> m;
+ v[i] = MxArray(m);
+ }
+ else if (isa(elem,"opencv-nd-matrix")) {
+ MatND m;
+ elem >> m;
+ v[i] = MxArray(m);
+ }
+ else {
+ MxArray y(static_cast<const char**>(NULL),0);
+ read(fs, y, elem);
+ v[i] = y;
+ }
+ }
+ }
+ x = MxArray(v);
+ }
+ else if (node.type()==FileNode::MAP) {
+ for (FileNodeIterator it=node.begin(); it!=node.end(); ++it) {
+ const FileNode& elem = (*it);
+ int type = elem.type();
+ if (type==FileNode::INT)
+ x.set(elem.name(), static_cast<int>(elem));
+ else if (type==FileNode::REAL)
+ x.set(elem.name(), static_cast<double>(elem));
+ else if (type==FileNode::STR)
+ x.set(elem.name(), static_cast<string>(elem));
+ else if (type==FileNode::SEQ) {
+ MxArray y(static_cast<mxArray*>(NULL));
+ read(fs, y, elem);
+ x.set(elem.name(), y);
+ }
+ else if (type==FileNode::MAP) {
+ if (isa(elem,"opencv-matrix")) {
+ Mat m;
+ elem >> m;
+ x.set(elem.name(), m);
+ }
+ else if (isa(elem,"opencv-nd-matrix")) {
+ MatND m;
+ elem >> m;
+ x.set(elem.name(), m);
+ }
+ else {
+ MxArray y(static_cast<const char**>(NULL),0);
+ read(fs, y, elem);
+ x.set(elem.name(), y);
+ }
+ }
+ }
+ }
+}
+
+/** Recursive function to output to a file storage
+ * @param fs FileStorage object
+ * @param x MxArray to be written
+ * @param root Flag inidicating the root node
+ */
+void write(FileStorage& fs, const MxArray& x, bool root=false)
+{
+ mxClassID classid = x.classID();
+ if (classid == mxFUNCTION_CLASS || classid==mxUNKNOWN_CLASS)
+ mexErrMsgIdAndTxt("mexopencv:error","Invalid MxArray");
+ if (classid == mxSTRUCT_CLASS) {
+ int n = x.numel();
+ vector<string> fields(x.fieldnames());
+ if (n>1) fs << "[";
+ for (int i=0; i<n; ++i) {
+ if (!root) fs << "{";
+ for (vector<string>::iterator it=fields.begin(); it<fields.end(); ++it) {
+ fs << *it;
+ write(fs, MxArray(x.at(*it,i)));
+ }
+ if (!root) fs << "}";
+ }
+ if (n>1) fs << "]";
+ }
+ else if (classid == mxCELL_CLASS) {
+ vector<MxArray> array(x.toVector<MxArray>());
+ fs << "[";
+ for (vector<MxArray>::iterator it=array.begin(); it<array.end(); ++it)
+ write(fs,*it);
+ fs << "]";
+ }
+ else if (classid == mxCHAR_CLASS) {
+ string s(x.toString());
+ fs << s;
+ }
+ else {
+ if (x.numel()==1) {
+ if (x.isDouble() || x.isSingle())
+ fs << x.toDouble();
+ else
+ fs << x.toInt();
+ }
+ else {
+ Mat y(x.toMat());
+ fs << y;
+ }
+ }
+}
+}
+
+/**
+ * Main entry called from Matlab
+ * @param nlhs number of left-hand-side arguments
+ * @param plhs pointers to mxArrays in the left-hand-side
+ * @param nrhs number of right-hand-side arguments
+ * @param prhs pointers to mxArrays in the right-hand-side
+ */
+void mexFunction( int nlhs, mxArray *plhs[],
+ int nrhs, const mxArray *prhs[] )
+{
+ // Check arguments
+ if (!(nrhs==2&&nlhs==0)&&!(nrhs==1&&nlhs<=1))
+ mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
+ string filename(MxArray(prhs[0]).toString());
+ if (nrhs==1) {
+ FileStorage fs(filename, FileStorage::READ);
+ MxArray x(static_cast<const char**>(NULL),0);
+ FileNode node = fs.root();
+ read(fs, x, node);
+ plhs[0] = x;
+ }
+ else {
+ MxArray x(prhs[1]);
+ if (!x.isStruct() || x.numel()!=1)
+ mexErrMsgIdAndTxt("mexopencv:error","Input is not a scalar struct array");
+ FileStorage fs(filename, FileStorage::WRITE);
+ write(fs, x, true);
+ }
+}
View
@@ -702,6 +702,33 @@ cv::TermCriteria MxArray::toTermCriteria(mwIndex index) const
);
}
+/** Get field name of a struct array
+ * @param index index of the struct array
+ * @return std::string
+ */
+std::string MxArray::fieldname(int index) const
+{
+ const char *f = mxGetFieldNameByNumber(p_, index);
+ if (!f)
+ mexErrMsgIdAndTxt("mexopencv:error","Failed to get field name at %d\n",index);
+ return std::string(f);
+}
+
+/** Get field names of a struct array
+ * @return std::string
+ */
+std::vector<std::string> MxArray::fieldnames() const
+{
+ if (!isStruct())
+ mexErrMsgIdAndTxt("mexopencv:error","MxArray is not a struct array");
+ int n = nfields();
+ std::vector<std::string> v;
+ v.reserve(n);
+ for (int i=0; i<n; ++i)
+ v.push_back(fieldname(i));
+ return v;
+}
+
/** Offset from first element to desired element
* @param i index of the first dimension of the array
* @param j index of the second dimension of the array
@@ -0,0 +1,29 @@
+classdef TestFileStorage
+ %TestFileStorage
+ properties (Constant)
+ end
+
+ methods (Static)
+ function test_1
+ S = struct('field1', magic(4), 'field2', 'this is the second field');
+ cv.FileStorage('.my.yml',S);
+ S2 = cv.FileStorage('.my.yml');
+ assert(all(S.field1(:)==S2.field1(:)));
+ assert(strcmp(S.field2,S2.field2));
+ if exist('.my.yml','file')
+ delete my.yml;
+ end
+ end
+
+ function test_error_1
+ try
+ cv.FileStorage();
+ throw('UnitTest:Fail');
+ catch e
+ assert(strcmp(e.identifier,'mexopencv:error'));
+ end
+ end
+ end
+
+end
+

0 comments on commit 07792de

Please sign in to comment.