自定义类重载运算符<< >>,并用FileStorage保存和读取xml文件

本文介绍如何在OpenCV中自定义一个类并实现该类的XML文件存储和读取功能,包括图像和不同类型的点集数据。

OpenCV在2.0以后的版本中提供了FileStorage类,供用户将数据保存为xml或者YAML文件。本文的内容就是介绍如何自定义类,而后重载<< 和 >> 运算符,并通过FileStorage保存和读取xml文件。

自定义一个数据类,想要保存的数据为一张图像,以及std::vector<cv::Point>和std::vector<std::vector<cv::Point> > 两类点集。

自定义类的头文件mydata.h

#pragma once
#include <core/mat.hpp>
#include <ostream>
#include <core/persistence.hpp>

class MyData
{
public:
	MyData();
	~MyData();

	void setImage(cv::Mat image);
	void setSingleRect(std::vector<cv::Point> singleRect);
	void setMultiRect(std::vector<std::vector<cv::Point> > multiRect);

	cv::Mat getImage();
	std::vector<cv::Point> getSingleRect();
	std::vector<std::vector<cv::Point> > getMultiRect();

	friend cv::FileStorage& operator<<(cv::FileStorage& fs, MyData& obj);
	friend MyData& operator>>(cv::FileStorage& fs, MyData& obj);


private:
	cv::Mat image;
	std::vector<cv::Point> singleRect;
	std::vector<std::vector<cv::Point> > multiRect;

};

自定义类的源文件mydata.c

#include "MyData.h"  
  
MyData::MyData()  
{  
      
}  
  
MyData::~MyData()  
{  
}  
  
void MyData::setImage(cv::Mat image)  
{  
    image.copyTo(this->image);  
}  
  
void MyData::setSingleRect(std::vector<cv::Point> singleRect)  
{  
    this->singleRect = singleRect;  
}  
  
void MyData::setMultiRect(std::vector<std::vector<cv::Point>> multiRect)  
{  
    this->multiRect = multiRect;  
}  
  
cv::Mat MyData::getImage()  
{  
    return this->image;  
}  
  
std::vector<cv::Point> MyData::getSingleRect()  
{  
    return this->singleRect;  
}  
  
std::vector<std::vector<cv::Point>> MyData::getMultiRect()  
{  
    return this->multiRect;  
}  
  
cv::FileStorage& operator<<(cv::FileStorage& fs, MyData& obj)  
{  
    fs << "image" << obj.image;  
    fs << "singleRect" << obj.singleRect;  
      
    // 注意singleRect与multiRect存放时的不同  
    fs << "multiRect" << "{";   
    for (int i = 0; i < obj.multiRect.size(); i++)  
    {  
        fs << "multiRect_" + std::to_string(i) << obj.multiRect[i];  
    }  
    fs << "}";  
  
    return fs;  
}  
  
MyData& operator>>(cv::FileStorage& fs, MyData& obj)  
{  
    fs["image"] >> obj.image;  
    fs["singleRect"] >> obj.singleRect;  
  
    cv::FileNode fn = fs["multiRect"];   
    for (auto nodeItor = fn.begin(); nodeItor != fn.end(); ++nodeItor)  
    {  
        std::vector<cv::Point> pts;  
        *nodeItor >> pts;  
        obj.multiRect.push_back(pts);  
    }  
  
    return obj;  
} 
主程序:
#include "mydata.h"  
  
int main()  
{  
    MyData myDataWrite;  
    myDataWrite.setImage(cv::Mat(3, 3, CV_8UC3, cv::Scalar(0, 255, 255)));  // 构造图像存入数据类  
    std::vector<cv::Point> singleRect = {cv::Point(1, 1), cv::Point(2, 2)}; // 构造一个矩形的两个顶点点集  
    myDataWrite.setSingleRect(singleRect);  
    std::vector<std::vector<cv::Point> > multiRect = {singleRect, singleRect, singleRect}; // 保存两个矩形的点集  
    myDataWrite.setMultiRect(multiRect);  
  
    // 将数据保存至xml文件  
    cv::FileStorage fsWrite("mydata.xml", cv::FileStorage::WRITE);  
    fsWrite << myDataWrite;  
    fsWrite.release();  
  
    // 从xml文件中读取数据  
    MyData myDataRead;  
    cv::FileStorage fsRead("mydata.xml", cv::FileStorage::READ);  
    fsRead >> myDataRead;  
    fsRead.release();  
  
    std::cout << myDataRead.getSingleRect().size() << std::endl;  
    std::cout << myDataRead.getMultiRect().size() << std::endl;  
  
    return 0;  
}
保存的xml文件内容如下图


注意singleRect与multiRect存放时的不同,如果用相同的方式存储即:

fs << "multiRect" << obj.multiRect;  
则这一部分的数据将为


### 如何使用 OpenCV 进行写入操作 #### 使用 `cv::imwrite` 函数写入图像文件 OpenCV 提供了一个简单易用的函数 `cv::imwrite()` 来将图像数据写入文件。该函数可以用于保存处理后的图像到指定路径下的文件中[^2]。 以下是 C++ 中的一个示例代码,展示了如何使用 `cv::imwrite` 将图像保存为 JPEG 文件: ```cpp #include <opencv2/opencv.hpp> using namespace cv; int main() { // 加载图像 Mat image = imread("input_image.jpg", IMREAD_COLOR); if (image.empty()) { std::cout << "Could not open or find the image!" << std::endl; return -1; } // 对图像进行某种处理(此处省略) // ... // 保存图像到文件 bool success = imwrite("output_image.jpg", image); if (!success) { std::cout << "Failed to write the image!" << std::endl; return -1; } std::cout << "Image successfully written to file." << std::endl; return 0; } ``` 上述代码加载了一张名为 `input_image.jpg` 的图片,并将其保存为新的文件 `output_image.jpg`。如果无法打开原始图像或者保存失败,则会打印错误消息。 --- #### 序列化反序列化的实现 除了基本的图像读写外,OpenCV 还允许通过 XML 或 YAML 文件存储复杂的数据结构,比如矩阵 (`Mat`) 向量 (`std::vector`) 等。这可以通过 FileStorage 类完成[^4]。 ##### 写入数据XML/YAML 文件 以下是一个完整的例子,说明如何将矩阵其他变量写入 XML 文件: ```cpp #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 创建一些测试数据 Mat R = Mat_<uchar>::eye(3, 3); // 单位矩阵 Mat T = Mat_<uchar>::zeros(3, 3); // 零矩阵 int iterationNr = 7; // 整数迭代次数 // 打开一个FileStorage对象以写模式创建XML文件 FileStorage fs("test.xml", FileStorage::WRITE); if (!fs.isOpened()) { // 检查是否成功打开文件 cout << "Error opening file for writing" << endl; return -1; } // 向文件中写入数据 fs << "iterationNr" << iterationNr; fs << "R" << R; fs << "T" << T; // 关闭文件 fs.release(); cout << "Data has been saved into test.xml" << endl; return 0; } ``` 此程序定义了一些基础数据类型(如整型数值以及两个小型矩阵),并将它们存入名为 `test.xml` 的 XML 文件中。 --- #### 数据读取对比分析 对于从文件中提取已存储的信息部分提到两种方法: - **第一种方式**:利用重载运算符 >> 实现直接赋值给目标变量; - **第二种方式**:采用强制转换的形式获取对应字段的内容[(见引用)](^4])。 两者的主要区别在于语法风格上的差异,但在功能上几乎一致。具体选择取决于个人编码习惯或团队内部规范的要求。 --- #### Python 版本实例补充 虽然提问主要针对的是 C++ 平台下 OpenCV 的运用场景介绍;但是考虑到跨平台兼容性灵活性考虑,这里也附带提供一段基于 Python 的相似功能实现片段作为参考[^3]: ```python import cv2 import numpy as np # 构建示例数据 R = np.eye(3, dtype=np.uint8) # 单位阵 T = np.zeros((3, 3), dtype=np.uint8) # 全零阵 data_dict = {"R": R, "T": T} # 存储至文件 file_name = 'example.yml' cv_file = cv2.FileStorage(file_name, cv2.FILE_STORAGE_WRITE) for key in data_dict.keys(): cv_file.write(key, data_dict[key]) cv_file.release() print(f'Data serialized and stored in {file_name}') ``` 这段脚本同样实现了把几个 NumPy 数组形式表示的小规模二维数组打包记录下来的功能。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值