一. Boost库介绍
利用Boost
库对视觉任务参数的存读时,有一个缺陷就是如果UI
界面新增参数时,在界面初始化的时候会读取不到这个新增的参数,导致原任务设置好的的参数会被清掉进而变成默认参数,需要重新做任务保存参数。这对项目初期开发阶段而言非常不友好,增大调试时间成本。
一般需要增加版本号来解决上述的问题:
namespace boost { namespace serialization { template<typename Archive> void serialize(Archive & ar, MS_CreateModelSingle_Params & d, const unsigned int version) { //VISION_LOG_INFO("%d", version);查看版本号 ar & BOOST_SERIALIZATION_NVP(d.m_isPreventReverse);//是否启用防反 ar & BOOST_SERIALIZATION_NVP(d.m_threshLow); //阈值下限 ar & BOOST_SERIALIZATION_NVP(d.m_threshHigh); //阈值上限 ar & BOOST_SERIALIZATION_NVP(d.m_area); //面积 if(version == 2) //只有 version = 新版本号才读取新参数 { ar & BOOST_SERIALIZATION_NVP(d.m_areaRatio); //面积占比 } } } } BOOST_CLASS_VERSION(MS_CreateModelSingle_Params, 2);//当前新版本号,重新保存任务版本号将会更新
这样的话,在初始化的时候就不会读取到新增的参数,也就不会崩溃了。只有在重新保存参数的时候,才会将新增的参数保存到任务文件中。
二. QJson库介绍
本文使用QJson
库来作为参数的保存与读取,不使用版本信息也可解决上述Boost
库存在的缺陷。
JSON
(JavaScript
对象表示法)是一种轻量级的数据交换格式。它可以表示整数,实数,字符串,值的有序序列以及名称/值对的集合。
关于Qt
中对JSON
的生成与解析,Qt5
以前的版本,可以使用QJson
库,需要单独下载、编译,才能使用。到了 Qt5
,提供了专门的QJsonDocument
及其相关类来读和写JSON
文档。
Json类 | 介绍 |
QJsonDoucument | 它封装了一个完整的 JSON 文档,并且可以从 UTF-8 编码的基于文本的表示以及 Qt 自己的二进制格式读取和写入该文档 |
QJsonArray | JSON 数组是一个值列表。可以通过从数组中插入和删除 QJsonValue 来操作该列表 |
QJsonObject | JSON 对象是键值对的列表,其中键是唯一的字符串,值由 QJsonValue 表示 |
QJsonValue | 该类封装了 JSON 支持的数据类型 |
三. QJson库生成与解析结构体数据
安装环境:本文使用的Qt
版本—Qt5.12.10
1、包含头文件:
#include <QJsonDocument>
2、将结构体中的数据序列化成本地Json
数据(toJson
— 生成数据),
struct MS_EdgeLineFitParam { //初始化结构体内数据 MS_EdgeLineFitParam() { m_isAssignCenterEdge = false; m_measureWidth = 5; m_measureHeight = 0.0; } bool m_isAssignCenterEdge; int m_measureWidth; double m_measureHeight; //将结构体中的数据序列化成本地`Json`数据 QJsonValue toJson() { // 定义 { } 对象 QJsonObject jObj; // 插入元素,对应键值对 jObj.insert("m_isAssignCenterEdge", m_isAssignCenterEdge); jObj.insert("m_measureWidth", m_measureWidth); jObj.insert("m_measureHeight", m_measureHeight); return QJsonValue(jObj); } };
3、将本地Json
数据进行反序列化成结构体中的数据(fromJson
— 解析数据),
struct MS_EdgeLineFitParam { //初始化结构体内数据 MS_EdgeLineFitParam() { m_isAssignCenterEdge= false; m_measureWidth= 5; m_dMeasureHeight = 0.0; } bool m_isAssignCenterEdge; int m_measureWidth; double m_measureHeight; //将本地`Json`数据进行反序列化成结构体中的数据 static MS_EdgeLineFitParam fromJson(QJsonValue _json) { MS_EdgeLineFitParam task; //定义空对象 QJsonObject jObj = _json.toObject(); //将Json类型数据进行反序列化 task.m_isAssignCenterEdge= jObj.value("m_isAssignCenterEdge").toBool(); task.m_measureWidth= jObj.value("m_measureWidth").toInt(); task.m_measureHeight= jObj.value("m_measureHeight").toDouble(); return task; } };
四. QJson库读、存数据的完整代码操作
1、结构体数据类型的序列化与反序列化
enum ME_EdgeLineFitShape { EDGELINE_LINE = 0, };
struct MS_IntersectionParam { MS_IntersectionParam() { m_intersectionEdgeOne = 0; } int m_intersectionEdgeOne; static MS_IntersectionParam fromJson(QJsonValue _json) { MS_IntersectionParam task; QJsonObject jObj = _json.toObject(); task.m_intersectionEdgeOne = jObj.value("m_intersectionEdgeOne").toInt(); return task; } QJsonValue toJson() { QJsonObject jObj; jObj.insert("m_intersectionEdgeOne", m_intersectionEdgeOne); return QJsonValue(jObj); } };
struct MS_EdgeLineFitParam { //初始化结构体内数据 MS_EdgeLineFitParam() { m_isAssignCenterEdge= false; m_measureWidth= 5; m_dMeasureHeight = 0.0; } bool m_isAssignCenterEdge; int m_measureWidth; double m_measureHeight; ME_EdgeLineFitShape m_edgeLineFitShape; //自定义的枚举 ME_EdgeLineFitShape MS_IntersectionParam m_intersectionParam; //自定义的结构体 MS_IntersectionParam static MS_EdgeLineFitParam fromJson(QJsonValue _json) { MS_EdgeLineFitParam task; QJsonObject jObj = _json.toObject(); task.m_isAssignCenterEdge = jObj.value("m_isAssignCenterEdge").toBool(); task.m_measureWidth = jObj.value("m_measureWidth").toInt(); task.m_measureHeight = jObj.value("m_measureHeight").toDouble(); //fromJson中自定义的枚举的写法 task.m_edgeLineFitShape = (ME_EdgeLineFitShape)jObj.value("m_edgeLineFitShape").toInt(); //fromJson中自定义结构体的写法 task.m_intersectionParam = MS_IntersectionParam::fromJson(jObj.value("m_intersectionParam")); return task; } QJsonValue toJson() { QJsonObject jObj; jObj.insert("m_isAssignCenterEdge", m_isAssignCenterEdge); jObj.insert("m_measureWidth", m_measureWidth); jObj.insert("m_measureHeight", m_measureHeight); //toJson中自定义的枚举的写法和常规写法一致 jObj.insert("m_edgeLineFitShape", m_edgeLineFitShape); //toJson中自定义结构体的写法 jObj.insert("m_intersectionParam", m_intersectionParam.toJson()); return QJsonValue(jObj); } };
struct VISIONLIBRARY_API MS_EdgeLineFit { //输出结构体包含的数据类型map,bool std::map<int, MS_EdgeLineFitParam> m_edgeLineFitParam; bool m_isAffineContour = true; //解析、读取保存到的本地数据 static MS_EdgeLineFit fromJson(QJsonValue _json) { MS_EdgeLineFit task; QJsonObject jObj = _json.toObject(); task.m_name = QString(jObj.value("m_name").toString().toLocal8Bit()); //fromJson中自定义map的写法 QJsonArray edgeLineFitParam = jObj.value("m_edgeLineFitParam").toArray(); for (auto value : edgeLineFitParam) { QJsonArray jArr = value.toArray(); int num = jArr[0].toInt(); MS_EdgeLineFitParam fitParam = MS_EdgeLineFitParam::fromJson(jArr[1]); task.m_edgeLineFitParam.insert(std::map<int, MS_EdgeLineFitParam>::value_type(num, fitParam)); } task.m_isAffineContour = jObj.value("m_isAffineContour").toBool(); return task; } //结构体数据通过toJson转换保存本地 QJsonValue toJson() { QJsonObject jObj; jObj.insert("task_name", m_name); std::map<int, MS_EdgeLineFitParam>::iterator fitParamIter; QJsonArray fitParamJArr; for (fitParamIter = m_edgeLineFitParam.begin(); fitParamIter != m_edgeLineFitParam.end(); fitParamIter++) { QJsonArray jArr; jArr.append(fitParamIter->first); jArr.append(fitParamIter->second.toJson()); fitParamJArr.append(jArr); } jObj.insert("m_edgeLineFitParam", fitParamJArr); jObj.insert("m_isAffineContour", m_isAffineContour); return QJsonValue(jObj); } }; Q_DECLARE_METATYPE(MS_EdgeLineFit)
2、读、存QJson
生成的.json
文件
MS_EdgeLineFit::MS_EdgeLineFit(const QString& _name) { m_name = _name; m_edgeLineFitPath = "./VisionFiles/EdgeLineFit/" + m_name + "/"; read(); }
bool MS_EdgeLineFit::read() { QDir traDir(m_edgeLineFitPath); if (!traDir.exists()) { ERROR_VISION("read attachData faild due to no such directory!"); return true; } QString fileName = QString(m_edgeLineFitPath + "attachData.json").toStdString().c_str(); INFO_VISION("read attachData taskPath, %s", fileName.toStdString().c_str()); QFileInfo cfg_json(fileName); if (!cfg_json.exists()) { INFO_VISION("read attachData faild due to no such file!"); return false; } QFile file_json(fileName); if (!(file_json.open(QIODevice::ReadOnly | QIODevice::Text))) { INFO_VISION("read attachData faild due to file cannot be opened!"); return false; } QByteArray cfgContent = file_json.readAll(); file_json.close(); QJsonParseError jsonError; QJsonDocument jsonDoc = QJsonDocument::fromJson(cfgContent, &jsonError); if (!jsonDoc.isNull() && (jsonError.error == QJsonParseError::NoError) && jsonDoc.isObject()) { INFO_VISION("read attachData success, %s", fileName.toStdString().c_str()); QJsonObject jObj = jsonDoc.object(); MS_EdgeLineFit task = MS_EdgeLineFit::fromJson(jObj.value("Task")); m_edgeLineFitParam = task.m_edgeLineFitParam; m_isAffineContour = task.m_isAffineContour; return true; } else { INFO_VISION("read attachData faild due to attachData exception!"); return false; } }
bool MS_EdgeLineFit::write() { writeGraphic(); QString fileName = QString(m_edgeLineFitPath + "attachData.json").toStdString().c_str(); INFO_VISION("write attachData taskPath, %s", fileName.toStdString().c_str()); QJsonDocument doc; QJsonObject jObj; MS_EdgeLineFit task(m_name); task.m_edgeFitHRegion = m_edgeFitHRegion; task.m_isAffineContour = m_isAffineContour; jObj.insert("Task", task.toJson()); doc.setObject(jObj); QString jsonText = doc.toJson(); QFile cfgFile(fileName); if (!(cfgFile.open(QIODevice::WriteOnly | QIODevice::Text))) { ERROR_VISION("Error occured in write attachData fail due to file cannot be opened!"); return false; } cfgFile.write(jsonText.toStdString().data()); cfgFile.close(); return true; }
五. 总结
本文主要对结构体中数据类型使用QJson
库的方式进行读存,数据类型包括bool
、int
、double
、enum
、map
等,以及结构体内嵌套子结构体情况下的处理。
下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。 |