#include "dialogalgoarg.h" #include "ui_dialogalgoarg.h" #include "RodAndBarPositionPresenter.h" #include "StyledMessageBox.h" #include "HandEyeCalibWidget.h" #include "NetworkConfigWidget.h" #include "ToolExtrinsicWidget.h" #include "PathManager.h" #include "VrLog.h" #include #include #include namespace { int PoseOutputOrderToProtocolOrder(int poseOrder) { switch (poseOrder) { case 0: return 10; // RX-RY-RZ -> XYZ case 1: return 15; // RX-RZ-RY -> XZY case 2: return 13; // RY-RX-RZ -> YXZ case 3: return 14; // RY-RZ-RX -> YZX case 4: return 12; // RZ-RX-RY -> ZXY case 5: return 11; // RZ-RY-RX -> ZYX default: return 11; } } int ProtocolOrderToPoseOutputOrder(int protocolOrder) { switch (protocolOrder) { case 10: return 0; // XYZ -> RX-RY-RZ case 15: return 1; // XZY -> RX-RZ-RY case 13: return 2; // YXZ -> RY-RX-RZ case 14: return 3; // YZX -> RY-RZ-RX case 12: return 4; // ZXY -> RZ-RX-RY case 11: return 5; // ZYX -> RZ-RY-RX default: return 5; } } } // namespace DialogAlgoArg::DialogAlgoArg(QWidget *parent) : QDialog(parent) , ui(new Ui::DialogAlgoArg) , m_presenter(nullptr) , m_handEyeCalibWidget(nullptr) , m_networkConfigWidget(nullptr) , m_toolExtrinsicWidget(nullptr) { ui->setupUi(this); const QList spinBoxes = findChildren(); for (QAbstractSpinBox* spinBox : spinBoxes) { spinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); spinBox->setKeyboardTracking(false); } setWindowTitle("算法参数设置"); } DialogAlgoArg::~DialogAlgoArg() { delete ui; } void DialogAlgoArg::SetPresenter(RodAndBarPositionPresenter* presenter) { m_presenter = presenter; loadParams(); // 初始化手眼标定 tab InitHandEyeCalibTab(); // 初始化工具参数 tab InitToolExtrinsicTab(); // 初始化网络配置 tab InitNetworkConfigTab(); } void DialogAlgoArg::loadParams() { if (!m_presenter) { return; } auto params = m_presenter->GetAlgoParams(); // 棒材参数 ui->spinRodDiameter->setValue(params.rodParam.rodDiameter); ui->spinRodLen->setValue(params.rodParam.rodLen); // 角点检测参数 ui->spinCornerTh->setValue(params.cornerParam.cornerTh); ui->spinScale->setValue(params.cornerParam.scale); ui->spinMinEndingGap->setValue(params.cornerParam.minEndingGap); ui->spinMinEndingGapZ->setValue(params.cornerParam.minEndingGap_z); ui->spinJumpCornerTh1->setValue(params.cornerParam.jumpCornerTh_1); ui->spinJumpCornerTh2->setValue(params.cornerParam.jumpCornerTh_2); // 滤波参数 ui->spinContinuityTh->setValue(params.filterParam.continuityTh); ui->spinOutlierTh->setValue(params.filterParam.outlierTh); // 树生长参数 ui->spinMaxLineSkipNum->setValue(params.growParam.maxLineSkipNum); ui->spinYDeviationMax->setValue(params.growParam.yDeviation_max); ui->spinMaxSkipDistance->setValue(params.growParam.maxSkipDistance); ui->spinZDeviationMax->setValue(params.growParam.zDeviation_max); ui->spinMinLTypeTreeLen->setValue(params.growParam.minLTypeTreeLen); ui->spinMinVTypeTreeLen->setValue(params.growParam.minVTypeTreeLen); } void DialogAlgoArg::saveParams() { if (!m_presenter) { return; } auto params = m_presenter->GetAlgoParams(); // 棒材参数 params.rodParam.rodDiameter = ui->spinRodDiameter->value(); params.rodParam.rodLen = ui->spinRodLen->value(); // 角点检测参数 params.cornerParam.cornerTh = ui->spinCornerTh->value(); params.cornerParam.scale = ui->spinScale->value(); params.cornerParam.minEndingGap = ui->spinMinEndingGap->value(); params.cornerParam.minEndingGap_z = ui->spinMinEndingGapZ->value(); params.cornerParam.jumpCornerTh_1 = ui->spinJumpCornerTh1->value(); params.cornerParam.jumpCornerTh_2 = ui->spinJumpCornerTh2->value(); // 滤波参数 params.filterParam.continuityTh = ui->spinContinuityTh->value(); params.filterParam.outlierTh = ui->spinOutlierTh->value(); // 树生长参数 params.growParam.maxLineSkipNum = ui->spinMaxLineSkipNum->value(); params.growParam.yDeviation_max = ui->spinYDeviationMax->value(); params.growParam.maxSkipDistance = ui->spinMaxSkipDistance->value(); params.growParam.zDeviation_max = ui->spinZDeviationMax->value(); params.growParam.minLTypeTreeLen = ui->spinMinLTypeTreeLen->value(); params.growParam.minVTypeTreeLen = ui->spinMinVTypeTreeLen->value(); m_presenter->SetAlgoParams(params); // 保存手眼标定矩阵 + 工具参数 + 网络配置到配置文件(统一获取一次配置,避免互相覆盖) if (m_presenter->GetConfigManager()) { ConfigManager* configManager = m_presenter->GetConfigManager(); SystemConfig systemConfig = configManager->GetConfig(); int protocolEulerOrder = systemConfig.configResult.eulerOrder; // 网络配置保存通信字节序和姿态输入/输出顺序;方向向量/长轴不再提供配置。 if (m_networkConfigWidget) { NetworkConfigData netConfig = m_networkConfigWidget->getConfig(); protocolEulerOrder = PoseOutputOrderToProtocolOrder(netConfig.poseOutputOrder); systemConfig.configResult.byteOrder = netConfig.byteOrder; } systemConfig.configResult.eulerOrder = protocolEulerOrder; // 保存手眼标定矩阵 if (m_handEyeCalibWidget) { const auto& oldMatrixList = systemConfig.configResult.handEyeCalibMatrixList; std::vector newMatrixList; const auto& cameraList = m_presenter->GetCameraList(); int cameraCount = std::max(1, static_cast(cameraList.size())); for (int i = 0; i < cameraCount; ++i) { int camIdx = i + 1; // 先从已有配置中获取该相机的矩阵作为基础 VrHandEyeCalibMatrix calibMatrix; calibMatrix.cameraIndex = camIdx; for (const auto& old : oldMatrixList) { if (old.cameraIndex == camIdx) { calibMatrix = old; break; } } if (m_toolExtrinsicWidget) { int toolEulerOrder = calibMatrix.eulerOrder; double toolRotX = calibMatrix.rotX; double toolRotY = calibMatrix.rotY; double toolRotZ = calibMatrix.rotZ; double toolOffsetX = calibMatrix.offsetX; double toolOffsetY = calibMatrix.offsetY; double toolOffsetZ = calibMatrix.offsetZ; double axialAngleMin = calibMatrix.axialAngleMin; double axialAngleMax = calibMatrix.axialAngleMax; if (m_toolExtrinsicWidget->getData(camIdx, toolEulerOrder, toolRotX, toolRotY, toolRotZ, toolOffsetX, toolOffsetY, toolOffsetZ, axialAngleMin, axialAngleMax)) { calibMatrix.eulerOrder = toolEulerOrder; calibMatrix.rotX = toolRotX; calibMatrix.rotY = toolRotY; calibMatrix.rotZ = toolRotZ; calibMatrix.offsetX = toolOffsetX; calibMatrix.offsetY = toolOffsetY; calibMatrix.offsetZ = toolOffsetZ; calibMatrix.axialAngleMin = axialAngleMin; calibMatrix.axialAngleMax = axialAngleMax; } } // 如果控件中有更新的数据则覆盖 bool isCalibrated = false; double matrix[16]; if (m_handEyeCalibWidget->getCalibData(camIdx, matrix, isCalibrated) && isCalibrated) { memcpy(calibMatrix.matrix, matrix, sizeof(double) * 16); } newMatrixList.push_back(calibMatrix); } systemConfig.configResult.handEyeCalibMatrixList = newMatrixList; } // 统一更新并保存到文件 configManager->UpdateFullConfig(systemConfig); QString configPath = PathManager::GetInstance().GetConfigFilePath(); configManager->SaveConfigToFile(configPath.toStdString()); // 通知 Presenter 重新加载手眼标定矩阵等参数 m_presenter->OnConfigChanged(systemConfig.configResult); } } void DialogAlgoArg::resetParams() { ui->spinRodDiameter->setValue(52.0); ui->spinRodLen->setValue(290.0); ui->spinCornerTh->setValue(60.0); ui->spinScale->setValue(13.0); ui->spinMinEndingGap->setValue(20.0); ui->spinMinEndingGapZ->setValue(5.0); ui->spinJumpCornerTh1->setValue(15.0); ui->spinJumpCornerTh2->setValue(60.0); ui->spinContinuityTh->setValue(5.0); ui->spinOutlierTh->setValue(5.0); ui->spinMaxLineSkipNum->setValue(5); ui->spinYDeviationMax->setValue(10.0); ui->spinMaxSkipDistance->setValue(10.0); ui->spinZDeviationMax->setValue(10.0); ui->spinMinLTypeTreeLen->setValue(100.0); ui->spinMinVTypeTreeLen->setValue(100.0); } void DialogAlgoArg::on_btnOK_clicked() { saveParams(); accept(); } void DialogAlgoArg::on_btnCancel_clicked() { reject(); } void DialogAlgoArg::on_btnApply_clicked() { saveParams(); StyledMessageBox::information(this, "提示", "参数已应用"); } void DialogAlgoArg::on_btnReset_clicked() { auto ret = StyledMessageBox::question(this, "确认重置", "确定要重置为默认参数吗?"); if (ret == QMessageBox::Yes) { resetParams(); } } // ========== 手眼标定相关实现 ========== void DialogAlgoArg::InitHandEyeCalibTab() { if (!ui || !m_presenter) return; m_handEyeCalibWidget = new HandEyeCalibWidget(this); m_handEyeCalibWidget->setMatrixEditable(true); ui->verticalLayout_handEyeCalibHost->addWidget(m_handEyeCalibWidget); m_handEyeCalibWidget->setDefaultFilePath( PathManager::GetInstance().GetAppConfigDirectory()); const auto& cameraList = m_presenter->GetCameraList(); QVector calibCameraList; if (cameraList.empty()) { HandEyeCalibCameraInfo defaultCam; defaultCam.cameraIndex = 1; defaultCam.displayName = QString::fromUtf8("相机 1"); calibCameraList.append(defaultCam); } else { for (size_t i = 0; i < cameraList.size(); ++i) { HandEyeCalibCameraInfo info; info.cameraIndex = static_cast(i + 1); info.displayName = QString::fromStdString(cameraList[i].first); calibCameraList.append(info); } } m_handEyeCalibWidget->setCameraList(calibCameraList); for (const auto& camInfo : calibCameraList) { CalibMatrix calibMatrix = m_presenter->GetClibMatrix(camInfo.cameraIndex - 1); bool hasCalibData = false; for (int i = 0; i < 16; ++i) { double identity = (i / 4 == i % 4) ? 1.0 : 0.0; if (qAbs(calibMatrix.clibMatrix[i] - identity) > 1e-9) { hasCalibData = true; break; } } m_handEyeCalibWidget->setCalibData(camInfo.cameraIndex, calibMatrix.clibMatrix, hasCalibData); } connect(m_handEyeCalibWidget, &HandEyeCalibWidget::calibMatrixLoaded, this, &DialogAlgoArg::onCalibMatrixLoaded); connect(m_handEyeCalibWidget, &HandEyeCalibWidget::saveCalibRequested, this, &DialogAlgoArg::onSaveCalibRequested); } void DialogAlgoArg::onCalibMatrixLoaded(int cameraIndex, const double* matrix) { Q_UNUSED(cameraIndex); Q_UNUSED(matrix); StyledMessageBox::information(this, "提示", "已从文件导入标定矩阵"); } void DialogAlgoArg::onSaveCalibRequested(int cameraIndex, const double* matrix) { Q_UNUSED(cameraIndex); Q_UNUSED(matrix); saveParams(); StyledMessageBox::information(this, "成功", "手眼标定参数已保存!"); } // ========== 工具参数相关实现 ========== void DialogAlgoArg::InitToolExtrinsicTab() { if (!ui || !m_presenter) return; m_toolExtrinsicWidget = new ToolExtrinsicWidget(this); m_toolExtrinsicWidget->setTargetOffsetVisible(true); m_toolExtrinsicWidget->setAxialAngleRangeVisible(true); ui->verticalLayout_toolExtrinsicHost->addWidget(m_toolExtrinsicWidget); const auto& cameraList = m_presenter->GetCameraList(); QVector toolCameraList; if (cameraList.empty()) { ToolExtrinsicCameraInfo defaultCam; defaultCam.cameraIndex = 1; defaultCam.displayName = QString::fromUtf8("相机 1"); toolCameraList.append(defaultCam); } else { for (size_t i = 0; i < cameraList.size(); ++i) { ToolExtrinsicCameraInfo info; info.cameraIndex = static_cast(i + 1); info.displayName = QString::fromStdString(cameraList[i].first); toolCameraList.append(info); } } m_toolExtrinsicWidget->setCameraList(toolCameraList); loadToolExtrinsicConfig(); } void DialogAlgoArg::loadToolExtrinsicConfig() { if (!m_presenter || !m_toolExtrinsicWidget) return; ConfigManager* configManager = m_presenter->GetConfigManager(); if (!configManager) return; ConfigResult configResult = configManager->GetConfigResult(); const auto& cameraList = m_presenter->GetCameraList(); int cameraCount = std::max(1, static_cast(cameraList.size())); for (int i = 0; i < cameraCount; ++i) { int camIdx = i + 1; int toolEulerOrder = 11; double rotX = 0.0; double rotY = 0.0; double rotZ = 0.0; double offsetX = 0.0; double offsetY = 0.0; double offsetZ = 0.0; double axialAngleMin = -180.0; double axialAngleMax = 180.0; for (const auto& toolConfig : configResult.handEyeCalibMatrixList) { if (toolConfig.cameraIndex == camIdx) { toolEulerOrder = toolConfig.eulerOrder; rotX = toolConfig.rotX; rotY = toolConfig.rotY; rotZ = toolConfig.rotZ; offsetX = toolConfig.offsetX; offsetY = toolConfig.offsetY; offsetZ = toolConfig.offsetZ; axialAngleMin = toolConfig.axialAngleMin; axialAngleMax = toolConfig.axialAngleMax; break; } } m_toolExtrinsicWidget->setData(camIdx, toolEulerOrder, rotX, rotY, rotZ, offsetX, offsetY, offsetZ, axialAngleMin, axialAngleMax); } } // ========== 网络配置相关实现 ========== void DialogAlgoArg::InitNetworkConfigTab() { if (!ui || !m_presenter) return; m_networkConfigWidget = new NetworkConfigWidget(false, false, this); ui->verticalLayout_networkConfigHost->addWidget(m_networkConfigWidget); m_networkConfigWidget->setExtrinsicControlsVisible(false); m_networkConfigWidget->setPoseOutputOrderVisible(true); loadNetworkConfig(); } void DialogAlgoArg::loadNetworkConfig() { if (!m_presenter || !m_networkConfigWidget) return; ConfigManager* configManager = m_presenter->GetConfigManager(); if (!configManager) return; ConfigResult configResult = configManager->GetConfigResult(); NetworkConfigData netConfig; netConfig.eulerOrder = configResult.eulerOrder; netConfig.poseOutputOrder = ProtocolOrderToPoseOutputOrder(netConfig.eulerOrder); netConfig.byteOrder = configResult.byteOrder; m_networkConfigWidget->setConfig(netConfig); } void DialogAlgoArg::saveNetworkConfig() { if (!m_presenter || !m_networkConfigWidget) return; ConfigManager* configManager = m_presenter->GetConfigManager(); if (!configManager) return; // 获取当前完整配置并更新网络参数 NetworkConfigData netConfig = m_networkConfigWidget->getConfig(); SystemConfig systemConfig = configManager->GetConfig(); const int protocolEulerOrder = PoseOutputOrderToProtocolOrder(netConfig.poseOutputOrder); systemConfig.configResult.eulerOrder = protocolEulerOrder; systemConfig.configResult.byteOrder = netConfig.byteOrder; // 更新并保存 configManager->UpdateFullConfig(systemConfig); QString configPath = PathManager::GetInstance().GetConfigFilePath(); configManager->SaveConfigToFile(configPath.toStdString()); }