357 lines
13 KiB
C++
357 lines
13 KiB
C++
#include "dialogalgoarg.h"
|
||
#include "ui_dialogalgoarg.h"
|
||
#include "RodWeldSeamPresenter.h"
|
||
#include "StyledMessageBox.h"
|
||
#include "HandEyeCalibWidget.h"
|
||
#include "NetworkConfigWidget.h"
|
||
#include "PathManager.h"
|
||
#include "VrLog.h"
|
||
#include <cstring>
|
||
|
||
DialogAlgoArg::DialogAlgoArg(QWidget *parent)
|
||
: QDialog(parent)
|
||
, ui(new Ui::DialogAlgoArg)
|
||
, m_presenter(nullptr)
|
||
, m_handEyeCalibWidget(nullptr)
|
||
, m_networkConfigWidget(nullptr)
|
||
{
|
||
ui->setupUi(this);
|
||
setWindowTitle("算法参数设置");
|
||
}
|
||
|
||
DialogAlgoArg::~DialogAlgoArg()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
void DialogAlgoArg::SetPresenter(RodWeldSeamPresenter* presenter)
|
||
{
|
||
m_presenter = presenter;
|
||
loadParams();
|
||
|
||
// 初始化手眼标定 tab
|
||
InitHandEyeCalibTab();
|
||
|
||
// 初始化网络配置 tab
|
||
InitNetworkConfigTab();
|
||
}
|
||
|
||
void DialogAlgoArg::loadParams()
|
||
{
|
||
if (!m_presenter) {
|
||
return;
|
||
}
|
||
|
||
auto params = m_presenter->GetAlgoParams();
|
||
|
||
// 钢筋与焊缝参数
|
||
ui->editRodDiameter->setText(QString::number(params.rodParam.rodDiameter, 'f', 1));
|
||
ui->editRodLen->setText(QString::number(params.rodParam.rodLen, 'f', 1));
|
||
ui->editWeldSeanRange->setText(QString::number(params.weldSeamParam.weldSeanRange, 'f', 1));
|
||
|
||
// 角点检测参数
|
||
ui->editCornerTh->setText(QString::number(params.cornerParam.cornerTh, 'f', 1));
|
||
ui->editScale->setText(QString::number(params.cornerParam.scale, 'f', 1));
|
||
ui->editMinEndingGap->setText(QString::number(params.cornerParam.minEndingGap, 'f', 1));
|
||
ui->editMinEndingGapZ->setText(QString::number(params.cornerParam.minEndingGap_z, 'f', 1));
|
||
ui->editJumpCornerTh1->setText(QString::number(params.cornerParam.jumpCornerTh_1, 'f', 1));
|
||
ui->editJumpCornerTh2->setText(QString::number(params.cornerParam.jumpCornerTh_2, 'f', 1));
|
||
|
||
// 滤波参数
|
||
ui->editContinuityTh->setText(QString::number(params.filterParam.continuityTh, 'f', 1));
|
||
ui->editOutlierTh->setText(QString::number(params.filterParam.outlierTh, 'f', 1));
|
||
|
||
// 树生长参数
|
||
ui->editMaxLineSkipNum->setText(QString::number(params.growParam.maxLineSkipNum));
|
||
ui->editYDeviationMax->setText(QString::number(params.growParam.yDeviation_max, 'f', 1));
|
||
ui->editMaxSkipDistance->setText(QString::number(params.growParam.maxSkipDistance, 'f', 1));
|
||
ui->editZDeviationMax->setText(QString::number(params.growParam.zDeviation_max, 'f', 1));
|
||
ui->editMinLTypeTreeLen->setText(QString::number(params.growParam.minLTypeTreeLen, 'f', 1));
|
||
ui->editMinVTypeTreeLen->setText(QString::number(params.growParam.minVTypeTreeLen, 'f', 1));
|
||
}
|
||
|
||
void DialogAlgoArg::saveParams()
|
||
{
|
||
if (!m_presenter) {
|
||
return;
|
||
}
|
||
|
||
auto params = m_presenter->GetAlgoParams();
|
||
|
||
// 钢筋与焊缝参数
|
||
params.rodParam.rodDiameter = ui->editRodDiameter->text().toDouble();
|
||
params.rodParam.rodLen = ui->editRodLen->text().toDouble();
|
||
params.weldSeamParam.weldSeanRange = ui->editWeldSeanRange->text().toDouble();
|
||
|
||
// 角点检测参数
|
||
params.cornerParam.cornerTh = ui->editCornerTh->text().toDouble();
|
||
params.cornerParam.scale = ui->editScale->text().toDouble();
|
||
params.cornerParam.minEndingGap = ui->editMinEndingGap->text().toDouble();
|
||
params.cornerParam.minEndingGap_z = ui->editMinEndingGapZ->text().toDouble();
|
||
params.cornerParam.jumpCornerTh_1 = ui->editJumpCornerTh1->text().toDouble();
|
||
params.cornerParam.jumpCornerTh_2 = ui->editJumpCornerTh2->text().toDouble();
|
||
|
||
// 滤波参数
|
||
params.filterParam.continuityTh = ui->editContinuityTh->text().toDouble();
|
||
params.filterParam.outlierTh = ui->editOutlierTh->text().toDouble();
|
||
|
||
// 树生长参数
|
||
params.growParam.maxLineSkipNum = ui->editMaxLineSkipNum->text().toInt();
|
||
params.growParam.yDeviation_max = ui->editYDeviationMax->text().toDouble();
|
||
params.growParam.maxSkipDistance = ui->editMaxSkipDistance->text().toDouble();
|
||
params.growParam.zDeviation_max = ui->editZDeviationMax->text().toDouble();
|
||
params.growParam.minLTypeTreeLen = ui->editMinLTypeTreeLen->text().toDouble();
|
||
params.growParam.minVTypeTreeLen = ui->editMinVTypeTreeLen->text().toDouble();
|
||
|
||
m_presenter->SetAlgoParams(params);
|
||
|
||
// 保存手眼标定矩阵 + 网络配置到配置文件(统一获取一次配置,避免互相覆盖)
|
||
if (m_presenter->GetConfigManager()) {
|
||
ConfigManager* configManager = m_presenter->GetConfigManager();
|
||
SystemConfig systemConfig = configManager->GetConfig();
|
||
NetworkConfigData netConfig;
|
||
bool hasNetworkConfig = false;
|
||
|
||
if (m_networkConfigWidget) {
|
||
netConfig = m_networkConfigWidget->getConfig();
|
||
hasNetworkConfig = true;
|
||
systemConfig.configResult.eulerOrder = netConfig.eulerOrder;
|
||
systemConfig.configResult.dirVectorInvert = netConfig.dirVectorInvert;
|
||
systemConfig.configResult.byteOrder = netConfig.byteOrder;
|
||
systemConfig.configResult.longAxisDir = netConfig.longAxisDir;
|
||
}
|
||
if (hasNetworkConfig) {
|
||
for (auto& calibMatrix : systemConfig.configResult.handEyeCalibMatrixList) {
|
||
calibMatrix.eulerOrder = netConfig.eulerOrder;
|
||
}
|
||
}
|
||
|
||
// 保存手眼标定矩阵
|
||
if (m_handEyeCalibWidget) {
|
||
const auto& oldMatrixList = systemConfig.configResult.handEyeCalibMatrixList;
|
||
std::vector<VrHandEyeCalibMatrix> newMatrixList;
|
||
const auto& cameraList = m_presenter->GetCameraList();
|
||
int cameraCount = std::max(1, static_cast<int>(cameraList.size()));
|
||
|
||
for (int i = 0; i < cameraCount; ++i) {
|
||
int camIdx = i + 1;
|
||
|
||
// 先从已有配置中获取该相机的矩阵作为基础
|
||
VrHandEyeCalibMatrix calibMatrix;
|
||
calibMatrix.cameraIndex = camIdx;
|
||
calibMatrix.eulerOrder = systemConfig.configResult.eulerOrder;
|
||
for (const auto& old : oldMatrixList) {
|
||
if (old.cameraIndex == camIdx) {
|
||
calibMatrix = old;
|
||
break;
|
||
}
|
||
}
|
||
calibMatrix.eulerOrder = systemConfig.configResult.eulerOrder;
|
||
|
||
// 如果控件中有更新的数据则覆盖
|
||
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;
|
||
}
|
||
|
||
// 保存网络配置
|
||
if (m_networkConfigWidget) {
|
||
NetworkConfigData netConfig = m_networkConfigWidget->getConfig();
|
||
systemConfig.configResult.eulerOrder = netConfig.eulerOrder;
|
||
systemConfig.configResult.dirVectorInvert = netConfig.dirVectorInvert;
|
||
systemConfig.configResult.byteOrder = netConfig.byteOrder;
|
||
}
|
||
|
||
// 统一更新并保存到文件
|
||
configManager->UpdateFullConfig(systemConfig);
|
||
QString configPath = PathManager::GetInstance().GetConfigFilePath();
|
||
configManager->SaveConfigToFile(configPath.toStdString());
|
||
|
||
// 通知 Presenter 重新加载手眼标定矩阵等参数
|
||
m_presenter->OnConfigChanged(systemConfig.configResult);
|
||
}
|
||
}
|
||
|
||
void DialogAlgoArg::resetParams()
|
||
{
|
||
ui->editRodDiameter->setText(QString::number(16.0, 'f', 1));
|
||
ui->editRodLen->setText(QString::number(50.0, 'f', 1));
|
||
ui->editWeldSeanRange->setText(QString::number(100.0, 'f', 1));
|
||
|
||
ui->editCornerTh->setText(QString::number(60.0, 'f', 1));
|
||
ui->editScale->setText(QString::number(4.0, 'f', 1));
|
||
ui->editMinEndingGap->setText(QString::number(20.0, 'f', 1));
|
||
ui->editMinEndingGapZ->setText(QString::number(5.0, 'f', 1));
|
||
ui->editJumpCornerTh1->setText(QString::number(15.0, 'f', 1));
|
||
ui->editJumpCornerTh2->setText(QString::number(60.0, 'f', 1));
|
||
|
||
ui->editContinuityTh->setText(QString::number(4.0, 'f', 1));
|
||
ui->editOutlierTh->setText(QString::number(4.0, 'f', 1));
|
||
|
||
ui->editMaxLineSkipNum->setText(QString::number(5));
|
||
ui->editYDeviationMax->setText(QString::number(5.0, 'f', 1));
|
||
ui->editMaxSkipDistance->setText(QString::number(20.0, 'f', 1));
|
||
ui->editZDeviationMax->setText(QString::number(3.0, 'f', 1));
|
||
ui->editMinLTypeTreeLen->setText(QString::number(50.0, 'f', 1));
|
||
ui->editMinVTypeTreeLen->setText(QString::number(50.0, 'f', 1));
|
||
}
|
||
|
||
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<HandEyeCalibCameraInfo> 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<int>(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::InitNetworkConfigTab()
|
||
{
|
||
if (!ui || !m_presenter) return;
|
||
|
||
// 创建网络配置控件:不显示PLC配置,不显示TCP配置
|
||
m_networkConfigWidget = new NetworkConfigWidget(false, false, this);
|
||
ui->verticalLayout_networkConfigHost->addWidget(m_networkConfigWidget);
|
||
|
||
// 加载当前配置
|
||
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;
|
||
if (!configResult.handEyeCalibMatrixList.empty()) {
|
||
netConfig.eulerOrder = configResult.handEyeCalibMatrixList[0].eulerOrder;
|
||
}
|
||
netConfig.dirVectorInvert = configResult.dirVectorInvert;
|
||
netConfig.byteOrder = configResult.byteOrder;
|
||
netConfig.longAxisDir = configResult.longAxisDir;
|
||
|
||
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();
|
||
systemConfig.configResult.eulerOrder = netConfig.eulerOrder;
|
||
systemConfig.configResult.dirVectorInvert = netConfig.dirVectorInvert;
|
||
systemConfig.configResult.byteOrder = netConfig.byteOrder;
|
||
systemConfig.configResult.longAxisDir = netConfig.longAxisDir;
|
||
for (auto& calibMatrix : systemConfig.configResult.handEyeCalibMatrixList) {
|
||
calibMatrix.eulerOrder = netConfig.eulerOrder;
|
||
}
|
||
|
||
// 更新并保存
|
||
configManager->UpdateFullConfig(systemConfig);
|
||
|
||
QString configPath = PathManager::GetInstance().GetConfigFilePath();
|
||
configManager->SaveConfigToFile(configPath.toStdString());
|
||
}
|