網(wǎng)站首頁 編程語言 正文
前言
本節(jié)我們將認(rèn)識(shí)XML和YAML這兩種文件類型。
所謂XML,即eXtensible Markup Language,翻譯成中文為“可擴(kuò)展標(biāo)識(shí)語言”。首先,XML是一種元標(biāo)記語言。所謂元標(biāo)記,就是開發(fā)者可以根據(jù)自身需要定義自己的標(biāo)記,比如可以定義標(biāo)記<book>、<name>。任何滿足XML命名規(guī)則的名稱都可以標(biāo)記,這就向不同的應(yīng)用程序打開了的大門。此外,XML是一種語義、結(jié)構(gòu)化語言,它描述了文檔的結(jié)構(gòu)與語義。
YAML是YAML Ain’t a Markup Language(YAML不是一種置標(biāo)語言)的縮寫。YAML是一個(gè)可讀性高,用來表達(dá)資料序列的格式。它參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822。
1.如何使用
XML和YAML是使用非常廣泛的文件格式。可以利用XML或者YAML格式的文件存儲(chǔ)和還原各式各樣的數(shù)據(jù)結(jié)構(gòu)。當(dāng)然,它們還可以存儲(chǔ)和載入任意復(fù)雜的數(shù)據(jù)結(jié)構(gòu),其中就包括了OpenCV相關(guān)周邊的數(shù)據(jù)結(jié)構(gòu),以及各種原始數(shù)據(jù)類型,如整數(shù)、浮點(diǎn)數(shù)和文本字符串。
我們一般使用如下過程來寫入或者讀取數(shù)據(jù)到XML或YAML文件中。
(1)實(shí)例化一個(gè)FileStorage類的對(duì)象,用默認(rèn)帶參數(shù)的構(gòu)造函數(shù)完成初始化,或者用FileStorage::open()成員函數(shù)輔助初始化。
(2)使用流操作符<<進(jìn)行文件寫入操作,或者>>進(jìn)行文件讀取操作,類似C++中的文件輸入輸出流。
(3)使用FileStorage::release()函數(shù)析構(gòu)掉FileStorage類對(duì)象,同時(shí)關(guān)閉文件。
1.1第一步:XML、YAML文件的打開
(1)準(zhǔn)備文件寫操作
FileStorage是OpenCV中XML和YAML文件的存儲(chǔ)類,封裝了所有相關(guān)的信息。它是OpenCV從文件中讀數(shù)據(jù)或向文件中寫數(shù)據(jù)時(shí)必須要使用的一個(gè)類。
此類的構(gòu)造函數(shù)為FileStorage::FileStorage,有兩個(gè)重載,如下:
C++:FileStorage::FileStorage()
C++:FileStorage::FileStorage(const string& source, int flags, const string& encoding=string())
構(gòu)造函數(shù)在實(shí)際使用中,一般有兩種方法。
1)對(duì)于第二種帶參數(shù)的構(gòu)造函數(shù),進(jìn)行寫操作范例如下:
FileStorage fs("abc.xml", FileStorage::WRITE);
2)對(duì)于第一種不帶參數(shù)的構(gòu)造函數(shù),可以使用其成員函數(shù)FileStorage::open進(jìn)行數(shù)據(jù)的寫操作,范例如下:
FileStorage fs;
fs.open("abc.xml",FileStorage::WRITE);
(2)準(zhǔn)備文件讀操作
上面講到的都是以FileStorage::WRITE為標(biāo)識(shí)符的寫操作,而讀操作,采用FileStorage::READ標(biāo)識(shí)符即可,相關(guān)示例代碼如下:
1)第一種方式
FileStorage fs(“abc.xml”, FileStorage::READ);
2)第二種方式
FileStorage fs;
fs.open(“abc.xml”, FileStorage::READ);
另外需要注意的是,上面的這些操作示例是對(duì)XML文件為例子作演示的,而對(duì)YAML文件,操作方法是類似的,就是將XML文件換為YAML文件即可。
1.2 第二步:進(jìn)行文件讀寫操作
(1)文本和數(shù)字的輸入和輸出
定義好FileStorage類對(duì)象之后,寫入文件可以使用<<運(yùn)算符,例如:
fs<<"iterationNr"<<100;
而讀取文件,使用>>運(yùn)算符,例如:
int itNr;
fs["iterationNr"]>>itNr;
itNr = (int) fs["iterationNr"];
(2)OpenCV數(shù)據(jù)結(jié)構(gòu)的輸入和輸出
關(guān)于OpenCV數(shù)據(jù)結(jié)構(gòu)的輸入和輸出,和基本的C++形式相同,范例如下:
// 數(shù)據(jù)結(jié)構(gòu)的初始化
Mat R = Mat_<uchar>::eye(3,3);
Mat T = Mat_<double>::zeros(3, 1);
// 向Mat中寫入數(shù)據(jù)
fs << "R" << R;
fs << "T" << T;
// 從Mat中讀取數(shù)據(jù)
fs["R"] >> R;
fs["T"] >> T;
1.3 第三步:vector(array)和map的輸入和輸出
對(duì)于vector結(jié)構(gòu)的輸出和輸出,要注意在第一個(gè)元素前加上”[“,在最后一個(gè)元素后加上”]“。例如:
fs << "strings"<<"["; //開始讀入string文本序列
fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
fs << "]"; //關(guān)閉序列
而對(duì)于map結(jié)構(gòu)的操作,使用的符號(hào)是”{“和”}“,例如:
fs << "Mapping";//開始讀入Mapping文本
fs << "{" << "One" << 1;
fs << "Two" << 2 << "}";
讀取這些數(shù)據(jù)結(jié)構(gòu)的時(shí)候,會(huì)用到FileNode和FileNodeIterator數(shù)據(jù)結(jié)構(gòu)。對(duì)FileStorage類的“[”、“]”操作符會(huì)返回FileNode數(shù)據(jù)類型;對(duì)于一連串的node,可以使用FileNodeIterator結(jié)構(gòu),例如:
```cpp
FileNode n = fs["strings"];//讀取字符串序列以得到節(jié)點(diǎn)
if (n.type()!=FileNode::SEQ)
{
cerr << "發(fā)生錯(cuò)誤!字符串不是一個(gè)序列" << endl;
return 1;
}
FileNodeIterator it = n.begin(),it_end = n.end(); //遍歷節(jié)點(diǎn)
for(;it!=it_end;it++)
cout << (string)*it << endl;
1.4 第四步:文件關(guān)閉
需要注意的是,文件關(guān)閉操作會(huì)在FileStorage類銷毀時(shí)自動(dòng)進(jìn)行,但我們也可以顯式調(diào)用其析構(gòu)函數(shù)FileStorage::release()實(shí)現(xiàn)。FileStorage::release()函數(shù)會(huì)析構(gòu)掉FileStorage類對(duì)象,同時(shí)關(guān)閉文件。
調(diào)用過程非常簡單,如下:fs.release();
2.代碼展示
2.1 寫文件
#include<opencv2/opencv.hpp>
#include<time.h>
using namespace cv;
int main()
{
//初始化
FileStorage fs("test.yaml", FileStorage::WRITE);
//開始文件寫入
fs << "frameCount" << 5;
time_t rawtime; time(&rawtime);
fs << "calibrationDate" << asctime(localtime(&rawtime));//讀取時(shí)間量
Mat cameraMatrix = (Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);
Mat distCoeffs = (Mat_<double>(5, 1) << 0.1, 0.01, -0.001, 0, 0);//畸變參數(shù)
fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;//讀取Mat型cameraMatrix,distcoeffs的內(nèi)容
fs << "feature" << "[";
for (int i = 0; i < 3; i++)
{
int x = rand() % 640;
int y = rand() % 480;
uchar ibp = rand() % 256;
fs << "{:" << "x" << x << "y" << y << "ibp" << "[:";
for (int j = 0; j < 8; j++)
fs << ((ibp >> j) & 1);
fs << "]" << "}";
}
fs << "]";
fs.release();
printf("完畢,請(qǐng)?jiān)诠こ棠夸浵虏榭次募?");
getchar();
return 0;
}
上面的示例將一個(gè)整數(shù)、一個(gè)文本字符串(標(biāo)定日期)、2 個(gè)矩陣和一個(gè)自定義結(jié)構(gòu)“feature”存儲(chǔ)到 YML,其中包括特征坐標(biāo)和 LBP(局部二進(jìn)制模式)值。這是樣本的輸出:
%YAML:1.0
frameCount: 5
calibrationDate: "Fri Jun 17 14:09:29 2011\n"
cameraMatrix: !!opencv-matrix
? ?rows: 3
? ?cols: 3
? ?dt: d
? ?data: [ 1000., 0., 320., 0., 1000., 240., 0., 0., 1. ]
distCoeffs: !!opencv-matrix
? ?rows: 5
? ?cols: 1
? ?dt: d
? ?data: [ 1.0000000000000001e-01, 1.0000000000000000e-02,
? ? ? ?-1.0000000000000000e-03, 0., 0. ]
features:
? ?- { x:167, y:49, lbp:[ 1, 0, 0, 1, 1, 0, 1, 1 ] }
? ?- { x:298, y:130, lbp:[ 0, 0, 0, 1, 0, 0, 1, 1 ] }
? ?- { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] }
作為練習(xí),您可以將上面示例中的“.yml”替換為“.xml”或“.json”,然后查看相應(yīng)的 XML 文件的外觀。
通過查看示例代碼和輸出可以注意到幾件事:
- 生成的 YAML(和 XML/JSON)由可以嵌套的異構(gòu)集合組成。有兩種類型的集合:命名集合(映射)和未命名集合(序列)。在映射中,每個(gè)元素都有一個(gè)名稱并通過名稱訪問。這類似于 C/C++ 中的std::map結(jié)構(gòu)以及 Python 中的字典。在序列中元素沒有名稱,它們通過索引訪問。這類似于 C/C++ 中的std::vector數(shù)組以及 Python 中的列表、元組。“異構(gòu)”意味著每個(gè)單一集合的元素可以有不同的類型。
- YAML/XML/JSON 中的頂級(jí)集合是一個(gè)映射。每個(gè)矩陣存儲(chǔ)為一個(gè)映射,矩陣元素存儲(chǔ)為一個(gè)序列。然后,有一個(gè)特征序列,其中每個(gè)特征都表示一個(gè)映射,以及嵌套序列中的 lbp 值。
- 當(dāng)您寫入映射(結(jié)構(gòu))時(shí),您寫入元素名稱后跟其值。當(dāng)您寫入一個(gè)序列時(shí),您只需一個(gè)一個(gè)地寫入元素。OpenCV 數(shù)據(jù)結(jié)構(gòu)(例如cv::Mat)的編寫方式與簡單的 C 數(shù)據(jù)結(jié)構(gòu)完全相同 - 使用<<運(yùn)算符。
- 要編寫映射,首先寫入特殊字符串{,然后將元素作為對(duì) ( fs << <element_name> << <element_value>) 寫入,然后寫入結(jié)束符}。
- 要編寫一個(gè)序列,首先要編寫特殊的字符串[,然后編寫元素,然后編寫結(jié)束]。
- 在 YAML/JSON(但不是 XML)中,映射和序列可以以類似 Python 的緊湊內(nèi)聯(lián)形式編寫。在上面的示例中,矩陣元素以及每個(gè)特征,包括它的 lbp 值,都以這種內(nèi)聯(lián)形式存儲(chǔ)。要以緊湊的形式存儲(chǔ)映射/序列,請(qǐng)放在:開始字符之后,例如使用{:代替{和[:代替[。當(dāng)數(shù)據(jù)寫入 XML 時(shí),那些額外:的將被忽略。
2.2 讀文件
#include<opencv2/opencv.hpp>
#include<time.h>
using namespace cv;
using namespace std;
int main()
{
//改變consolo字體顏色
system("color 6F");
//初始化
FileStorage fs2("test.yaml", FileStorage::READ);
//開始文件讀取
//法一,對(duì)FileNode操作
int frameCount2 = (int)fs2["framecount2"];
std::string date;//定義字符串 date
//法二,使用FileNode運(yùn)算符>>
fs2["calibrationDate"] >> date;
Mat cameraMatrix2, distCoeffs2;
fs2["cameraMatrix"] >> cameraMatrix2;
fs2["distCoeffs"] >> distCoeffs2;//讀取
cout << "frameCount2:" << frameCount2 << endl
<< "calibration date:" << date << endl
<< "camera matrix:" << cameraMatrix2 << endl
<< "distortion coeffs:" << distCoeffs2 << endl;
FileNode feature = fs2["feature"];
FileNodeIterator it = feature.begin(), it_end = feature.end();//定義it
int idx = 0;
std::vector<uchar>ibpval;//定義向量容器ibpal
//使用FileNodeIterator歷遍序列(讀取)
for (; it != it_end; it++, idx++)
{
cout << "feature#" << idx << ":";
cout << "x=" << (int)(*it)["x"] << ",y=" << (int)(*it)["y"] << ",ibp:(";
//也可以使用filenod>>std::vector操作符很容易讀取數(shù)值陣列
(*it)["ibp"] >> ibpval;
for (int i = 0; i < (int)ibpval.size(); i++)
cout << "" << (int)ibpval[i];
cout << ")" << endl;
}
fs2.release();
printf("讀取完畢,請(qǐng)按任意鍵結(jié)束-");
getchar();
return 0;
}
2.3 完整的示例代碼
/*
* filestorage_sample demonstrate the usage of the opencv serialization functionality
*/
#include "opencv2/core.hpp"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::cerr;
using std::ostream;
using namespace cv;
static void help(char** av)
{
cout << "\nfilestorage_sample demonstrate the usage of the opencv serialization functionality.\n"
<< "usage:\n"
<< av[0] << " outputfile.yml.gz\n"
<< "\n outputfile above can have many different extensions, see below."
<< "\nThis program demonstrates the use of FileStorage for serialization, that is in use << and >> in OpenCV\n"
<< "For example, how to create a class and have it serialize, but also how to use it to read and write matrices.\n"
<< "FileStorage allows you to serialize to various formats specified by the file end type."
<< "\nYou should try using different file extensions.(e.g. yaml yml xml xml.gz yaml.gz etc...)\n" << endl;
}
struct MyData
{
MyData() :
A(0), X(0), id()
{
}
explicit MyData(int) :
A(97), X(CV_PI), id("mydata1234")
{
}
int A;
double X;
string id;
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"];
}
};
//These write and read functions must exist as per the inline functions in operations.hpp
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);
}
static ostream& operator<<(ostream& out, const MyData& m){
out << "{ id = " << m.id << ", ";
out << "X = " << m.X << ", ";
out << "A = " << m.A << "}";
return out;
}
int main(int ac, char** av)
{
cv::CommandLineParser parser(ac, av,
"{@input||}{help h ||}"
);
if (parser.has("help"))
{
help(av);
return 0;
}
string filename = parser.get<string>("@input");
if (filename.empty())
{
help(av);
return 1;
}
//write
{
FileStorage fs(filename, FileStorage::WRITE);
cout << "writing images\n";
fs << "images" << "[";
fs << "image1.jpg" << "myfi.png" << "baboon.jpg";
cout << "image1.jpg" << " myfi.png" << " baboon.jpg" << endl;
fs << "]";
cout << "writing mats\n";
Mat R =Mat_<double>::eye(3, 3),T = Mat_<double>::zeros(3, 1);
cout << "R = " << R << "\n";
cout << "T = " << T << "\n";
fs << "R" << R;
fs << "T" << T;
cout << "writing MyData struct\n";
MyData m(1);
fs << "mdata" << m;
cout << m << endl;
}
//read
{
FileStorage fs(filename, FileStorage::READ);
if (!fs.isOpened())
{
cerr << "failed to open " << filename << endl;
help(av);
return 1;
}
FileNode n = fs["images"];
if (n.type() != FileNode::SEQ)
{
cerr << "images is not a sequence! FAIL" << endl;
return 1;
}
cout << "reading images\n";
FileNodeIterator it = n.begin(), it_end = n.end();
for (; it != it_end; ++it)
{
cout << (string)*it << "\n";
}
Mat R, T;
cout << "reading R and T" << endl;
fs["R"] >> R;
fs["T"] >> T;
cout << "R = " << R << "\n";
cout << "T = " << T << endl;
MyData m;
fs["mdata"] >> m;
cout << "read mdata\n";
cout << m << endl;
cout << "attempting to read mdata_b\n"; //Show default behavior for empty matrix
fs["mdata_b"] >> m;
cout << "read mdata_b\n";
cout << m << endl;
}
cout << "Try opening " << filename << " to see the serialized data." << endl << endl;
//read from string
{
cout << "Read data from string\n";
string dataString =
"%YAML:1.0\n"
"mdata:\n"
" A: 97\n"
" X: 3.1415926535897931e+00\n"
" id: mydata1234\n";
MyData m;
FileStorage fs(dataString, FileStorage::READ | FileStorage::MEMORY);
cout << "attempting to read mdata_b from string\n"; //Show default behavior for empty matrix
fs["mdata"] >> m;
cout << "read mdata\n";
cout << m << endl;
}
//write to string
{
cout << "Write data to string\n";
FileStorage fs(filename, FileStorage::WRITE | FileStorage::MEMORY | FileStorage::FORMAT_YAML);
cout << "writing MyData struct\n";
MyData m(1);
fs << "mdata" << m;
cout << m << endl;
string createdString = fs.releaseAndGetString();
cout << "Created string:\n" << createdString << "\n";
}
return 0;
}
原文鏈接:https://blog.csdn.net/weixin_43229348/article/details/124620459
相關(guān)推薦
- 2022-10-06 Android?Fragment源碼分析Add方法_Android
- 2022-06-02 Kubernetes關(guān)鍵組件與結(jié)構(gòu)組成介紹_云和虛擬化
- 2022-12-05 C++?Boost?Heap使用實(shí)例詳解_C 語言
- 2022-07-18 SQL?Server中元數(shù)據(jù)函數(shù)的用法_MsSql
- 2023-02-01 Python動(dòng)態(tài)演示旋轉(zhuǎn)矩陣的作用詳解_python
- 2024-03-03 Layui 主窗口調(diào)用 iframe 彈出框模塊,獲取控件的相應(yīng)值
- 2022-05-10 @requestmapping獲取請(qǐng)求參數(shù)
- 2022-07-22 解決安裝時(shí)間序列分析庫fbprophet
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支