OpenCV持久化(二)
如何利用OpenCV持久化自己的数据结构?我们来看看OpenCV中的一个例子。
MyData.hpp定义自己的数据结构MyData如下:
#ifndef MYDATA_HPP
#define MYDATA_HPP #include <opencv2/core/core.hpp>
#include <iostream>
#include <string> using namespace std;
using namespace cv; class MyData
{
public:
MyData() : A(), X(), id()
{}
explicit MyData(int) : A(), X(CV_PI), id("mydata1234") // explicit to avoid implicit conversion
{}
void write(FileStorage& fs) const //Write serialization for this class
{
fs << "{" << "A" << A << "X" << X << "id" << id << "}";
}
void read(const FileNode& node) //Read serialization for this class
{
A = (int)node["A"];
X = (double)node["X"];
id = (string)node["id"];
}
public: // Data Members
int A;
double X;
string id;
}; //These write and read functions must be defined for the serialization in FileStorage to work
static void write(FileStorage& fs, const std::string&, const MyData& x)
{
x.write(fs);
} static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData())
{
if(node.empty())
x = default_value;
else
x.read(node);
} // This function will print our custom class to the console
static ostream& operator<<(ostream& out, const MyData& m)
{
out << "{ id = " << m.id << ", ";
out << "X = " << m.X << ", ";
out << "A = " << m.A << "}";
return out;
} #endif // MYDATA_HPP
注意,外部静态函数 write 和 read 必须定义,即:
static void write(FileStorage& fs, const std::string&, const MyData& x);
static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()); 原因稍后说明。 主函数main.cpp如下:
#include <QtCore/QCoreApplication>
#include "MyData.hpp" int main(int argc, char *argv[])
{
// QCoreApplication a(argc, argv);
// return a.exec(); string filename = "../file/test.xml";
{ //write
Mat R = Mat_<uchar>::eye(, ),
T = Mat_<double>::zeros(, );
MyData m(); FileStorage fs(filename, FileStorage::WRITE); fs << "iterationNr" << ;
fs << "strings" << "["; // text - string sequence
fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
fs << "]"; // close sequence fs << "Mapping"; // text - mapping
fs << "{" << "One" << ;
fs << "Two" << << "}"; fs << "R" << R; // cv::Mat
fs << "T" << T; fs << "MyData" << m; // your own data structures fs.release(); // explicit close
cout << "Write Done." << endl;
} {//read
cout << endl << "Reading: " << endl;
FileStorage fs;
fs.open(filename, FileStorage::READ); int itNr;
//fs["iterationNr"] >> itNr;
itNr = (int) fs["iterationNr"];
cout << itNr;
if (!fs.isOpened())
{
cerr << "Failed to open " << filename << endl;
//help(av);
return ;
} FileNode n = fs["strings"]; // Read string sequence - Get node
if (n.type() != FileNode::SEQ)
{
cerr << "strings is not a sequence! FAIL" << endl;
return ;
} FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
for (; it != it_end; ++it)
cout << (string)*it << endl; n = fs["Mapping"]; // Read mappings from a sequence
cout << "Two " << (int)(n["Two"]) << "; ";
cout << "One " << (int)(n["One"]) << endl << endl; MyData m;
Mat R, T; fs["R"] >> R; // Read cv::Mat
fs["T"] >> T;
fs["MyData"] >> m; // Read your own structure_ cout << endl
<< "R = " << R << endl;
cout << "T = " << T << endl << endl;
cout << "MyData = " << endl << m << endl << endl; //Show default behavior for non existing nodes
cout << "Attempt to read NonExisting (should initialize the data structure with its default).";
fs["NonExisting"] >> m;
cout << endl << "NonExisting = " << endl << m << endl;
} cout << endl
<< "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl; return ;
}
可以看到第29行: fs << "MyData" << m;
当执行到 fs << "MyData" 时,将调用OpenCV源码operations.hpp中的输出操作符:
static inline FileStorage& operator << (FileStorage& fs, const char* str)
返回 FileStorage 的引用,继续输入自定义的数据m时,将调用operations.hpp中的模板函数:
template<typename _Tp> static inline FileStorage& operator << (FileStorage& fs, const _Tp& value)
{
if( !fs.isOpened() )
return fs;
if( fs.state == FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP )
CV_Error( CV_StsError, "No element name has been given" );
write( fs, fs.elname, value );
if( fs.state & FileStorage::INSIDE_MAP )
fs.state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
return fs;
}
可以看到第7行:write( fs, fs.elname, value );
在operations.hpp中,可以看到两个OpenCV导出函数:
CV_EXPORTS_W void write( FileStorage& fs, const string& name, const Mat& value );
CV_EXPORTS void write( FileStorage& fs, const string& name, const SparseMat& value );
CV_EXPORTS_W void read(const FileNode& node, Mat& mat, const Mat& default_mat=Mat() );
CV_EXPORTS void read(const FileNode& node, SparseMat& mat, const SparseMat& default_mat=SparseMat() );
回到上面的问题,为什么必须要定义外部静态函数write和read:
static void write(FileStorage& fs, const std::string&, const MyData& x);
static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData());
因此,我们在MyData.hpp中定义的外部静态函数write和read重载了OpenCV中operations.hpp的read和write函数。
所以,上述调用第7行:write( fs, fs.elname, value ) 将调用我们自己定义的 write和read 函数。然后如MyData.hpp所示,在MyData类内部定义方法实现自定义数据结构的持久化。
而对外接口用起来就像 fs << "MyData" << m; 这句这么简单。
最后输出结果如下:


OpenCV持久化(二)的更多相关文章
- 开发环境配置--Ubuntu+Qt4+OpenCV(二)
同系列文章 1. 开发环境配置--Ubuntu+Qt4+OpenCV(一) 2. 开发环境配置--Ubuntu+Qt4+OpenCV(二) 3. 开发环境配置--Ubuntu+Qt4+OpenCV(三 ...
- 使用OpenCV查找二值图中最大连通区域
http://blog.csdn.net/shaoxiaohu1/article/details/40272875 使用OpenCV查找二值图中最大连通区域 标签: OpenCVfindCoutour ...
- OpenCV教程二 - Mat对象与它各种用法
学习OpenCV大家都会遇到一个对象叫做Mat,此对象非常神奇,支持各种操作.很多初学者因此被搞得头晕脑胀,它各种用法太多太杂,搞得初学者应接不暇,感觉有心无力.无处下手之感.这里我们首先要正本清源, ...
- opencv 删除二值化图像中面积较小的连通域
对于上图的二值化图像,要去除左下角和右上角的噪点,方法:使用opencv去掉黑色面积较小的连通域. 代码 CvSeq* contour = NULL; double minarea = 100.0; ...
- OpenCV持久化(一)
在OpenCV中,采用FileStorage类进行数据持久化,可以采用XML或YAML格式存储数据. 将数据写入XML或YAML文件,可采用以下步骤: 1.创建FileStorage对象.可以调用构造 ...
- OpenCV使用二维特征点(Features2D)和单映射(Homography)寻找已知物体
使用二维特征点(Features2D)和单映射(Homography)寻找已知物体 目标 在本教程中我们将涉及以下内容: 使用函数 findHomography 寻找匹配上的关键点的变换. 使用函数 ...
- opencv图像二值化的函数cvThreshold()。 cvAdaptiveThreshol
OpenCV中对图像进行二值化的关键函数——cvThreshold(). 函数功能:采用Canny方法对图像进行边缘检测 函数原型: void cvThreshold( const CvArr* sr ...
- Opencv+Zbar二维码识别(标准条形码/二维码识别)
使用Opencv+Zbar组合可以很容易的识别图片中的二维码,特别是标准的二维码,这里标准指的是二维码成像清晰,图片中二维码的空间占比在40%~100%之间,这样标准的图片,Zbar识别起来很容易,不 ...
- OpenCV图像变换二 投影变换与极坐标变换实现圆形图像修正
投影变换 在放射变换中,物体是在二维空间中变换的.如果物体在三维空间中发生了旋转,那么这种变换就成为投影变换,在投影变换中就会出现阴影或者遮挡,我们可以运用二维投影对三维投影变换进行模块化,来处理阴影 ...
随机推荐
- Lvs+Keepalived实现MySQL高可用
LVS+Keepalived+MySQL高可用配置 本文所有配置前提是已实现MySQL双主备份(MySQL双主) 安装前的准备: VIP:192.168.0.201 Keepalived: Keepa ...
- 自定义UITableViewCell的方法
1.纯XIB/storyboard自定义.对应一个Controller的storyboard上拖拽出一个自定义Cell,并加上ReuseIdentifitor 2.纯代码自定义,通过在contentV ...
- 无法将网络更改为桥接状态 没有VMent0
本文主要分享 VMware 10.0.2 报错信息:无法将网络更改为桥接状态的解决经验 工具/原料 VMware 10.0.2 方法/步骤 1 故障现象,导致虚拟机无法正常上网 设备管理器 ...
- Spark记录-Scala介绍
Scala是可扩展语言的缩写,是一种混合功能编程语言. 它由Martin Odersky创建. Scala顺利整合面向对象和函数式语言的功能. Scala被编译后在Java虚拟机上运行. 许多现有公司 ...
- Java中的容器类(List,Set,Map,Queue)
Java中的容器类(List,Set,Map,Queue) 一.基本概念 Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念: 1)Collection.一个独立元素的序列,这些元素都 ...
- c# net 使用反射为对象赋值
public T Bson2T(MongoDB.Bson.BsonDocument bson) { T t = default(T); //获取T类中的所有属性 PropertyInfo[] Tpro ...
- 正则表达式 grep文本查询 sed流处理 应用
一.正则表达: ^:以什么什么开头,^a:以a字符开头 $:以什么什么结尾,b$:以b字符结尾 *:左边字符0-无穷个 +:左边字符1-无穷个 .:代表单字符 ?:前导字符为零个或1个 {n}:左面字 ...
- spring断言使用
断言就是断定某一个实际的值为自己预期想得到的,如果不一样就抛出异常. Assert经常用于: 1.判断method的参数是否属于正常值.2.juit中使用. import org.springfram ...
- 16、DecimalFormat类
DecimalFormat类概述 在一些金融或者银行的业务里面,会出现这样千分位格式的数字,¥123,456.00,表示人民币壹拾贰万叁仟肆佰伍拾陆元整,java.text包下提供了一个Decimal ...
- 字符串hash&&对字符串hash的理解
对字符串hash的一些总结: 1,首先,我们在转化的时候,取底的时候一般是取131这些数,因为要避免不同的字符串对应相同的hash值这种情况的出现.如果卡精度的时候,我们可以采取双模数的方式尽量减少 ...