GrabBag/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp

470 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "VrWheelMeasureConfig.h"
#include "IVrWheelMeasureConfig.h"
#include <algorithm>
#include <sstream>
#include "VrLog.h"
#include <QFile>
#include <QTextStream>
#include <QString>
#include <QTextCodec>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
VrWheelMeasureConfig::VrWheelMeasureConfig()
: m_notify(nullptr)
{
}
VrWheelMeasureConfig::~VrWheelMeasureConfig()
{
}
// 静态工厂方法
bool IVrWheelMeasureConfig::CreateInstance(IVrWheelMeasureConfig** ppVrConfig)
{
if (!ppVrConfig) {
return false;
}
*ppVrConfig = new VrWheelMeasureConfig();
return true;
}
WheelMeasureConfigResult VrWheelMeasureConfig::LoadConfig(const std::string& filePath)
{
WheelMeasureConfigResult result;
// 使用QString处理可能包含中文的路径
QString qFilePath = QString::fromStdString(filePath);
QFile file(qFilePath);
// 检查文件是否存在并可读
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_DEBUG("Failed to open file: %s\n", filePath.c_str());
return result;
}
// 使用QXmlStreamReader解析XML内容
QXmlStreamReader xml(&file);
// 读取到根元素
if (xml.readNextStartElement()) {
if (xml.name() != "WheelMeasureConfig") {
xml.raiseError(QObject::tr("Not a WheelMeasureConfig file"));
}
} else {
xml.raiseError(QObject::tr("Failed to read root element"));
}
// 解析XML内容
while (!xml.atEnd() && !xml.hasError()) {
xml.readNext();
// 解析相机配置
if (xml.isStartElement() && xml.name() == "Cameras") {
while (xml.readNextStartElement()) {
if (xml.name() == "Camera") {
WheelCameraParam camera;
camera.cameraIndex = xml.attributes().value("index").toInt();
camera.name = xml.attributes().value("name").toString().toStdString();
camera.cameraIP = xml.attributes().value("ip").toString().toStdString();
camera.enabled = xml.attributes().value("enabled").toInt() != 0;
result.cameras.push_back(camera);
xml.skipCurrentElement();
}
}
}
// 解析相机调平参数
else if (xml.isStartElement() && xml.name() == "PlaneCalibParams") {
while (xml.readNextStartElement()) {
if (xml.name() == "CameraCalib") {
WheelCameraPlaneCalibParam calibParam;
calibParam.cameraIndex = xml.attributes().value("index").toInt();
calibParam.cameraName = xml.attributes().value("name").toString().toStdString();
calibParam.planeHeight = xml.attributes().value("planeHeight").toDouble();
calibParam.isCalibrated = xml.attributes().value("isCalibrated").toInt() != 0;
// 读取误差补偿参数,默认值为-5.0
if (xml.attributes().hasAttribute("errorCompensation")) {
calibParam.errorCompensation = xml.attributes().value("errorCompensation").toDouble();
} else {
calibParam.errorCompensation = -5.0;
}
// 读取修正系数默认值为1.0
if (xml.attributes().hasAttribute("correctionFactor")) {
calibParam.correctionFactor = xml.attributes().value("correctionFactor").toDouble();
} else {
calibParam.correctionFactor = 1.0;
}
// 读取轮胎存在检测的3D ROI范围
if (xml.attributes().hasAttribute("wheelRoi3d_xMin")) {
calibParam.wheelRoi3d_xMin = xml.attributes().value("wheelRoi3d_xMin").toDouble();
calibParam.wheelRoi3d_xMax = xml.attributes().value("wheelRoi3d_xMax").toDouble();
calibParam.wheelRoi3d_yMin = xml.attributes().value("wheelRoi3d_yMin").toDouble();
calibParam.wheelRoi3d_yMax = xml.attributes().value("wheelRoi3d_yMax").toDouble();
calibParam.wheelRoi3d_zMin = xml.attributes().value("wheelRoi3d_zMin").toDouble();
calibParam.wheelRoi3d_zMax = xml.attributes().value("wheelRoi3d_zMax").toDouble();
} else {
// 默认值
calibParam.wheelRoi3d_xMin = -1000.0;
calibParam.wheelRoi3d_xMax = 1000.0;
calibParam.wheelRoi3d_yMin = -1000.0;
calibParam.wheelRoi3d_yMax = 1000.0;
calibParam.wheelRoi3d_zMin = -1000.0;
calibParam.wheelRoi3d_zMax = 1000.0;
}
// 读取planeCalib矩阵
QString planeCalibStr = xml.attributes().value("planeCalib").toString();
QStringList planeCalibList = planeCalibStr.split(",");
for (int i = 0; i < 9 && i < planeCalibList.size(); ++i) {
calibParam.planeCalib[i] = planeCalibList[i].toDouble();
}
// 读取invRMatrix矩阵
QString invRMatrixStr = xml.attributes().value("invRMatrix").toString();
QStringList invRMatrixList = invRMatrixStr.split(",");
for (int i = 0; i < 9 && i < invRMatrixList.size(); ++i) {
calibParam.invRMatrix[i] = invRMatrixList[i].toDouble();
}
result.planeCalibParams.push_back(calibParam);
xml.skipCurrentElement();
}
}
}
// 解析算法参数
else if (xml.isStartElement() && xml.name() == "AlgorithmParams") {
while (xml.readNextStartElement()) {
// 角点参数
if (xml.name() == "CornerParam") {
result.algorithmParams.cornerParam.minEndingGap =
xml.attributes().value("minEndingGap").toDouble();
result.algorithmParams.cornerParam.minEndingGap_z =
xml.attributes().value("minEndingGap_z").toDouble();
result.algorithmParams.cornerParam.scale =
xml.attributes().value("scale").toDouble();
result.algorithmParams.cornerParam.cornerTh =
xml.attributes().value("cornerTh").toDouble();
result.algorithmParams.cornerParam.jumpCornerTh_1 =
xml.attributes().value("jumpCornerTh_1").toDouble();
result.algorithmParams.cornerParam.jumpCornerTh_2 =
xml.attributes().value("jumpCornerTh_2").toDouble();
// 设置默认值
if (result.algorithmParams.cornerParam.minEndingGap == 0.0) {
result.algorithmParams.cornerParam.minEndingGap = 3.0;
}
if (result.algorithmParams.cornerParam.minEndingGap_z == 0.0) {
result.algorithmParams.cornerParam.minEndingGap_z = 5.0;
}
if (result.algorithmParams.cornerParam.scale == 0.0) {
result.algorithmParams.cornerParam.scale = 10.0;
}
if (result.algorithmParams.cornerParam.cornerTh == 0.0) {
result.algorithmParams.cornerParam.cornerTh = 130.0;
}
if (result.algorithmParams.cornerParam.jumpCornerTh_1 == 0.0) {
result.algorithmParams.cornerParam.jumpCornerTh_1 = 5.0;
}
if (result.algorithmParams.cornerParam.jumpCornerTh_2 == 0.0) {
result.algorithmParams.cornerParam.jumpCornerTh_2 = 2.0;
}
xml.skipCurrentElement();
}
// 线段参数
else if (xml.name() == "LineSegParam") {
result.algorithmParams.lineSegParam.segGapTh_y =
xml.attributes().value("segGapTh_y").toDouble();
result.algorithmParams.lineSegParam.segGapTh_z =
xml.attributes().value("segGapTh_z").toDouble();
result.algorithmParams.lineSegParam.maxDist =
xml.attributes().value("maxDist").toDouble();
// 设置默认值
if (result.algorithmParams.lineSegParam.segGapTh_y == 0.0) {
result.algorithmParams.lineSegParam.segGapTh_y = 5.0;
}
if (result.algorithmParams.lineSegParam.segGapTh_z == 0.0) {
result.algorithmParams.lineSegParam.segGapTh_z = 10.0;
}
if (result.algorithmParams.lineSegParam.maxDist == 0.0) {
result.algorithmParams.lineSegParam.maxDist = 50.0;
}
xml.skipCurrentElement();
}
// 离群点过滤参数
else if (xml.name() == "OutlierFilterParam") {
result.algorithmParams.filterParam.continuityTh =
xml.attributes().value("continuityTh").toDouble();
result.algorithmParams.filterParam.outlierTh =
xml.attributes().value("outlierTh").toDouble();
// 设置默认值
if (result.algorithmParams.filterParam.continuityTh == 0.0) {
result.algorithmParams.filterParam.continuityTh = 5.0;
}
if (result.algorithmParams.filterParam.outlierTh == 0.0) {
result.algorithmParams.filterParam.outlierTh = 3.0;
}
xml.skipCurrentElement();
}
// 树生长参数
else if (xml.name() == "TreeGrowParam") {
result.algorithmParams.growParam.yDeviation_max =
xml.attributes().value("yDeviation_max").toDouble();
result.algorithmParams.growParam.zDeviation_max =
xml.attributes().value("zDeviation_max").toDouble();
result.algorithmParams.growParam.maxLineSkipNum =
xml.attributes().value("maxLineSkipNum").toInt();
result.algorithmParams.growParam.maxSkipDistance =
xml.attributes().value("maxSkipDistance").toDouble();
result.algorithmParams.growParam.minLTypeTreeLen =
xml.attributes().value("minLTypeTreeLen").toDouble();
result.algorithmParams.growParam.minVTypeTreeLen =
xml.attributes().value("minVTypeTreeLen").toDouble();
// 设置默认值
if (result.algorithmParams.growParam.yDeviation_max == 0.0) {
result.algorithmParams.growParam.yDeviation_max = 20.0;
}
if (result.algorithmParams.growParam.zDeviation_max == 0.0) {
result.algorithmParams.growParam.zDeviation_max = 30.0;
}
if (result.algorithmParams.growParam.maxLineSkipNum == 0) {
result.algorithmParams.growParam.maxLineSkipNum = 5;
}
if (result.algorithmParams.growParam.minLTypeTreeLen == 0.0) {
result.algorithmParams.growParam.minLTypeTreeLen = 10.0;
}
if (result.algorithmParams.growParam.minVTypeTreeLen == 0.0) {
result.algorithmParams.growParam.minVTypeTreeLen = 10.0;
}
xml.skipCurrentElement();
}
else {
xml.skipCurrentElement();
}
}
}
// 解析调试参数
else if (xml.isStartElement() && xml.name() == "DebugParam") {
result.debugParam.enableDebug = xml.attributes().value("enableDebug").toInt();
result.debugParam.savePointCloud = xml.attributes().value("savePointCloud").toInt();
result.debugParam.saveDebugImage = xml.attributes().value("saveDebugImage").toInt();
result.debugParam.printDetailLog = xml.attributes().value("printDetailLog").toInt();
result.debugParam.debugOutputPath = xml.attributes().value("debugOutputPath").toString().toStdString();
xml.skipCurrentElement();
}
// 解析服务端配置
else if (xml.isStartElement() && xml.name() == "LocalServerConfig") {
while (xml.readNextStartElement()) {
if (xml.name() == "ServerPort") {
result.serverPort = xml.attributes().value("port").toInt();
xml.skipCurrentElement();
} else if (xml.name() == "TcpPort") {
result.tcpPort = xml.attributes().value("port").toInt();
if (result.tcpPort == 0) {
result.tcpPort = 5800; // 默认值
}
xml.skipCurrentElement();
} else {
xml.skipCurrentElement();
}
}
}
// 解析服务器列表
else if (xml.isStartElement() && xml.name() == "Servers") {
while (xml.readNextStartElement()) {
if (xml.name() == "Server") {
WheelServerInfo server;
server.name = xml.attributes().value("name").toString().toStdString();
server.ip = xml.attributes().value("ip").toString().toStdString();
server.port = xml.attributes().value("port").toInt();
if (server.port == 0) {
server.port = 5800; // 默认端口
}
result.servers.push_back(server);
xml.skipCurrentElement();
} else {
xml.skipCurrentElement();
}
}
}
}
file.close();
// 检查解析错误
if (xml.hasError()) {
LOG_ERROR("XML parsing error: %s\n", xml.errorString().toStdString().c_str());
return WheelMeasureConfigResult(); // 返回空结果
}
return result;
}
bool VrWheelMeasureConfig::SaveConfig(const std::string& filePath, WheelMeasureConfigResult& configResult)
{
// 使用QString处理可能包含中文的路径
QString qFilePath = QString::fromStdString(filePath);
QFile file(qFilePath);
// 打开文件进行写入
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
LOG_DEBUG("Failed to open file for writing: %s\n", filePath.c_str());
return false;
}
// 使用QXmlStreamWriter写入XML内容
QXmlStreamWriter xml(&file);
xml.setAutoFormatting(true);
xml.setCodec("UTF-8");
xml.writeStartDocument();
xml.writeStartElement("WheelMeasureConfig");
// 保存相机配置
xml.writeStartElement("Cameras");
for (const auto& camera : configResult.cameras) {
xml.writeStartElement("Camera");
xml.writeAttribute("index", QString::number(camera.cameraIndex));
xml.writeAttribute("name", QString::fromStdString(camera.name));
xml.writeAttribute("ip", QString::fromStdString(camera.cameraIP));
xml.writeAttribute("enabled", QString::number(camera.enabled ? 1 : 0));
xml.writeEndElement(); // Camera
}
xml.writeEndElement(); // Cameras
// 保存相机调平参数
xml.writeStartElement("PlaneCalibParams");
for (const auto& calibParam : configResult.planeCalibParams) {
xml.writeStartElement("CameraCalib");
xml.writeAttribute("index", QString::number(calibParam.cameraIndex));
xml.writeAttribute("name", QString::fromStdString(calibParam.cameraName));
xml.writeAttribute("planeHeight", QString::number(calibParam.planeHeight, 'f', 6));
xml.writeAttribute("isCalibrated", QString::number(calibParam.isCalibrated ? 1 : 0));
xml.writeAttribute("errorCompensation", QString::number(calibParam.errorCompensation, 'f', 2));
xml.writeAttribute("correctionFactor", QString::number(calibParam.correctionFactor, 'f', 8));
// 保存轮胎存在检测的3D ROI范围
xml.writeAttribute("wheelRoi3d_xMin", QString::number(calibParam.wheelRoi3d_xMin, 'f', 2));
xml.writeAttribute("wheelRoi3d_xMax", QString::number(calibParam.wheelRoi3d_xMax, 'f', 2));
xml.writeAttribute("wheelRoi3d_yMin", QString::number(calibParam.wheelRoi3d_yMin, 'f', 2));
xml.writeAttribute("wheelRoi3d_yMax", QString::number(calibParam.wheelRoi3d_yMax, 'f', 2));
xml.writeAttribute("wheelRoi3d_zMin", QString::number(calibParam.wheelRoi3d_zMin, 'f', 2));
xml.writeAttribute("wheelRoi3d_zMax", QString::number(calibParam.wheelRoi3d_zMax, 'f', 2));
// 保存planeCalib矩阵
QStringList planeCalibList;
for (int i = 0; i < 9; ++i) {
planeCalibList.append(QString::number(calibParam.planeCalib[i], 'f', 8));
}
xml.writeAttribute("planeCalib", planeCalibList.join(","));
// 保存invRMatrix矩阵
QStringList invRMatrixList;
for (int i = 0; i < 9; ++i) {
invRMatrixList.append(QString::number(calibParam.invRMatrix[i], 'f', 8));
}
xml.writeAttribute("invRMatrix", invRMatrixList.join(","));
xml.writeEndElement(); // CameraCalib
}
xml.writeEndElement(); // PlaneCalibParams
// 保存算法参数
xml.writeStartElement("AlgorithmParams");
// 角点参数
xml.writeStartElement("CornerParam");
xml.writeAttribute("minEndingGap", QString::number(configResult.algorithmParams.cornerParam.minEndingGap));
xml.writeAttribute("minEndingGap_z", QString::number(configResult.algorithmParams.cornerParam.minEndingGap_z));
xml.writeAttribute("scale", QString::number(configResult.algorithmParams.cornerParam.scale));
xml.writeAttribute("cornerTh", QString::number(configResult.algorithmParams.cornerParam.cornerTh));
xml.writeAttribute("jumpCornerTh_1", QString::number(configResult.algorithmParams.cornerParam.jumpCornerTh_1));
xml.writeAttribute("jumpCornerTh_2", QString::number(configResult.algorithmParams.cornerParam.jumpCornerTh_2));
xml.writeEndElement(); // CornerParam
// 线段参数
xml.writeStartElement("LineSegParam");
xml.writeAttribute("segGapTh_y", QString::number(configResult.algorithmParams.lineSegParam.segGapTh_y));
xml.writeAttribute("segGapTh_z", QString::number(configResult.algorithmParams.lineSegParam.segGapTh_z));
xml.writeAttribute("maxDist", QString::number(configResult.algorithmParams.lineSegParam.maxDist));
xml.writeEndElement(); // LineSegParam
// 离群点过滤参数
xml.writeStartElement("OutlierFilterParam");
xml.writeAttribute("continuityTh", QString::number(configResult.algorithmParams.filterParam.continuityTh));
xml.writeAttribute("outlierTh", QString::number(configResult.algorithmParams.filterParam.outlierTh));
xml.writeEndElement(); // OutlierFilterParam
// 树生长参数
xml.writeStartElement("TreeGrowParam");
xml.writeAttribute("yDeviation_max", QString::number(configResult.algorithmParams.growParam.yDeviation_max));
xml.writeAttribute("zDeviation_max", QString::number(configResult.algorithmParams.growParam.zDeviation_max));
xml.writeAttribute("maxLineSkipNum", QString::number(configResult.algorithmParams.growParam.maxLineSkipNum));
xml.writeAttribute("maxSkipDistance", QString::number(configResult.algorithmParams.growParam.maxSkipDistance));
xml.writeAttribute("minLTypeTreeLen", QString::number(configResult.algorithmParams.growParam.minLTypeTreeLen));
xml.writeAttribute("minVTypeTreeLen", QString::number(configResult.algorithmParams.growParam.minVTypeTreeLen));
xml.writeEndElement(); // TreeGrowParam
xml.writeEndElement(); // AlgorithmParams
// 保存调试参数
xml.writeStartElement("DebugParam");
xml.writeAttribute("enableDebug", QString::number(configResult.debugParam.enableDebug));
xml.writeAttribute("savePointCloud", QString::number(configResult.debugParam.savePointCloud));
xml.writeAttribute("saveDebugImage", QString::number(configResult.debugParam.saveDebugImage));
xml.writeAttribute("printDetailLog", QString::number(configResult.debugParam.printDetailLog));
xml.writeAttribute("debugOutputPath", QString::fromStdString(configResult.debugParam.debugOutputPath));
xml.writeEndElement(); // DebugParam
// 保存服务端配置
xml.writeStartElement("LocalServerConfig");
xml.writeStartElement("ServerPort");
xml.writeAttribute("port", QString::number(configResult.serverPort));
xml.writeEndElement(); // ServerPort
xml.writeStartElement("TcpPort");
xml.writeAttribute("port", QString::number(configResult.tcpPort));
xml.writeEndElement(); // TcpPort
xml.writeEndElement(); // LocalServerConfig
// 保存服务器列表
xml.writeStartElement("Servers");
for (const auto& server : configResult.servers) {
xml.writeStartElement("Server");
xml.writeAttribute("name", QString::fromStdString(server.name));
xml.writeAttribute("ip", QString::fromStdString(server.ip));
xml.writeAttribute("port", QString::number(server.port));
xml.writeEndElement(); // Server
}
xml.writeEndElement(); // Servers
xml.writeEndElement(); // WheelMeasureConfig
xml.writeEndDocument();
file.close();
// 通知配置改变
if (m_notify) {
m_notify->OnConfigChanged(configResult);
}
return true;
}
void VrWheelMeasureConfig::SetConfigChangeNotify(IVrWheelMeasureConfigChangeNotify* notify)
{
m_notify = notify;
}