#include "dialogalgoarg.h" #include "ui_dialogalgoarg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ParkingSpaceGuidePresenter.h" #include "PathManager.h" #include "StyledMessageBox.h" class TouchTabNavigator final : public QWidget { public: explicit TouchTabNavigator(QWidget* parent = nullptr) : QWidget(parent) { auto* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(10); layout->setAlignment(Qt::AlignVCenter); m_prevButton = CreateNavButton(QStringLiteral("上一页")); m_nextButton = CreateNavButton(QStringLiteral("下一页")); connect(m_prevButton, &QPushButton::clicked, this, [this]() { StepTab(-1); }); connect(m_nextButton, &QPushButton::clicked, this, [this]() { StepTab(1); }); m_strip = new QScrollArea(this); m_strip->setWidgetResizable(false); m_strip->setFixedHeight(kButtonHeight); m_strip->setFrameShape(QFrame::NoFrame); m_strip->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_strip->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_strip->setStyleSheet(QStringLiteral( "QScrollArea { background: transparent; border: none; }")); m_stripInner = new QWidget; m_stripInner->setStyleSheet(QStringLiteral("background: transparent;")); m_stripLayout = new QHBoxLayout(m_stripInner); m_stripLayout->setContentsMargins(0, 0, 0, 0); m_stripLayout->setSpacing(8); m_stripLayout->setSizeConstraint(QLayout::SetFixedSize); m_strip->setWidget(m_stripInner); m_strip->viewport()->installEventFilter(this); if (m_prevButton) { m_prevButton->setAutoRepeat(true); m_prevButton->setAutoRepeatDelay(400); m_prevButton->setAutoRepeatInterval(180); } if (m_nextButton) { m_nextButton->setAutoRepeat(true); m_nextButton->setAutoRepeatDelay(400); m_nextButton->setAutoRepeatInterval(180); } layout->addWidget(m_prevButton); layout->addWidget(m_strip, 1); layout->addWidget(m_nextButton); ApplyTouchFont(); } void Attach(QTabWidget* tabs) { m_tabs = tabs; if (!m_tabs) { return; } if (QTabBar* bar = m_tabs->tabBar()) { bar->hide(); bar->setMaximumHeight(0); } m_tabs->setDocumentMode(true); m_tabs->setStyleSheet(m_tabs->styleSheet() + QStringLiteral( " QTabWidget::tab-bar { height: 0px; width: 0px; }" " QTabWidget::pane { top: 0px; }")); connect(m_tabs, &QTabWidget::currentChanged, this, [this](int) { SyncCurrent(); }); Rebuild(); } void Rebuild() { while (QLayoutItem* item = m_stripLayout->takeAt(0)) { if (item->widget()) { delete item->widget(); } delete item; } m_tabButtons.clear(); if (!m_tabs) { UpdateNavEnabled(); return; } // 原生 QTabBar 在 clear/addTab 后可能再次露出,保持隐藏。 if (QTabBar* bar = m_tabs->tabBar()) { bar->hide(); bar->setMaximumHeight(0); } const int count = m_tabs->count(); for (int i = 0; i < count; ++i) { auto* button = new QPushButton(m_tabs->tabText(i), m_stripInner); button->setCheckable(true); button->setMinimumWidth(140); button->setFixedHeight(kButtonHeight); button->setFocusPolicy(Qt::NoFocus); button->setCursor(Qt::PointingHandCursor); button->setStyleSheet(TabButtonStyle()); button->installEventFilter(this); connect(button, &QPushButton::clicked, this, [this, i]() { if (m_tabs) { m_tabs->setCurrentIndex(i); } }); m_stripLayout->addWidget(button); m_tabButtons.append(button); } ApplyTouchFont(); m_stripInner->adjustSize(); SyncCurrent(); } void ApplyTouchFont() { QFont navFont; navFont.setPointSize(16); navFont.setBold(true); if (m_prevButton) { m_prevButton->setFont(navFont); } if (m_nextButton) { m_nextButton->setFont(navFont); } QFont tabFont; tabFont.setPointSize(16); for (QPushButton* button : m_tabButtons) { if (button) { button->setFont(tabFont); } } } protected: bool eventFilter(QObject* watched, QEvent* event) override { const bool onStrip = watched == m_strip->viewport() || qobject_cast(watched) != nullptr; if (!onStrip) { return QWidget::eventFilter(watched, event); } switch (event->type()) { case QEvent::MouseButtonPress: return HandleMousePress(static_cast(event)); case QEvent::MouseMove: return HandleMouseMove(static_cast(event)); case QEvent::MouseButtonRelease: return HandleMouseRelease(watched, static_cast(event)); default: break; } return QWidget::eventFilter(watched, event); } private: static QString NavButtonStyle() { return QStringLiteral( "QPushButton { background-color: rgb(55, 92, 132); color: rgb(239, 241, 245);" " border: none; border-radius: 8px; padding: 8px 12px; }" "QPushButton:pressed { background-color: rgb(80, 140, 200); }" "QPushButton:disabled { background-color: rgb(47, 48, 52); color: rgb(110, 112, 118); }"); } static QString TabButtonStyle() { return QStringLiteral( "QPushButton { background-color: rgb(47, 48, 52); color: rgb(221, 225, 233);" " border: 1px solid rgb(70, 72, 78); border-radius: 8px; padding: 8px 16px; }" "QPushButton:checked { background-color: rgb(70, 72, 78);" " border: 2px solid rgb(100, 150, 200); color: rgb(255, 255, 255); }" "QPushButton:pressed { background-color: rgb(60, 90, 130); }"); } QPushButton* CreateNavButton(const QString& text) { auto* button = new QPushButton(text, this); button->setFixedSize(108, kButtonHeight); button->setFocusPolicy(Qt::NoFocus); button->setCursor(Qt::PointingHandCursor); button->setStyleSheet(NavButtonStyle()); return button; } void StepTab(int delta) { if (!m_tabs) { return; } const int nextIndex = m_tabs->currentIndex() + delta; if (nextIndex < 0 || nextIndex >= m_tabs->count()) { return; } m_tabs->setCurrentIndex(nextIndex); } void SyncCurrent() { if (!m_tabs) { UpdateNavEnabled(); return; } const int current = m_tabs->currentIndex(); for (int i = 0; i < m_tabButtons.size(); ++i) { QPushButton* button = m_tabButtons[i]; if (!button) { continue; } const QSignalBlocker blocker(button); button->setChecked(i == current); } if (current >= 0 && current < m_tabButtons.size() && m_tabButtons[current]) { m_strip->ensureWidgetVisible(m_tabButtons[current], 48, 0); } UpdateNavEnabled(); } void UpdateNavEnabled() { const int current = m_tabs ? m_tabs->currentIndex() : -1; const int count = m_tabs ? m_tabs->count() : 0; if (m_prevButton) { m_prevButton->setEnabled(current > 0); } if (m_nextButton) { m_nextButton->setEnabled(current >= 0 && current < count - 1); } } bool HandleMousePress(QMouseEvent* event) { if (event->button() != Qt::LeftButton) { return false; } m_pressPos = event->globalPos(); m_lastPos = event->globalPos(); m_swiping = false; m_pressed = true; return false; } bool HandleMouseMove(QMouseEvent* event) { if (!m_pressed || !(event->buttons() & Qt::LeftButton) || !m_strip) { return false; } const int totalDx = event->globalPos().x() - m_pressPos.x(); if (!m_swiping && qAbs(totalDx) >= 16) { m_swiping = true; } if (!m_swiping) { return false; } QScrollBar* bar = m_strip->horizontalScrollBar(); if (bar) { bar->setValue(bar->value() - (event->globalPos().x() - m_lastPos.x())); } m_lastPos = event->globalPos(); return true; } bool HandleMouseRelease(QObject* watched, QMouseEvent* event) { if (event->button() != Qt::LeftButton || !m_pressed) { return false; } const bool wasSwiping = m_swiping; m_pressed = false; m_swiping = false; if (wasSwiping) { if (auto* button = qobject_cast(watched)) { button->setDown(false); } return true; } return false; } static const int kButtonHeight = 64; QTabWidget* m_tabs = nullptr; QPushButton* m_prevButton = nullptr; QPushButton* m_nextButton = nullptr; QScrollArea* m_strip = nullptr; QWidget* m_stripInner = nullptr; QHBoxLayout* m_stripLayout = nullptr; QList m_tabButtons; QPoint m_pressPos; QPoint m_lastPos; bool m_pressed = false; bool m_swiping = false; }; class RoiPreviewWidget final : public QWidget { public: explicit RoiPreviewWidget(QWidget* parent = nullptr) : QWidget(parent) { setMinimumSize(420, 360); } void SetImage(const QImage& image) { m_image = image; update(); } void SetRoi(const QRectF& roi, const QString& label) { m_roi = roi; m_label = label; update(); } void SetStatus(const QString& status) { m_status = status; update(); } protected: void paintEvent(QPaintEvent*) override { QPainter painter(this); painter.fillRect(rect(), QColor(20, 22, 25)); painter.setPen(QColor(221, 225, 233)); const QRect content = rect().adjusted(12, 36, -12, -12); painter.drawText(QRect(12, 8, width() - 24, 22), Qt::AlignLeft | Qt::AlignVCenter, m_label.isEmpty() ? QStringLiteral("实时图像") : m_label); if (m_image.isNull()) { painter.drawText(content, Qt::AlignCenter, m_status.isEmpty() ? QStringLiteral("等待相机图像") : m_status); return; } QSize targetSize = m_image.size(); targetSize.scale(content.size(), Qt::KeepAspectRatio); const QRect imageRect( content.center().x() - targetSize.width() / 2, content.center().y() - targetSize.height() / 2, targetSize.width(), targetSize.height()); painter.drawImage(imageRect, m_image); const QRectF normalizedRoi( std::clamp(m_roi.x(), 0.0, 1.0), std::clamp(m_roi.y(), 0.0, 1.0), std::clamp(m_roi.width(), 0.0, 1.0), std::clamp(m_roi.height(), 0.0, 1.0)); const QRectF roiRect( imageRect.x() + normalizedRoi.x() * imageRect.width(), imageRect.y() + normalizedRoi.y() * imageRect.height(), normalizedRoi.width() * imageRect.width(), normalizedRoi.height() * imageRect.height()); painter.setPen(QPen(QColor(255, 205, 65), 3)); painter.drawRect(roiRect); } private: QImage m_image; QRectF m_roi; QString m_label; QString m_status; }; DialogAlgoArg::DialogAlgoArg(QWidget* parent) : QDialog(parent) , ui(new Ui::DialogAlgoArg) { ui->setupUi(this); setWindowTitle(QStringLiteral("停机引导参数设置")); if (ui->label_title) { ui->label_title->setText(QStringLiteral("停机引导参数设置")); } setMinimumSize(1260, 760); resize(1260, 760); m_tabNavigator = new TouchTabNavigator(this); m_tabNavigator->setGeometry(40, 80, 1180, 64); m_tabNavigator->Attach(ui->tabWidget); ui->tabWidget->setGeometry(40, 156, 690, 524); ui->btnReset->setGeometry(40, 695, 120, 45); ui->btnApply->setGeometry(390, 695, 100, 45); ui->btnOK->setGeometry(510, 695, 100, 45); ui->btnCancel->setGeometry(630, 695, 100, 45); m_roiPreview = new RoiPreviewWidget(this); m_roiPreview->setGeometry(760, 156, 460, 524); m_roiPreview->hide(); m_previewTimer = new QTimer(this); m_previewTimer->setInterval(250); connect(m_previewTimer, &QTimer::timeout, this, &DialogAlgoArg::RefreshPreview); BuildUi(); connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this](int index) { if (index >= 0 && index < m_visiblePages.size()) { UpdateTitle(m_visiblePages[index]); } UpdatePreviewVisibility(); }); connect(this, &QDialog::finished, this, [this]() { m_previewTimer->stop(); }); ApplyUiFont(); if (m_tabNavigator) { m_tabNavigator->ApplyTouchFont(); } } DialogAlgoArg::~DialogAlgoArg() { delete ui; } void DialogAlgoArg::SetPresenter(ParkingSpaceGuidePresenter* presenter) { m_presenter = presenter; LoadParams(); } void DialogAlgoArg::SetCurrentPage(ConfigPage page) { if (ui && ui->tabWidget) { ShowTabGroup(page); } } void DialogAlgoArg::ShowTabGroup(ConfigPage page) { if (!ui || !ui->tabWidget) { return; } const bool oldBlocked = ui->tabWidget->blockSignals(true); ui->tabWidget->clear(); HideDetachedTabs(); m_visiblePages.clear(); auto addTab = [this](QWidget* tab, const QString& title, ConfigPage tabPage) { if (tab) { ui->tabWidget->addTab(tab, title); m_visiblePages.push_back(tabPage); } }; int selectedIndex = 0; if (page == ConfigPage::Camera || page == ConfigPage::Lidar) { addTab(m_cameraTab, QStringLiteral("相机参数"), ConfigPage::Camera); addTab(m_lidarTab, QStringLiteral("雷达参数"), ConfigPage::Lidar); selectedIndex = page == ConfigPage::Lidar ? 1 : 0; } else if (page == ConfigPage::Calibration) { addTab(m_groundCalibrationTab, QStringLiteral("地面调平"), ConfigPage::Calibration); } else if (page == ConfigPage::Multicast) { addTab(m_multicastTab, QStringLiteral("组播参数"), ConfigPage::Multicast); } else { addTab(m_siteIdentityTab, QStringLiteral("站点信息"), ConfigPage::Detection); addTab(m_planeParkingTab, QStringLiteral("停机几何"), ConfigPage::Detection); addTab(m_groundCalibrationTab, QStringLiteral("地面调平"), ConfigPage::Detection); addTab(m_treeGrowTab, QStringLiteral("聚类生长"), ConfigPage::Detection); addTab(m_guideDecisionTab, QStringLiteral("引导判定"), ConfigPage::Detection); addTab(m_processTab, QStringLiteral("流程判定"), ConfigPage::Detection); addTab(m_modelRecognitionTab, QStringLiteral("机型识别"), ConfigPage::Detection); addTab(m_personDetectionTab, QStringLiteral("人员检测"), ConfigPage::Detection); addTab(m_autoExposureTab, QStringLiteral("自动曝光"), ConfigPage::Detection); addTab(m_multicastTab, QStringLiteral("组播参数"), ConfigPage::Detection); } if (selectedIndex >= 0 && selectedIndex < ui->tabWidget->count()) { ui->tabWidget->setCurrentIndex(selectedIndex); } if (ui->tabWidget->currentWidget()) { ui->tabWidget->currentWidget()->show(); } ui->tabWidget->blockSignals(oldBlocked); if (m_tabNavigator) { m_tabNavigator->Rebuild(); } UpdateTitle(page); UpdatePreviewVisibility(); } void DialogAlgoArg::UpdateTitle(ConfigPage page) { QString title = QStringLiteral("停机引导参数设置"); switch (page) { case ConfigPage::Detection: title = QStringLiteral("检测参数设置"); break; case ConfigPage::Camera: title = QStringLiteral("相机参数设置"); break; case ConfigPage::Lidar: title = QStringLiteral("雷达参数设置"); break; case ConfigPage::Multicast: title = QStringLiteral("组播参数设置"); break; case ConfigPage::Calibration: title = QStringLiteral("雷达地面调平参数"); break; } setWindowTitle(title); if (ui && ui->label_title) { ui->label_title->setText(title); } } void DialogAlgoArg::HideDetachedTabs() { const QList tabs = { m_planeParkingTab, m_groundCalibrationTab, m_treeGrowTab, m_guideDecisionTab, m_processTab, m_modelRecognitionTab, m_personDetectionTab, m_autoExposureTab, m_siteIdentityTab, m_cameraTab, m_lidarTab, m_multicastTab }; for (QWidget* tab : tabs) { if (tab) { tab->hide(); } } } void DialogAlgoArg::OnPreviewFrame(const QImage& image) { if (image.isNull()) { return; } if (m_roiPreview) { m_roiPreview->SetImage(image); } } void DialogAlgoArg::UpdatePreviewVisibility() { if (!m_roiPreview || !m_previewTimer || !ui || !ui->tabWidget) { return; } const QWidget* currentTab = ui->tabWidget->currentWidget(); const bool showPreview = currentTab == m_modelRecognitionTab || currentTab == m_personDetectionTab || currentTab == m_autoExposureTab; m_roiPreview->setVisible(showPreview); if (showPreview) { UpdateRoiPreview(); RefreshPreview(); m_previewTimer->start(); } else { m_previewTimer->stop(); } } void DialogAlgoArg::UpdateRoiPreview() { if (!m_roiPreview || !ui || !ui->tabWidget) { return; } const QWidget* currentTab = ui->tabWidget->currentWidget(); const bool modelPreview = currentTab == m_modelRecognitionTab; const bool personPreview = currentTab == m_personDetectionTab; const bool exposurePreview = currentTab == m_autoExposureTab; if (!modelPreview && !personPreview && !exposurePreview) { return; } const auto value = [](QLineEdit* edit) { bool ok = false; const double result = edit ? edit->text().trimmed().toDouble(&ok) : 0.0; return ok && std::isfinite(result) ? result : 0.0; }; QRectF roi; QString label; if (modelPreview) { roi = QRectF(value(m_modelRoiX), value(m_modelRoiY), value(m_modelRoiWidth), value(m_modelRoiHeight)); label = QStringLiteral("机型识别实时图像"); } else if (personPreview) { roi = QRectF(value(m_personRoiX), value(m_personRoiY), value(m_personRoiWidth), value(m_personRoiHeight)); label = QStringLiteral("人员检测实时图像"); } else { roi = QRectF(value(m_exposureRoiX), value(m_exposureRoiY), value(m_exposureRoiWidth), value(m_exposureRoiHeight)); label = QStringLiteral("自动曝光实时图像"); } m_roiPreview->SetRoi(roi, label); } void DialogAlgoArg::RefreshPreview() { if (!m_presenter || !m_roiPreview || !m_roiPreview->isVisible()) { return; } QImage image; QString errorMessage; if (m_presenter->CapturePreviewImage(image, errorMessage) && !image.isNull()) { m_roiPreview->SetStatus(QString()); OnPreviewFrame(image); } else { m_roiPreview->SetStatus(errorMessage.trimmed().isEmpty() ? QStringLiteral("相机图像不可用") : errorMessage.trimmed()); } } void DialogAlgoArg::CalculateGroundCalibration() { if (!m_presenter) { StyledMessageBox::warning(this, QStringLiteral("失败"), QStringLiteral("系统未初始化")); return; } VrPlaneGroundCalibrationParam calibration; QString errorMessage; if (!m_presenter->CalibrateGround(calibration, errorMessage)) { StyledMessageBox::warning( this, QStringLiteral("地面调平失败"), errorMessage.trimmed().isEmpty() ? QStringLiteral("地面调平算法计算失败") : errorMessage.trimmed()); return; } SetMatrix(m_planeCalib, calibration.planeCalib); SetDouble(m_planeHeight, calibration.planeHeight); SetMatrix(m_invRMatrix, calibration.invRMatrix); StyledMessageBox::information(this, QStringLiteral("地面调平"), QStringLiteral("算法计算完成,请确认后应用或保存参数")); } void DialogAlgoArg::BuildUi() { ui->tabWidget->clear(); auto makeTab = [this](QWidget** tabWidget, const QString& title) -> QWidget* { auto* scroll = new QScrollArea(ui->tabWidget); scroll->setWidgetResizable(true); auto* page = new QWidget(scroll); page->setObjectName(title); auto* layout = new QFormLayout(page); layout->setContentsMargins(24, 24, 24, 24); layout->setSpacing(14); scroll->setWidget(page); *tabWidget = scroll; scroll->hide(); return page; }; QWidget* siteIdentity = makeTab(&m_siteIdentityTab, QStringLiteral("站点信息")); m_udpTargetId = AddTextEditor(siteIdentity, QStringLiteral("目标编号"), 0); m_udpParkId = AddTextEditor(siteIdentity, QStringLiteral("停机位"), 1); QWidget* planeParking = makeTab(&m_planeParkingTab, QStringLiteral("停机几何")); m_parkingPointX = AddDoubleEditor(planeParking, QStringLiteral("停机点X(毫米)"), 0, -1000000.0, 1000000.0); m_parkingPointY = AddDoubleEditor(planeParking, QStringLiteral("停机点Y(毫米)"), 1, -1000000.0, 1000000.0); m_parkingPointZ = AddDoubleEditor(planeParking, QStringLiteral("停机点Z(毫米)"), 2, -1000000.0, 1000000.0); m_guideLinePointX = AddDoubleEditor(planeParking, QStringLiteral("引导线远点X(毫米)"), 3, -1000000.0, 1000000.0); m_guideLinePointY = AddDoubleEditor(planeParking, QStringLiteral("引导线远点Y(毫米)"), 4, -1000000.0, 1000000.0); m_guideLinePointZ = AddDoubleEditor(planeParking, QStringLiteral("引导线远点Z(毫米)"), 5, -1000000.0, 1000000.0); m_guidingRange = AddDoubleEditor(planeParking, QStringLiteral("飞机引导范围(毫米)"), 6, 0.0, 10000000.0); m_parkingRange = AddDoubleEditor(planeParking, QStringLiteral("引导线过滤范围(毫米)"), 7, 0.0, 10000000.0); m_distFromNoseToWheel = AddDoubleEditor(planeParking, QStringLiteral("机鼻到前轮距离(毫米)"), 8, 0.0, 100000.0); QWidget* ground = makeTab(&m_groundCalibrationTab, QStringLiteral("地面调平")); for (int i = 0; i < 9; ++i) { m_planeCalib[i] = AddDoubleEditor(ground, QStringLiteral("调平矩阵 R%1%2").arg(i / 3).arg(i % 3), i, -1000.0, 1000.0); } m_planeHeight = AddDoubleEditor(ground, QStringLiteral("地面高度(毫米)"), 9, -1000000.0, 1000000.0); for (int i = 0; i < 9; ++i) { m_invRMatrix[i] = AddDoubleEditor(ground, QStringLiteral("逆矩阵 R%1%2").arg(i / 3).arg(i % 3), 10 + i, -1000.0, 1000.0); } m_calibrateGroundButton = new QPushButton(QStringLiteral("算法计算地面调平"), ground); static_cast(ground->layout())->addRow(QString(), m_calibrateGroundButton); connect(m_calibrateGroundButton, &QPushButton::clicked, this, &DialogAlgoArg::CalculateGroundCalibration); QWidget* treeGrow = makeTab(&m_treeGrowTab, QStringLiteral("聚类生长")); m_yDeviationMax = AddDoubleEditor(treeGrow, QStringLiteral("Y方向最大偏差(毫米)"), 0, 0.0, 1000000.0); m_zDeviationMax = AddDoubleEditor(treeGrow, QStringLiteral("Z方向最大偏差(毫米)"), 1, 0.0, 1000000.0); m_maxLineSkipNum = AddIntEditor(treeGrow, QStringLiteral("最大跳线数(-1按距离)"), 2, -1, 1000000); m_maxSkipDistance = AddDoubleEditor(treeGrow, QStringLiteral("最大跳过距离(毫米,-1禁用)"), 3, -1.0, 1000000.0); m_minLTypeTreeLen = AddDoubleEditor(treeGrow, QStringLiteral("L型树最小长度(毫米)"), 4, 0.0, 1000000.0); m_minVTypeTreeLen = AddDoubleEditor(treeGrow, QStringLiteral("V型树最小长度(毫米)"), 5, 0.0, 1000000.0); QWidget* guideDecision = makeTab(&m_guideDecisionTab, QStringLiteral("引导判定")); m_lateralTolerance = AddDoubleEditor(guideDecision, QStringLiteral("横向对中容差(毫米)"), 0, 0.0, 100000.0); m_angleTolerance = AddDoubleEditor(guideDecision, QStringLiteral("航向角容差(度)"), 1, 0.0, 180.0); QWidget* process = makeTab(&m_processTab, QStringLiteral("流程判定")); m_dockingStartDistance = AddDoubleEditor(process, QStringLiteral("引导启动距离(毫米)"), 0, 0.0, 1000000.0); m_captureStartDistance = AddDoubleEditor(process, QStringLiteral("目标捕获距离(毫米)"), 1, 0.0, 1000000.0); m_approachStartDistance = AddDoubleEditor(process, QStringLiteral("对中/方位引导距离(毫米)"), 2, 0.0, 1000000.0); m_slowDistance = AddDoubleEditor(process, QStringLiteral("减速触发距离(毫米)"), 3, 0.0, 1000000.0); m_stopDistanceTolerance = AddDoubleEditor(process, QStringLiteral("到位距离容差(毫米)"), 4, 0.0, 100000.0); m_overshootDistance = AddDoubleEditor(process, QStringLiteral("越过停止线距离(毫米)"), 5, 0.0, 1000000.0); m_stoppedShortMinDistance = AddDoubleEditor(process, QStringLiteral("提前停止最小距离(毫米)"), 6, 0.0, 1000000.0); m_maxApproachSpeed = AddDoubleEditor(process, QStringLiteral("最大接近速度(毫米/秒)"), 7, 0.0, 100000.0); m_stoppedSpeedThreshold = AddDoubleEditor(process, QStringLiteral("静止速度阈值(毫米/秒)"), 8, 0.0, 100000.0); m_speedFilterAlpha = AddDoubleEditor(process, QStringLiteral("速度滤波系数"), 9, 0.0, 1.0); m_distanceChangeThreshold = AddDoubleEditor(process, QStringLiteral("距离变化阈值(毫米)"), 10, 0.0, 1000000.0); m_lateralOffsetChangeThreshold = AddDoubleEditor(process, QStringLiteral("横向偏移变化阈值(毫米)"), 11, 0.0, 1000000.0); m_stopStableFrames = AddIntEditor(process, QStringLiteral("到位稳定帧数"), 12, 1, 1000000); m_stoppedShortStableFrames = AddIntEditor(process, QStringLiteral("提前停止稳定帧数"), 13, 1, 1000000); m_errorFrameThreshold = AddIntEditor(process, QStringLiteral("连续错误帧阈值"), 14, 1, 1000000); m_lostFrameThreshold = AddIntEditor(process, QStringLiteral("目标丢失帧阈值"), 15, 1, 1000000); m_completedHoldFrames = AddIntEditor(process, QStringLiteral("完成状态保持帧数"), 16, 1, 1000000); QWidget* model = makeTab(&m_modelRecognitionTab, QStringLiteral("机型识别")); m_modelVerifyDistance = AddDoubleEditor(model, QStringLiteral("机型验证距离(毫米)"), 0, -1000000.0, 1000000.0); m_modelRoiX = AddDoubleEditor(model, QStringLiteral("飞机检测区域 X (0~1)"), 1, 0.0, 1.0); m_modelRoiY = AddDoubleEditor(model, QStringLiteral("飞机检测区域 Y (0~1)"), 2, 0.0, 1.0); m_modelRoiWidth = AddDoubleEditor(model, QStringLiteral("飞机检测区域宽度 (0~1)"), 3, 0.000001, 1.0); m_modelRoiHeight = AddDoubleEditor(model, QStringLiteral("飞机检测区域高度 (0~1)"), 4, 0.000001, 1.0); m_confidenceThreshold = AddDoubleEditor(model, QStringLiteral("识别置信度阈值"), 5, 0.0, 1.0); m_maxRecognitionAttempts = AddIntEditor(model, QStringLiteral("最大识别次数"), 6, 1, 1000); QWidget* person = makeTab(&m_personDetectionTab, QStringLiteral("人员检测")); m_personDetectionEnabled = AddCheckBox(person, QStringLiteral("启用停稳后人员检测"), 0); m_personRoiX = AddDoubleEditor(person, QStringLiteral("轮挡区域 X (0~1)"), 1, 0.0, 1.0); m_personRoiY = AddDoubleEditor(person, QStringLiteral("轮挡区域 Y (0~1)"), 2, 0.0, 1.0); m_personRoiWidth = AddDoubleEditor(person, QStringLiteral("轮挡区域宽度 (0~1)"), 3, 0.000001, 1.0); m_personRoiHeight = AddDoubleEditor(person, QStringLiteral("轮挡区域高度 (0~1)"), 4, 0.000001, 1.0); m_personConfidenceThreshold = AddDoubleEditor(person, QStringLiteral("人员置信度阈值"), 5, 0.0, 1.0); m_personStableFrames = AddIntEditor(person, QStringLiteral("连续有效检测次数"), 6, 1, 1000); m_personDetectionIntervalMs = AddIntEditor(person, QStringLiteral("检测周期(毫秒)"), 7, 10, 60000); QWidget* autoExposure = makeTab(&m_autoExposureTab, QStringLiteral("自动曝光")); m_autoExposureEnabled = AddCheckBox(autoExposure, QStringLiteral("启用自动曝光"), 0); m_exposureRoiX = AddDoubleEditor(autoExposure, QStringLiteral("曝光区域 X (0~1)"), 1, 0.0, 1.0); m_exposureRoiY = AddDoubleEditor(autoExposure, QStringLiteral("曝光区域 Y (0~1)"), 2, 0.0, 1.0); m_exposureRoiWidth = AddDoubleEditor(autoExposure, QStringLiteral("曝光区域宽度 (0~1)"), 3, 0.000001, 1.0); m_exposureRoiHeight = AddDoubleEditor(autoExposure, QStringLiteral("曝光区域高度 (0~1)"), 4, 0.000001, 1.0); m_exposureReferenceGray = AddDoubleEditor(autoExposure, QStringLiteral("参考灰度"), 5, 0.0, 255.0); m_exposureGrayTolerance = AddDoubleEditor(autoExposure, QStringLiteral("灰度容差"), 6, 0.000001, 255.0); m_autoExposureIntervalMinutes = AddIntEditor(autoExposure, QStringLiteral("曝光调整间隔(分钟)"), 7, 1, 1440); const QList roiEditors = { m_modelRoiX, m_modelRoiY, m_modelRoiWidth, m_modelRoiHeight, m_personRoiX, m_personRoiY, m_personRoiWidth, m_personRoiHeight, m_exposureRoiX, m_exposureRoiY, m_exposureRoiWidth, m_exposureRoiHeight }; for (QLineEdit* editor : roiEditors) { connect(editor, &QLineEdit::textChanged, this, &DialogAlgoArg::UpdateRoiPreview); } QWidget* camera = makeTab(&m_cameraTab, QStringLiteral("相机参数")); m_mvsSerialNumber = AddTextEditor(camera, QStringLiteral("设备序列号"), 0); m_mvsIpAddress = AddTextEditor(camera, QStringLiteral("相机IP"), 1); m_mvsDeviceIndex = AddIntEditor(camera, QStringLiteral("设备序号"), 2, 0, 64); m_mvsEnabled = AddCheckBox(camera, QStringLiteral("启用"), 3); QWidget* lidar = makeTab(&m_lidarTab, QStringLiteral("雷达参数")); m_lidarType = AddTextEditor(lidar, QStringLiteral("雷达型号"), 0); m_lidarHost = AddTextEditor(lidar, QStringLiteral("监听地址"), 1); m_lidarDeviceIp = AddTextEditor(lidar, QStringLiteral("雷达IP"), 2); m_lidarMsopPort = AddIntEditor(lidar, QStringLiteral("数据端口"), 3, 1, 65535); m_lidarDifopPort = AddIntEditor(lidar, QStringLiteral("设备端口"), 4, 1, 65535); m_lidarMinDistance = AddDoubleEditor(lidar, QStringLiteral("最小距离(米)"), 5, 0.0, 1000.0); m_lidarMaxDistance = AddDoubleEditor(lidar, QStringLiteral("最大距离(米)"), 6, 0.0, 1000.0); m_lidarStartAngle = AddDoubleEditor(lidar, QStringLiteral("起始角度(度)"), 7, 0.0, 360.0); m_lidarEndAngle = AddDoubleEditor(lidar, QStringLiteral("结束角度(度)"), 8, 0.0, 360.0); QWidget* udp = makeTab(&m_multicastTab, QStringLiteral("组播参数")); m_udpAddress = AddTextEditor(udp, QStringLiteral("组播地址"), 0); m_udpPort = AddIntEditor(udp, QStringLiteral("组播端口"), 1, 1, 65535); m_udpEnabled = AddCheckBox(udp, QStringLiteral("启用"), 2); ShowTabGroup(ConfigPage::Detection); } void DialogAlgoArg::ApplyUiFont() { QFont font; font.setPointSize(16); setFont(font); const QList widgets = findChildren(); for (QWidget* widget : widgets) { widget->setFont(font); } } QLineEdit* DialogAlgoArg::AddDoubleEditor(QWidget* parent, const QString& label, int row, double min, double max) { Q_UNUSED(row); auto* edit = new QLineEdit(parent); auto* validator = new QDoubleValidator(min, max, 12, edit); validator->setNotation(QDoubleValidator::ScientificNotation); edit->setValidator(validator); static_cast(parent->layout())->addRow(label, edit); return edit; } QLineEdit* DialogAlgoArg::AddIntEditor(QWidget* parent, const QString& label, int row, int min, int max) { Q_UNUSED(row); auto* edit = new QLineEdit(parent); edit->setValidator(new QIntValidator(min, max, edit)); static_cast(parent->layout())->addRow(label, edit); return edit; } QLineEdit* DialogAlgoArg::AddTextEditor(QWidget* parent, const QString& label, int row, bool password) { Q_UNUSED(row); auto* edit = new QLineEdit(parent); if (password) { edit->setEchoMode(QLineEdit::Password); } static_cast(parent->layout())->addRow(label, edit); return edit; } QCheckBox* DialogAlgoArg::AddCheckBox(QWidget* parent, const QString& label, int row) { Q_UNUSED(row); auto* check = new QCheckBox(label, parent); check->setMinimumHeight(40); check->setStyleSheet( QStringLiteral( "QCheckBox { color: rgb(221, 225, 233); spacing: 10px; }" "QCheckBox::indicator { width: 28px; height: 28px;" " border: 2px solid rgb(160, 165, 175); border-radius: 4px;" " background-color: rgb(47, 48, 52); }" "QCheckBox::indicator:checked { background-color: rgb(80, 140, 200);" " border-color: rgb(140, 190, 230); }")); static_cast(parent->layout())->addRow(check); return check; } void DialogAlgoArg::LoadParams() { if (!m_presenter || !m_presenter->GetConfigManager()) { return; } const ConfigResult config = m_presenter->GetConfigManager()->GetConfigResult(); const VrAlgorithmParams& params = config.algorithmParams; const VrPlaneParkingParam& parking = params.planeParkingParam; SetDouble(m_parkingPointX, parking.parkingPointX); SetDouble(m_parkingPointY, parking.parkingPointY); SetDouble(m_parkingPointZ, parking.parkingPointZ); SetDouble(m_guideLinePointX, parking.guideLinePointX); SetDouble(m_guideLinePointY, parking.guideLinePointY); SetDouble(m_guideLinePointZ, parking.guideLinePointZ); SetDouble(m_guidingRange, parking.guidingRange); SetDouble(m_parkingRange, parking.parkingRange); SetDouble(m_distFromNoseToWheel, parking.distFromNoseToWheel); const VrPlaneGroundCalibrationParam& ground = params.groundCalibrationParam; SetMatrix(m_planeCalib, ground.planeCalib); SetDouble(m_planeHeight, ground.planeHeight); SetMatrix(m_invRMatrix, ground.invRMatrix); const VrPlaneTreeGrowParam& tree = params.treeGrowParam; SetDouble(m_yDeviationMax, tree.yDeviationMax); SetDouble(m_zDeviationMax, tree.zDeviationMax); SetInt(m_maxLineSkipNum, tree.maxLineSkipNum); SetDouble(m_maxSkipDistance, tree.maxSkipDistance); SetDouble(m_minLTypeTreeLen, tree.minLTypeTreeLen); SetDouble(m_minVTypeTreeLen, tree.minVTypeTreeLen); const VrGuideDecisionParam& guide = params.guideDecisionParam; SetDouble(m_lateralTolerance, guide.lateralTolerance); SetDouble(m_angleTolerance, guide.angleTolerance); const VrParkingProcessParam& process = params.processParam; SetDouble(m_dockingStartDistance, process.dockingStartDistance); SetDouble(m_captureStartDistance, process.captureStartDistance); SetDouble(m_approachStartDistance, process.approachStartDistance); SetDouble(m_slowDistance, process.slowDistance); SetDouble(m_stopDistanceTolerance, process.stopDistanceTolerance); SetDouble(m_overshootDistance, process.overshootDistance); SetDouble(m_stoppedShortMinDistance, process.stoppedShortMinDistance); SetDouble(m_maxApproachSpeed, process.maxApproachSpeed); SetDouble(m_stoppedSpeedThreshold, process.stoppedSpeedThreshold); SetDouble(m_speedFilterAlpha, process.speedFilterAlpha); SetDouble(m_distanceChangeThreshold, process.distanceChangeThreshold); SetDouble(m_lateralOffsetChangeThreshold, process.lateralOffsetChangeThreshold); SetInt(m_stopStableFrames, process.stopStableFrames); SetInt(m_stoppedShortStableFrames, process.stoppedShortStableFrames); SetInt(m_errorFrameThreshold, process.errorFrameThreshold); SetInt(m_lostFrameThreshold, process.lostFrameThreshold); SetInt(m_completedHoldFrames, process.completedHoldFrames); const VrModelRecognitionParam& model = params.modelRecognitionParam; SetDouble(m_modelVerifyDistance, model.modelVerifyDistance); SetDouble(m_modelRoiX, model.roiX); SetDouble(m_modelRoiY, model.roiY); SetDouble(m_modelRoiWidth, model.roiWidth); SetDouble(m_modelRoiHeight, model.roiHeight); SetDouble(m_confidenceThreshold, model.confidenceThreshold); SetInt(m_maxRecognitionAttempts, model.maxRecognitionAttempts); const VrPersonDetectionParam& person = params.personDetectionParam; m_personDetectionEnabled->setChecked(person.enabled); SetDouble(m_personRoiX, person.roiX); SetDouble(m_personRoiY, person.roiY); SetDouble(m_personRoiWidth, person.roiWidth); SetDouble(m_personRoiHeight, person.roiHeight); SetDouble(m_personConfidenceThreshold, person.confidenceThreshold); SetInt(m_personStableFrames, person.stableFrames); SetInt(m_personDetectionIntervalMs, person.detectionIntervalMs); m_autoExposureEnabled->setChecked(config.mvsCamera.autoExposureEnabled); SetDouble(m_exposureRoiX, config.mvsCamera.exposureRoiX); SetDouble(m_exposureRoiY, config.mvsCamera.exposureRoiY); SetDouble(m_exposureRoiWidth, config.mvsCamera.exposureRoiWidth); SetDouble(m_exposureRoiHeight, config.mvsCamera.exposureRoiHeight); SetDouble(m_exposureReferenceGray, config.mvsCamera.exposureReferenceGray); SetDouble(m_exposureGrayTolerance, config.mvsCamera.exposureGrayTolerance); SetInt(m_autoExposureIntervalMinutes, config.mvsCamera.autoExposureIntervalMinutes); m_mvsSerialNumber->setText(QString::fromStdString(config.mvsCamera.serialNumber)); m_mvsIpAddress->setText(QString::fromStdString(config.mvsCamera.ipAddress)); SetInt(m_mvsDeviceIndex, config.mvsCamera.deviceIndex); m_mvsEnabled->setChecked(config.mvsCamera.enabled); m_lidarType->setText(QString::fromStdString(config.lidarConfig.lidarType)); m_lidarHost->setText(QString::fromStdString(config.lidarConfig.hostAddress)); m_lidarDeviceIp->setText(QString::fromStdString(config.lidarConfig.deviceIp)); SetInt(m_lidarMsopPort, config.lidarConfig.msopPort); SetInt(m_lidarDifopPort, config.lidarConfig.difopPort); SetDouble(m_lidarMinDistance, config.lidarConfig.minDistance); SetDouble(m_lidarMaxDistance, config.lidarConfig.maxDistance); SetDouble(m_lidarStartAngle, config.lidarConfig.startAngle); SetDouble(m_lidarEndAngle, config.lidarConfig.endAngle); m_udpAddress->setText(QString::fromStdString(config.udpBroadcastConfig.address)); SetInt(m_udpPort, config.udpBroadcastConfig.port); m_udpTargetId->setText(QString::fromStdString(config.udpBroadcastConfig.targetId)); m_udpParkId->setText(QString::fromStdString(config.udpBroadcastConfig.parkId)); m_udpEnabled->setChecked(config.udpBroadcastConfig.enabled); } bool DialogAlgoArg::SaveParams() { if (!m_presenter || !m_presenter->GetConfigManager()) { return false; } SystemConfig systemConfig = m_presenter->GetConfigManager()->GetConfig(); ConfigResult& config = systemConfig.configResult; VrAlgorithmParams& params = config.algorithmParams; VrPlaneParkingParam& parking = params.planeParkingParam; if (!GetDouble(m_parkingPointX, QStringLiteral("停机点X"), parking.parkingPointX)) return false; if (!GetDouble(m_parkingPointY, QStringLiteral("停机点Y"), parking.parkingPointY)) return false; if (!GetDouble(m_parkingPointZ, QStringLiteral("停机点Z"), parking.parkingPointZ)) return false; if (!GetDouble(m_guideLinePointX, QStringLiteral("引导线远点X"), parking.guideLinePointX)) return false; if (!GetDouble(m_guideLinePointY, QStringLiteral("引导线远点Y"), parking.guideLinePointY)) return false; if (!GetDouble(m_guideLinePointZ, QStringLiteral("引导线远点Z"), parking.guideLinePointZ)) return false; if (!GetDouble(m_guidingRange, QStringLiteral("飞机引导范围"), parking.guidingRange)) return false; if (!GetDouble(m_parkingRange, QStringLiteral("引导线过滤范围"), parking.parkingRange)) return false; if (!GetDouble(m_distFromNoseToWheel, QStringLiteral("机鼻到前轮距离"), parking.distFromNoseToWheel)) return false; const double dx = parking.guideLinePointX - parking.parkingPointX; const double dy = parking.guideLinePointY - parking.parkingPointY; const double dz = parking.guideLinePointZ - parking.parkingPointZ; if (parking.guidingRange <= 0.0 || parking.parkingRange <= 0.0 || std::sqrt(dx * dx + dy * dy + dz * dz) < 20000.0) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("引导范围必须大于0,且引导线远点距离停机点至少20米")); return false; } VrPlaneGroundCalibrationParam& ground = params.groundCalibrationParam; if (!GetMatrix(m_planeCalib, QStringLiteral("调平矩阵"), ground.planeCalib)) return false; if (!GetDouble(m_planeHeight, QStringLiteral("地面高度"), ground.planeHeight)) return false; if (!GetMatrix(m_invRMatrix, QStringLiteral("逆矩阵"), ground.invRMatrix)) return false; VrPlaneTreeGrowParam& tree = params.treeGrowParam; if (!GetDouble(m_yDeviationMax, QStringLiteral("Y方向最大偏差"), tree.yDeviationMax)) return false; if (!GetDouble(m_zDeviationMax, QStringLiteral("Z方向最大偏差"), tree.zDeviationMax)) return false; if (!GetInt(m_maxLineSkipNum, QStringLiteral("最大跳线数"), tree.maxLineSkipNum)) return false; if (!GetDouble(m_maxSkipDistance, QStringLiteral("最大跳过距离"), tree.maxSkipDistance)) return false; if (!GetDouble(m_minLTypeTreeLen, QStringLiteral("L型树最小长度"), tree.minLTypeTreeLen)) return false; if (!GetDouble(m_minVTypeTreeLen, QStringLiteral("V型树最小长度"), tree.minVTypeTreeLen)) return false; if (tree.yDeviationMax <= 0.0 || tree.zDeviationMax <= 0.0 || (tree.maxLineSkipNum == -1 && tree.maxSkipDistance < 0.0)) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("聚类生长参数组合无效")); return false; } VrGuideDecisionParam& guide = params.guideDecisionParam; if (!GetDouble(m_lateralTolerance, QStringLiteral("横向对中容差"), guide.lateralTolerance)) return false; if (!GetDouble(m_angleTolerance, QStringLiteral("航向角容差"), guide.angleTolerance)) return false; VrParkingProcessParam& process = params.processParam; if (!GetDouble(m_dockingStartDistance, QStringLiteral("引导启动距离"), process.dockingStartDistance)) return false; if (!GetDouble(m_captureStartDistance, QStringLiteral("目标捕获距离"), process.captureStartDistance)) return false; if (!GetDouble(m_approachStartDistance, QStringLiteral("对中/方位引导距离"), process.approachStartDistance)) return false; if (!GetDouble(m_slowDistance, QStringLiteral("减速触发距离"), process.slowDistance)) return false; if (!GetDouble(m_stopDistanceTolerance, QStringLiteral("到位距离容差"), process.stopDistanceTolerance)) return false; if (!GetDouble(m_overshootDistance, QStringLiteral("越过停止线距离"), process.overshootDistance)) return false; if (!GetDouble(m_stoppedShortMinDistance, QStringLiteral("提前停止最小距离"), process.stoppedShortMinDistance)) return false; if (!GetDouble(m_maxApproachSpeed, QStringLiteral("最大接近速度"), process.maxApproachSpeed)) return false; if (!GetDouble(m_stoppedSpeedThreshold, QStringLiteral("静止速度阈值"), process.stoppedSpeedThreshold)) return false; if (!GetDouble(m_speedFilterAlpha, QStringLiteral("速度滤波系数"), process.speedFilterAlpha)) return false; if (!GetDouble(m_distanceChangeThreshold, QStringLiteral("距离变化阈值"), process.distanceChangeThreshold)) return false; if (!GetDouble(m_lateralOffsetChangeThreshold, QStringLiteral("横向偏移变化阈值"), process.lateralOffsetChangeThreshold)) return false; if (!GetInt(m_stopStableFrames, QStringLiteral("到位稳定帧数"), process.stopStableFrames)) return false; if (!GetInt(m_stoppedShortStableFrames, QStringLiteral("提前停止稳定帧数"), process.stoppedShortStableFrames)) return false; if (!GetInt(m_errorFrameThreshold, QStringLiteral("连续错误帧阈值"), process.errorFrameThreshold)) return false; if (!GetInt(m_lostFrameThreshold, QStringLiteral("目标丢失帧阈值"), process.lostFrameThreshold)) return false; if (!GetInt(m_completedHoldFrames, QStringLiteral("完成状态保持帧数"), process.completedHoldFrames)) return false; if (process.dockingStartDistance <= process.captureStartDistance || process.captureStartDistance <= process.approachStartDistance || process.approachStartDistance <= process.slowDistance || process.slowDistance <= process.stopDistanceTolerance || process.overshootDistance < process.stopDistanceTolerance || process.stoppedShortMinDistance < process.stopDistanceTolerance || process.maxApproachSpeed <= process.stoppedSpeedThreshold) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("流程距离应满足启动>捕获>对中/方位>减速>到位容差,越线和提前停止距离不得小于到位容差,最大接近速度必须大于静止速度阈值")); return false; } VrModelRecognitionParam& model = params.modelRecognitionParam; if (!GetDouble(m_modelVerifyDistance, QStringLiteral("机型验证距离"), model.modelVerifyDistance)) return false; if (!GetDouble(m_modelRoiX, QStringLiteral("飞机检测区域 X"), model.roiX)) return false; if (!GetDouble(m_modelRoiY, QStringLiteral("飞机检测区域 Y"), model.roiY)) return false; if (!GetDouble(m_modelRoiWidth, QStringLiteral("飞机检测区域宽度"), model.roiWidth)) return false; if (!GetDouble(m_modelRoiHeight, QStringLiteral("飞机检测区域高度"), model.roiHeight)) return false; if (!GetDouble(m_confidenceThreshold, QStringLiteral("识别置信度阈值"), model.confidenceThreshold)) return false; if (!GetInt(m_maxRecognitionAttempts, QStringLiteral("最大识别次数"), model.maxRecognitionAttempts)) return false; if (model.roiX + model.roiWidth > 1.0 || model.roiY + model.roiHeight > 1.0) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("飞机检测区域必须完整位于归一化图像范围 0~1 内")); return false; } VrPersonDetectionParam& person = params.personDetectionParam; person.enabled = m_personDetectionEnabled->isChecked(); if (!GetDouble(m_personRoiX, QStringLiteral("轮挡区域 X"), person.roiX)) return false; if (!GetDouble(m_personRoiY, QStringLiteral("轮挡区域 Y"), person.roiY)) return false; if (!GetDouble(m_personRoiWidth, QStringLiteral("轮挡区域宽度"), person.roiWidth)) return false; if (!GetDouble(m_personRoiHeight, QStringLiteral("轮挡区域高度"), person.roiHeight)) return false; if (!GetDouble(m_personConfidenceThreshold, QStringLiteral("人员置信度阈值"), person.confidenceThreshold)) return false; if (!GetInt(m_personStableFrames, QStringLiteral("连续有效检测次数"), person.stableFrames)) return false; if (!GetInt(m_personDetectionIntervalMs, QStringLiteral("人员检测周期"), person.detectionIntervalMs)) return false; if (person.roiX + person.roiWidth > 1.0 || person.roiY + person.roiHeight > 1.0) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("轮挡区域必须完整位于归一化图像范围 0~1 内")); return false; } config.mvsCamera.autoExposureEnabled = m_autoExposureEnabled->isChecked(); if (!GetDouble(m_exposureRoiX, QStringLiteral("曝光区域 X"), config.mvsCamera.exposureRoiX)) return false; if (!GetDouble(m_exposureRoiY, QStringLiteral("曝光区域 Y"), config.mvsCamera.exposureRoiY)) return false; if (!GetDouble(m_exposureRoiWidth, QStringLiteral("曝光区域宽度"), config.mvsCamera.exposureRoiWidth)) return false; if (!GetDouble(m_exposureRoiHeight, QStringLiteral("曝光区域高度"), config.mvsCamera.exposureRoiHeight)) return false; if (!GetDouble(m_exposureReferenceGray, QStringLiteral("参考灰度"), config.mvsCamera.exposureReferenceGray)) return false; if (!GetDouble(m_exposureGrayTolerance, QStringLiteral("灰度容差"), config.mvsCamera.exposureGrayTolerance)) return false; if (!GetInt(m_autoExposureIntervalMinutes, QStringLiteral("曝光调整间隔"), config.mvsCamera.autoExposureIntervalMinutes)) return false; if (config.mvsCamera.exposureRoiX + config.mvsCamera.exposureRoiWidth > 1.0 || config.mvsCamera.exposureRoiY + config.mvsCamera.exposureRoiHeight > 1.0) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("曝光区域必须完整位于归一化图像范围 0~1 内")); return false; } config.mvsCamera.serialNumber = m_mvsSerialNumber->text().trimmed().toStdString(); config.mvsCamera.ipAddress = m_mvsIpAddress->text().trimmed().toStdString(); if (!GetInt(m_mvsDeviceIndex, QStringLiteral("相机设备序号"), config.mvsCamera.deviceIndex)) return false; config.mvsCamera.enabled = m_mvsEnabled->isChecked(); config.lidarConfig.lidarType = m_lidarType->text().trimmed().toStdString(); config.lidarConfig.hostAddress = m_lidarHost->text().trimmed().toStdString(); config.lidarConfig.deviceIp = m_lidarDeviceIp->text().trimmed().toStdString(); int intValue = 0; if (!GetInt(m_lidarMsopPort, QStringLiteral("雷达数据端口"), intValue)) return false; config.lidarConfig.msopPort = static_cast(intValue); if (!GetInt(m_lidarDifopPort, QStringLiteral("雷达设备端口"), intValue)) return false; config.lidarConfig.difopPort = static_cast(intValue); if (!GetFloat(m_lidarMinDistance, QStringLiteral("雷达最小距离"), config.lidarConfig.minDistance)) return false; if (!GetFloat(m_lidarMaxDistance, QStringLiteral("雷达最大距离"), config.lidarConfig.maxDistance)) return false; if (!GetFloat(m_lidarStartAngle, QStringLiteral("雷达起始角度"), config.lidarConfig.startAngle)) return false; if (!GetFloat(m_lidarEndAngle, QStringLiteral("雷达结束角度"), config.lidarConfig.endAngle)) return false; config.udpBroadcastConfig.address = m_udpAddress->text().trimmed().toStdString(); if (!GetInt(m_udpPort, QStringLiteral("组播端口"), config.udpBroadcastConfig.port)) return false; config.udpBroadcastConfig.targetId = m_udpTargetId->text().trimmed().toStdString(); config.udpBroadcastConfig.parkId = m_udpParkId->text().trimmed().toStdString(); config.udpBroadcastConfig.enabled = m_udpEnabled->isChecked(); config.Normalize(); if (!m_presenter->GetConfigManager()->UpdateFullConfig(systemConfig)) { StyledMessageBox::warning(this, QStringLiteral("失败"), QStringLiteral("更新配置缓存失败")); return false; } const QString configPath = PathManager::GetInstance().GetConfigFilePath(); if (!m_presenter->GetConfigManager()->SaveConfigToFile(configPath.toStdString())) { StyledMessageBox::warning(this, QStringLiteral("失败"), QStringLiteral("保存配置文件失败")); return false; } m_presenter->OnConfigChanged(config); emit paramsSaved(); return true; } void DialogAlgoArg::ResetParams() { ConfigResult config; config.Normalize(); const VrAlgorithmParams& params = config.algorithmParams; const VrPlaneParkingParam& parking = params.planeParkingParam; SetDouble(m_parkingPointX, parking.parkingPointX); SetDouble(m_parkingPointY, parking.parkingPointY); SetDouble(m_parkingPointZ, parking.parkingPointZ); SetDouble(m_guideLinePointX, parking.guideLinePointX); SetDouble(m_guideLinePointY, parking.guideLinePointY); SetDouble(m_guideLinePointZ, parking.guideLinePointZ); SetDouble(m_guidingRange, parking.guidingRange); SetDouble(m_parkingRange, parking.parkingRange); SetDouble(m_distFromNoseToWheel, parking.distFromNoseToWheel); const VrPlaneGroundCalibrationParam& ground = params.groundCalibrationParam; SetMatrix(m_planeCalib, ground.planeCalib); SetDouble(m_planeHeight, ground.planeHeight); SetMatrix(m_invRMatrix, ground.invRMatrix); const VrPlaneTreeGrowParam& tree = params.treeGrowParam; SetDouble(m_yDeviationMax, tree.yDeviationMax); SetDouble(m_zDeviationMax, tree.zDeviationMax); SetInt(m_maxLineSkipNum, tree.maxLineSkipNum); SetDouble(m_maxSkipDistance, tree.maxSkipDistance); SetDouble(m_minLTypeTreeLen, tree.minLTypeTreeLen); SetDouble(m_minVTypeTreeLen, tree.minVTypeTreeLen); const VrGuideDecisionParam& guide = params.guideDecisionParam; SetDouble(m_lateralTolerance, guide.lateralTolerance); SetDouble(m_angleTolerance, guide.angleTolerance); const VrParkingProcessParam& process = params.processParam; SetDouble(m_dockingStartDistance, process.dockingStartDistance); SetDouble(m_captureStartDistance, process.captureStartDistance); SetDouble(m_approachStartDistance, process.approachStartDistance); SetDouble(m_slowDistance, process.slowDistance); SetDouble(m_stopDistanceTolerance, process.stopDistanceTolerance); SetDouble(m_overshootDistance, process.overshootDistance); SetDouble(m_stoppedShortMinDistance, process.stoppedShortMinDistance); SetDouble(m_maxApproachSpeed, process.maxApproachSpeed); SetDouble(m_stoppedSpeedThreshold, process.stoppedSpeedThreshold); SetDouble(m_speedFilterAlpha, process.speedFilterAlpha); SetDouble(m_distanceChangeThreshold, process.distanceChangeThreshold); SetDouble(m_lateralOffsetChangeThreshold, process.lateralOffsetChangeThreshold); SetInt(m_stopStableFrames, process.stopStableFrames); SetInt(m_stoppedShortStableFrames, process.stoppedShortStableFrames); SetInt(m_errorFrameThreshold, process.errorFrameThreshold); SetInt(m_lostFrameThreshold, process.lostFrameThreshold); SetInt(m_completedHoldFrames, process.completedHoldFrames); const VrModelRecognitionParam& model = params.modelRecognitionParam; SetDouble(m_modelVerifyDistance, model.modelVerifyDistance); SetDouble(m_modelRoiX, model.roiX); SetDouble(m_modelRoiY, model.roiY); SetDouble(m_modelRoiWidth, model.roiWidth); SetDouble(m_modelRoiHeight, model.roiHeight); SetDouble(m_confidenceThreshold, model.confidenceThreshold); SetInt(m_maxRecognitionAttempts, model.maxRecognitionAttempts); const VrPersonDetectionParam& person = params.personDetectionParam; m_personDetectionEnabled->setChecked(person.enabled); SetDouble(m_personRoiX, person.roiX); SetDouble(m_personRoiY, person.roiY); SetDouble(m_personRoiWidth, person.roiWidth); SetDouble(m_personRoiHeight, person.roiHeight); SetDouble(m_personConfidenceThreshold, person.confidenceThreshold); SetInt(m_personStableFrames, person.stableFrames); SetInt(m_personDetectionIntervalMs, person.detectionIntervalMs); m_autoExposureEnabled->setChecked(config.mvsCamera.autoExposureEnabled); SetDouble(m_exposureRoiX, config.mvsCamera.exposureRoiX); SetDouble(m_exposureRoiY, config.mvsCamera.exposureRoiY); SetDouble(m_exposureRoiWidth, config.mvsCamera.exposureRoiWidth); SetDouble(m_exposureRoiHeight, config.mvsCamera.exposureRoiHeight); SetDouble(m_exposureReferenceGray, config.mvsCamera.exposureReferenceGray); SetDouble(m_exposureGrayTolerance, config.mvsCamera.exposureGrayTolerance); SetInt(m_autoExposureIntervalMinutes, config.mvsCamera.autoExposureIntervalMinutes); m_mvsSerialNumber->setText(QString::fromStdString(config.mvsCamera.serialNumber)); m_mvsIpAddress->setText(QString::fromStdString(config.mvsCamera.ipAddress)); SetInt(m_mvsDeviceIndex, config.mvsCamera.deviceIndex); m_mvsEnabled->setChecked(config.mvsCamera.enabled); m_lidarType->setText(QString::fromStdString(config.lidarConfig.lidarType)); m_lidarHost->setText(QString::fromStdString(config.lidarConfig.hostAddress)); m_lidarDeviceIp->setText(QString::fromStdString(config.lidarConfig.deviceIp)); SetInt(m_lidarMsopPort, config.lidarConfig.msopPort); SetInt(m_lidarDifopPort, config.lidarConfig.difopPort); SetDouble(m_lidarMinDistance, config.lidarConfig.minDistance); SetDouble(m_lidarMaxDistance, config.lidarConfig.maxDistance); SetDouble(m_lidarStartAngle, config.lidarConfig.startAngle); SetDouble(m_lidarEndAngle, config.lidarConfig.endAngle); m_udpAddress->setText(QString::fromStdString(config.udpBroadcastConfig.address)); SetInt(m_udpPort, config.udpBroadcastConfig.port); m_udpTargetId->setText(QString::fromStdString(config.udpBroadcastConfig.targetId)); m_udpParkId->setText(QString::fromStdString(config.udpBroadcastConfig.parkId)); m_udpEnabled->setChecked(config.udpBroadcastConfig.enabled); } void DialogAlgoArg::SetDouble(QLineEdit* edit, double value) { if (edit) edit->setText(QString::number(value, 'g', 12)); } void DialogAlgoArg::SetInt(QLineEdit* edit, int value) { if (edit) edit->setText(QString::number(value)); } bool DialogAlgoArg::GetDouble(QLineEdit* edit, const QString& label, double& value) { bool ok = false; value = edit ? edit->text().trimmed().toDouble(&ok) : 0.0; if (!edit || !edit->hasAcceptableInput() || !ok || !std::isfinite(value)) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("%1无效").arg(label)); if (edit) edit->setFocus(); return false; } return true; } bool DialogAlgoArg::GetFloat(QLineEdit* edit, const QString& label, float& value) { double doubleValue = 0.0; if (!GetDouble(edit, label, doubleValue)) return false; value = static_cast(doubleValue); return true; } bool DialogAlgoArg::GetInt(QLineEdit* edit, const QString& label, int& value) { bool ok = false; value = edit ? edit->text().trimmed().toInt(&ok) : 0; if (!edit || !edit->hasAcceptableInput() || !ok) { StyledMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("%1无效").arg(label)); if (edit) edit->setFocus(); return false; } return true; } void DialogAlgoArg::SetMatrix(QLineEdit* const edits[9], const double values[9]) { for (int i = 0; i < 9; ++i) SetDouble(edits[i], values[i]); } bool DialogAlgoArg::GetMatrix(QLineEdit* const edits[9], const QString& label, double values[9]) { for (int i = 0; i < 9; ++i) { if (!GetDouble(edits[i], QStringLiteral("%1 R%2%3").arg(label).arg(i / 3).arg(i % 3), values[i])) { return false; } } return true; } void DialogAlgoArg::on_btnOK_clicked() { if (SaveParams()) accept(); } void DialogAlgoArg::on_btnCancel_clicked() { reject(); } void DialogAlgoArg::on_btnApply_clicked() { if (SaveParams()) { StyledMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("参数已应用")); } } void DialogAlgoArg::on_btnReset_clicked() { ResetParams(); }