233 lines
10 KiB
C++
233 lines
10 KiB
C++
#include "VrConfig.h"
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include "VrLog.h"
|
|
#include "ConfigXmlUtils.h"
|
|
|
|
using namespace tinyxml2;
|
|
|
|
CVrConfig::CVrConfig() : m_pNotify(nullptr)
|
|
{
|
|
// 构造函数
|
|
}
|
|
|
|
CVrConfig::~CVrConfig()
|
|
{
|
|
// 析构函数
|
|
}
|
|
|
|
int CVrConfig::LoadConfig(const std::string& filePath, ConfigResult& configResult)
|
|
{
|
|
// 使用tinyxml2库加载XML文件
|
|
XMLDocument doc;
|
|
XMLError err = doc.LoadFile(filePath.c_str());
|
|
if (err != XML_SUCCESS)
|
|
{
|
|
LOG_ERR("Failed to open config file: %s\n", filePath.c_str());
|
|
return LOAD_CONFIG_FILE_NOT_FOUND;
|
|
}
|
|
|
|
// 获取根元素
|
|
XMLElement* root = doc.RootElement();
|
|
if (!root || std::string(root->Name()) != "RodAndBarPositionConfig")
|
|
{
|
|
LOG_ERR("Config file format error: root element is not RodAndBarPositionConfig\n");
|
|
return LOAD_CONFIG_INVALID_FORMAT;
|
|
}
|
|
|
|
// 1. 解析相机设备列表
|
|
ConfigXmlUtils::LoadCameraList(root, configResult.cameraList);
|
|
|
|
// 2. 解析算法参数
|
|
XMLElement* algoElement = root->FirstChildElement("AlgorithmParams");
|
|
if (algoElement)
|
|
{
|
|
// 2.1 解析棒材检测参数 (RodParam)
|
|
XMLElement* rodElement = algoElement->FirstChildElement("RodParam");
|
|
if (rodElement)
|
|
{
|
|
rodElement->QueryDoubleAttribute("rodDiameter", &configResult.algorithmParams.rodParam.rodDiameter);
|
|
rodElement->QueryDoubleAttribute("rodLen", &configResult.algorithmParams.rodParam.rodLen);
|
|
|
|
LOG_INFO("RodParam: rodDiameter=%.1f, rodLen=%.1f\n",
|
|
configResult.algorithmParams.rodParam.rodDiameter,
|
|
configResult.algorithmParams.rodParam.rodLen);
|
|
}
|
|
|
|
// 2.2 解析离群点滤波参数 (FilterParam)
|
|
XMLElement* filterElement = algoElement->FirstChildElement("FilterParam");
|
|
if (filterElement)
|
|
{
|
|
filterElement->QueryDoubleAttribute("continuityTh", &configResult.algorithmParams.filterParam.continuityTh);
|
|
filterElement->QueryDoubleAttribute("outlierTh", &configResult.algorithmParams.filterParam.outlierTh);
|
|
|
|
LOG_INFO("FilterParam: continuityTh=%.1f, outlierTh=%.1f\n",
|
|
configResult.algorithmParams.filterParam.continuityTh,
|
|
configResult.algorithmParams.filterParam.outlierTh);
|
|
}
|
|
|
|
// 2.3 解析角点检测参数 (CornerParam)
|
|
XMLElement* cornerElement = algoElement->FirstChildElement("CornerParam");
|
|
if (cornerElement)
|
|
{
|
|
cornerElement->QueryDoubleAttribute("minEndingGap", &configResult.algorithmParams.cornerParam.minEndingGap);
|
|
cornerElement->QueryDoubleAttribute("minEndingGap_z", &configResult.algorithmParams.cornerParam.minEndingGap_z);
|
|
cornerElement->QueryDoubleAttribute("scale", &configResult.algorithmParams.cornerParam.scale);
|
|
cornerElement->QueryDoubleAttribute("cornerTh", &configResult.algorithmParams.cornerParam.cornerTh);
|
|
cornerElement->QueryDoubleAttribute("jumpCornerTh_1", &configResult.algorithmParams.cornerParam.jumpCornerTh_1);
|
|
cornerElement->QueryDoubleAttribute("jumpCornerTh_2", &configResult.algorithmParams.cornerParam.jumpCornerTh_2);
|
|
|
|
LOG_INFO("CornerParam: minEndingGap=%.1f, cornerTh=%.1f\n",
|
|
configResult.algorithmParams.cornerParam.minEndingGap,
|
|
configResult.algorithmParams.cornerParam.cornerTh);
|
|
}
|
|
|
|
// 2.4 解析树生长参数 (GrowParam)
|
|
XMLElement* growElement = algoElement->FirstChildElement("GrowParam");
|
|
if (growElement)
|
|
{
|
|
growElement->QueryDoubleAttribute("yDeviation_max", &configResult.algorithmParams.growParam.yDeviation_max);
|
|
growElement->QueryDoubleAttribute("zDeviation_max", &configResult.algorithmParams.growParam.zDeviation_max);
|
|
growElement->QueryIntAttribute("maxLineSkipNum", &configResult.algorithmParams.growParam.maxLineSkipNum);
|
|
growElement->QueryDoubleAttribute("maxSkipDistance", &configResult.algorithmParams.growParam.maxSkipDistance);
|
|
growElement->QueryDoubleAttribute("minLTypeTreeLen", &configResult.algorithmParams.growParam.minLTypeTreeLen);
|
|
growElement->QueryDoubleAttribute("minVTypeTreeLen", &configResult.algorithmParams.growParam.minVTypeTreeLen);
|
|
|
|
LOG_INFO("GrowParam: yDeviation_max=%.1f, zDeviation_max=%.1f\n",
|
|
configResult.algorithmParams.growParam.yDeviation_max,
|
|
configResult.algorithmParams.growParam.zDeviation_max);
|
|
}
|
|
|
|
// 2.5 解析平面标定参数 (PlaneCalibParams)
|
|
ConfigXmlUtils::LoadPlaneCalibParams(algoElement, configResult.algorithmParams.planeCalibParam);
|
|
}
|
|
|
|
// 3. 解析调试参数
|
|
ConfigXmlUtils::LoadDebugParam(root, configResult.debugParam);
|
|
|
|
// 4. 解析串口配置
|
|
ConfigXmlUtils::LoadSerialConfig(root, configResult.serialConfig);
|
|
|
|
// 5. 解析网络参数
|
|
XMLElement* networkElement = root->FirstChildElement("NetworkConfig");
|
|
if (networkElement)
|
|
{
|
|
networkElement->QueryIntAttribute("eulerOrder", &configResult.eulerOrder);
|
|
networkElement->QueryIntAttribute("dirVectorInvert", &configResult.dirVectorInvert);
|
|
networkElement->QueryIntAttribute("byteOrder", &configResult.byteOrder);
|
|
networkElement->QueryIntAttribute("longAxisDir", &configResult.longAxisDir);
|
|
|
|
LOG_INFO("Network config: eulerOrder=%d, dirVectorInvert=%d, byteOrder=%d, longAxisDir=%d\n",
|
|
configResult.eulerOrder, configResult.dirVectorInvert, configResult.byteOrder, configResult.longAxisDir);
|
|
}
|
|
|
|
// 6. 解析手眼标定矩阵列表(支持多相机)
|
|
ConfigXmlUtils::LoadHandEyeCalibMatrixs(root, configResult.handEyeCalibMatrixList, configResult.eulerOrder);
|
|
|
|
LOG_INFO("Config loaded successfully from: %s\n", filePath.c_str());
|
|
return LOAD_CONFIG_SUCCESS;
|
|
}
|
|
|
|
bool CVrConfig::SaveConfig(const std::string& filePath, ConfigResult& configResult)
|
|
{
|
|
XMLDocument doc;
|
|
|
|
// 创建 XML 声明
|
|
XMLDeclaration* declaration = doc.NewDeclaration();
|
|
doc.InsertFirstChild(declaration);
|
|
|
|
// 创建根元素
|
|
XMLElement* root = doc.NewElement("RodAndBarPositionConfig");
|
|
doc.InsertEndChild(root);
|
|
|
|
// 1. 保存相机设备列表
|
|
ConfigXmlUtils::SaveCameraList(doc, root, configResult.cameraList);
|
|
|
|
// 2. 保存算法参数
|
|
XMLElement* algoElement = doc.NewElement("AlgorithmParams");
|
|
|
|
// 2.1 保存棒材检测参数
|
|
XMLElement* rodElement = doc.NewElement("RodParam");
|
|
rodElement->SetAttribute("rodDiameter", configResult.algorithmParams.rodParam.rodDiameter);
|
|
rodElement->SetAttribute("rodLen", configResult.algorithmParams.rodParam.rodLen);
|
|
algoElement->InsertEndChild(rodElement);
|
|
|
|
// 2.2 保存离群点滤波参数
|
|
XMLElement* filterElement = doc.NewElement("FilterParam");
|
|
filterElement->SetAttribute("continuityTh", configResult.algorithmParams.filterParam.continuityTh);
|
|
filterElement->SetAttribute("outlierTh", configResult.algorithmParams.filterParam.outlierTh);
|
|
algoElement->InsertEndChild(filterElement);
|
|
|
|
// 2.3 保存角点检测参数
|
|
XMLElement* cornerElement = doc.NewElement("CornerParam");
|
|
cornerElement->SetAttribute("cornerTh", configResult.algorithmParams.cornerParam.cornerTh);
|
|
cornerElement->SetAttribute("scale", configResult.algorithmParams.cornerParam.scale);
|
|
cornerElement->SetAttribute("minEndingGap", configResult.algorithmParams.cornerParam.minEndingGap);
|
|
cornerElement->SetAttribute("minEndingGap_z", configResult.algorithmParams.cornerParam.minEndingGap_z);
|
|
cornerElement->SetAttribute("jumpCornerTh_1", configResult.algorithmParams.cornerParam.jumpCornerTh_1);
|
|
cornerElement->SetAttribute("jumpCornerTh_2", configResult.algorithmParams.cornerParam.jumpCornerTh_2);
|
|
algoElement->InsertEndChild(cornerElement);
|
|
|
|
// 2.4 保存树生长参数
|
|
XMLElement* growElement = doc.NewElement("GrowParam");
|
|
growElement->SetAttribute("maxLineSkipNum", configResult.algorithmParams.growParam.maxLineSkipNum);
|
|
growElement->SetAttribute("yDeviation_max", configResult.algorithmParams.growParam.yDeviation_max);
|
|
growElement->SetAttribute("maxSkipDistance", configResult.algorithmParams.growParam.maxSkipDistance);
|
|
growElement->SetAttribute("zDeviation_max", configResult.algorithmParams.growParam.zDeviation_max);
|
|
growElement->SetAttribute("minLTypeTreeLen", configResult.algorithmParams.growParam.minLTypeTreeLen);
|
|
growElement->SetAttribute("minVTypeTreeLen", configResult.algorithmParams.growParam.minVTypeTreeLen);
|
|
algoElement->InsertEndChild(growElement);
|
|
|
|
// 2.5 保存平面标定参数
|
|
ConfigXmlUtils::SavePlaneCalibParams(doc, algoElement, configResult.algorithmParams.planeCalibParam);
|
|
|
|
root->InsertEndChild(algoElement);
|
|
|
|
// 3. 保存调试参数
|
|
ConfigXmlUtils::SaveDebugParam(doc, root, configResult.debugParam);
|
|
|
|
// 4. 保存串口配置
|
|
ConfigXmlUtils::SaveSerialConfig(doc, root, configResult.serialConfig);
|
|
|
|
// 5. 保存网络参数
|
|
XMLElement* networkElement = doc.NewElement("NetworkConfig");
|
|
networkElement->SetAttribute("eulerOrder", configResult.eulerOrder);
|
|
networkElement->SetAttribute("dirVectorInvert", configResult.dirVectorInvert);
|
|
networkElement->SetAttribute("byteOrder", configResult.byteOrder);
|
|
networkElement->SetAttribute("longAxisDir", configResult.longAxisDir);
|
|
root->InsertEndChild(networkElement);
|
|
|
|
// 6. 保存手眼标定矩阵列表(支持多相机)
|
|
ConfigXmlUtils::SaveHandEyeCalibMatrixs(doc, root, configResult.handEyeCalibMatrixList);
|
|
|
|
// 保存到文件
|
|
XMLError err = doc.SaveFile(filePath.c_str());
|
|
if (err != XML_SUCCESS)
|
|
{
|
|
LOG_ERR("Failed to save config file: %s\n", filePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
LOG_INFO("Config saved successfully to: %s\n", filePath.c_str());
|
|
return true;
|
|
}
|
|
|
|
// 设置配置改变通知回调
|
|
void CVrConfig::SetConfigChangeNotify(IVrConfigChangeNotify* notify)
|
|
{
|
|
m_pNotify = notify;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief 创建实例
|
|
* @return 实例
|
|
*/
|
|
bool IVrConfig::CreateInstance(IVrConfig** ppVrConfig)
|
|
{
|
|
*ppVrConfig = new CVrConfig() ;
|
|
return *ppVrConfig != nullptr;
|
|
}
|