diff --git a/App/WheelMeasure/Doc/TCP_Protocol.md b/App/WheelMeasure/Doc/TCP_Protocol.md
new file mode 100644
index 00000000..00e7ee37
--- /dev/null
+++ b/App/WheelMeasure/Doc/TCP_Protocol.md
@@ -0,0 +1,131 @@
+# 轮眉测量 TCP/IP 通信协议
+
+## 概述
+
+- **协议类型**: TCP/IP 文本协议
+- **默认端口**: 5000(可在配置文件中修改)
+- **数据格式**: 纯文本,UTF-8编码
+- **通信模式**: 客户端-服务器模式(视觉系统作为服务器)
+
+## 协议格式
+
+### 1. 触发检测命令(客户端 → 服务器)
+
+```
+start,100
+```
+
+**格式说明**:
+- `start`: 命令关键字
+- `100`: 参数(当前未使用,保留用于扩展)
+
+**示例**:
+```
+start,100
+```
+
+### 2. 检测结果响应(服务器 → 客户端)
+
+#### 成功情况(所有相机检测成功)
+
+```
+1,100,200;2,100,200;3,100,200;4,100,200
+```
+
+**格式说明**:
+- 多个相机结果用分号 `;` 分隔
+- 每个相机结果格式:`相机ID,中心点到地面距离,轮眉到地面距离`
+ - `相机ID`: 1-4(对应4个相机)
+ - `中心点到地面距离`: 整数,单位mm
+ - `轮眉到地面距离`: 整数,单位mm
+
+**示例**:
+```
+1,150,250;2,148,252;3,151,249;4,149,251
+```
+表示:
+- 相机1:中心距离150mm,轮眉距离250mm
+- 相机2:中心距离148mm,轮眉距离252mm
+- 相机3:中心距离151mm,轮眉距离249mm
+- 相机4:中心距离149mm,轮眉距离251mm
+
+#### 失败情况(部分相机检测失败)
+
+```
+1,400;2,100,200;3,100,200;4,100,200
+```
+
+**错误码说明**:
+- `400`: 扫描/匹配失败
+- `401`: 工件为空
+
+**格式说明**:
+- 失败的相机只返回:`相机ID,错误码`
+- 成功的相机返回:`相机ID,中心距离,轮眉距离`
+
+**示例**:
+```
+1,400;2,150,250;3,401;4,149,251
+```
+表示:
+- 相机1:扫描失败(错误码400)
+- 相机2:成功,中心距离150mm,轮眉距离250mm
+- 相机3:工件为空(错误码401)
+- 相机4:成功,中心距离149mm,轮眉距离251mm
+
+## 通信流程
+
+```
+客户端 服务器(视觉系统)
+ | |
+ |-------- start,100 ------------------------>|
+ | |
+ | | 触发所有相机顺序检测
+ | | (相机1 → 相机2 → 相机3 → 相机4)
+ | |
+ |<------- 1,150,250;2,148,252;... -----------|
+ | |
+```
+
+**时序说明**:
+1. 客户端发送 `start,100` 命令
+2. 服务器收到命令后,依次触发所有启用的相机进行检测
+3. 所有相机检测完成后,服务器发送汇总结果
+4. 客户端接收结果并处理
+
+## 错误处理
+
+### 连接错误
+- 如果TCP连接断开,服务器会清除当前客户端的请求状态
+- 客户端需要重新连接并发送命令
+
+### 超时处理
+- 建议客户端设置接收超时(推荐60秒)
+- 如果超时未收到响应,可以重新发送命令
+
+### 数据解析
+- 客户端应验证返回数据格式
+- 检查相机ID是否在1-4范围内
+- 检查是否包含错误码(400/401)
+
+## 配置说明
+
+TCP服务器端口可在配置文件中修改:
+
+```xml
+
+
+ TCPServer
+ 0.0.0.0
+ 5000
+
+
+```
+
+## 注意事项
+
+1. **数据单位**:所有距离值单位为毫米(mm)
+2. **相机顺序**:相机ID固定为1-4,对应配置文件中的相机顺序
+3. **检测时间**:完整检测所有相机通常需要30-50秒,请设置合理的超时时间
+4. **并发限制**:服务器同时只处理一个检测请求,多个客户端连接时按先后顺序处理
+5. **数据精度**:返回的距离值已四舍五入为整数
diff --git a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
index fd90298f..29aeff71 100644
--- a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp
@@ -73,8 +73,11 @@ int WheelMeasurePresenter::InitApp()
}
}
- // 初始化TCP服务器
- int tcpPort = 6800; // 默认端口
+ // 初始化TCP服务器(从配置读取端口)
+ int tcpPort = 5000; // 默认端口
+ if (!m_configResult.servers.empty()) {
+ tcpPort = m_configResult.servers[0].port;
+ }
int tcpResult = m_tcpProtocol.Initialize(tcpPort);
if (tcpResult != 0) {
LOG_ERROR("Failed to initialize TCP server on port %d, error code: %d\n", tcpPort, tcpResult);
@@ -306,6 +309,9 @@ void WheelMeasurePresenter::StartAllDetection()
LOG_INFO("Sequential detection started, total cameras: %d\n", m_sequentialTotalCount);
+
+ m_statusUpdate->OnStatusUpdate(QString("开始所有设备的检测"));
+
// 开始检测第一个设备
continueSequentialDetection();
}
@@ -517,7 +523,7 @@ void WheelMeasurePresenter::processScanData(std::vectorwheelRoi3d_xMin;
+ wheelRoi3d.xRange.max = calibParam->wheelRoi3d_xMax;
+ wheelRoi3d.yRange.min = calibParam->wheelRoi3d_yMin;
+ wheelRoi3d.yRange.max = calibParam->wheelRoi3d_yMax;
+ wheelRoi3d.zRange.min = calibParam->wheelRoi3d_zMin;
+ wheelRoi3d.zRange.max = calibParam->wheelRoi3d_zMax;
+
+ LOG_INFO("Using ROI range for wheel presence detection:\n");
+ LOG_INFO(" X: [%.1f, %.1f], Y: [%.1f, %.1f], Z: [%.1f, %.1f]\n",
+ wheelRoi3d.xRange.min, wheelRoi3d.xRange.max,
+ wheelRoi3d.yRange.min, wheelRoi3d.yRange.max,
+ wheelRoi3d.zRange.min, wheelRoi3d.zRange.max);
+ } else {
+ // 使用默认ROI范围
+ wheelRoi3d.xRange.min = -1000.0;
+ wheelRoi3d.xRange.max = 1000.0;
+ wheelRoi3d.yRange.min = -1000.0;
+ wheelRoi3d.yRange.max = 1000.0;
+ wheelRoi3d.zRange.min = -1000.0;
+ wheelRoi3d.zRange.max = 1000.0;
+
+ LOG_INFO("Using default ROI range for wheel presence detection: ±1000.0 mm\n");
+ }
+
+ // 调用轮胎存在检测
+ bool wheelPresent = wd_wheelPresenseDetection(scanLines, wheelRoi3d);
+ LOG_INFO("Wheel presence detection result: %s\n", wheelPresent ? "PRESENT" : "NOT PRESENT");
+
+ if (!wheelPresent) {
+ LOG_WARNING("No wheel detected in ROI range, skipping measurement\n");
+ if (m_statusUpdate) {
+ m_statusUpdate->OnStatusUpdate(QString("未检测到轮胎,请检查ROI范围配置"));
+ }
+
+ // 如果是TCP触发的检测,缓存401错误结果
+ if (m_tcpDetectionMode) {
+ WheelMeasureTCPProtocol::CameraMeasureResult tcpResult;
+ tcpResult.cameraId = m_currentCameraIndex;
+ tcpResult.errorCode = 401; // 工件为空
+ tcpResult.centerDistance = 0.0;
+ tcpResult.archDistance = 0.0;
+ m_tcpResults[m_currentCameraIndex] = tcpResult;
+ LOG_INFO("TCP检测结果已缓存: 相机%d, 错误码=401 (未检测到轮胎)\n", m_currentCameraIndex);
+ }
+
+ // 如果正在进行顺序检测,继续检测下一个设备
+ if (m_sequentialDetecting) {
+ m_sequentialCurrentIndex++;
+
+ // TCP模式下,检查是否所有相机都检测完成
+ if (m_tcpDetectionMode && m_tcpResults.size() >= m_sequentialTotalCount) {
+ LOG_INFO("TCP模式:所有相机检测完成,准备发送结果\n");
+ m_sequentialDetecting = false;
+ sendTCPMeasureResults();
+ } else {
+ // 继续检测下一个设备
+ QMetaObject::invokeMethod(this, [this]() {
+ continueSequentialDetection();
+ }, Qt::QueuedConnection);
+ }
+ }
+
+ return;
+ }
+
+ // 4. 准备调平参数并执行调平处理(使用当前相机的调平参数)
SSG_planeCalibPara groundCalibPara;
memset(&groundCalibPara, 0, sizeof(groundCalibPara));
@@ -544,8 +622,6 @@ void WheelMeasurePresenter::processScanData(std::vectorisCalibrated) {
for (int i = 0; i < 9; ++i) {
groundCalibPara.planeCalib[i] = calibParam->planeCalib[i];
@@ -568,8 +644,7 @@ void WheelMeasurePresenter::processScanData(std::vector= m_sequentialTotalCount) {
+ if (m_tcpDetectionMode && m_tcpResults.size() >= m_sequentialTotalCount) {
+ LOG_INFO("TCP模式:所有相机检测完成,准备发送结果\n");
+ // 先结束顺序检测
+ m_sequentialDetecting = false;
+ // 发送TCP结果
sendTCPMeasureResults();
+ } else {
+ // 继续检测下一个设备
+ QMetaObject::invokeMethod(this, [this]() {
+ continueSequentialDetection();
+ }, Qt::QueuedConnection);
}
}
}
diff --git a/App/WheelMeasure/WheelMeasureApp/Version.h b/App/WheelMeasure/WheelMeasureApp/Version.h
index a8fe569a..4b268e0b 100644
--- a/App/WheelMeasure/WheelMeasureApp/Version.h
+++ b/App/WheelMeasure/WheelMeasureApp/Version.h
@@ -1,22 +1,22 @@
-#ifndef VERSION_H
-#define VERSION_H
-
-
-#define WHEELMEASURE_VERSION_STRING "1.0.1"
-#define WHEELMEASURE_BUILD_STRING "5"
-#define WHEELMEASURE_FULL_VERSION_STRING "V" WHEELMEASURE_VERSION_STRING "_" WHEELMEASURE_BUILD_STRING
-
-// 获取版本信息的便捷函数
-inline const char* GetWheelMeasureVersion() {
- return WHEELMEASURE_VERSION_STRING;
-}
-
-inline const char* GetWheelMeasureBuild() {
- return WHEELMEASURE_BUILD_STRING;
-}
-
-inline const char* GetWheelMeasureFullVersion() {
- return WHEELMEASURE_FULL_VERSION_STRING;
-}
-
-#endif // VERSION_H
+#ifndef VERSION_H
+#define VERSION_H
+
+
+#define WHEELMEASURE_VERSION_STRING "1.0.1"
+#define WHEELMEASURE_BUILD_STRING "6"
+#define WHEELMEASURE_FULL_VERSION_STRING "V" WHEELMEASURE_VERSION_STRING "_" WHEELMEASURE_BUILD_STRING
+
+// 获取版本信息的便捷函数
+inline const char* GetWheelMeasureVersion() {
+ return WHEELMEASURE_VERSION_STRING;
+}
+
+inline const char* GetWheelMeasureBuild() {
+ return WHEELMEASURE_BUILD_STRING;
+}
+
+inline const char* GetWheelMeasureFullVersion() {
+ return WHEELMEASURE_FULL_VERSION_STRING;
+}
+
+#endif // VERSION_H
diff --git a/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro b/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro
index 2ce6eb59..e4f914b7 100644
--- a/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro
+++ b/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro
@@ -27,6 +27,7 @@ INCLUDEPATH += ../../../Utils/VrCommon/Inc
INCLUDEPATH += ../../../AppUtils/UICommon/Inc
INCLUDEPATH += ../../../Utils/CloudUtils/Inc
INCLUDEPATH += ../../../AppUtils/AppCommon/Inc
+INCLUDEPATH += ../../../Module/AuthModule/Inc
INCLUDEPATH += ../../../SDK/Device/VzNLSDK/Inc
INCLUDEPATH += ../../../AppAlgo/wheelArchHeigthMeasure/Inc
@@ -38,8 +39,9 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../../../Utils/VrUtils/debug -lVrUtils
LIBS += -L../../../Device/VrEyeDevice/debug -lVrEyeDevice
LIBS += -L../../../AppUtils/UICommon/debug -lUICommon
- LIBS += -L../../../Utils/CloudUtils/debug -lCloudUtils
+ LIBS += -L../../../Utils/CloudUtils/debug -lCloudUtils
LIBS += -L../../../AppUtils/AppCommon/debug -lAppCommon
+ LIBS += -L../../../Module/AuthModule/debug -lAuthModule
LIBS += -L../../../Module/ModbusTCPServer/debug -lModbusTCPServer
LIBS += -L../../../VrNets/debug -lVrModbus
} else:win32:CONFIG(release, debug|release) {
@@ -48,8 +50,9 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../../../Utils/VrUtils/release -lVrUtils
LIBS += -L../../../Device/VrEyeDevice/release -lVrEyeDevice
LIBS += -L../../../AppUtils/UICommon/release -lUICommon
- LIBS += -L../../../Utils/CloudUtils/release -lCloudUtils
+ LIBS += -L../../../Utils/CloudUtils/release -lCloudUtils
LIBS += -L../../../AppUtils/AppCommon/release -lAppCommon
+ LIBS += -L../../../Module/AuthModule/release -lAuthModule
LIBS += -L../../../Module/ModbusTCPServer/release -lModbusTCPServer
LIBS += -L../../../VrNets/release -lVrModbus
}else:unix:!macx {
@@ -57,7 +60,8 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../WheelMeasureConfig -lWheelMeasureConfig
LIBS += -L../../../AppUtils/AppCommon -lAppCommon
LIBS += -L../../../AppUtils/UICommon -lUICommon
- LIBS += -L../../../Utils/CloudUtils -lCloudUtils
+ LIBS += -L../../../Module/AuthModule -lAuthModule
+ LIBS += -L../../../Utils/CloudUtils -lCloudUtils
LIBS += -L../../../Device/VrEyeDevice -lVrEyeDevice
LIBS += -L../../../VrNets -lVrTcpClient -lVrTcpServer
LIBS += -L../../../Utils/VrUtils -lVrUtils
diff --git a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.cpp b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.cpp
index a1a79b90..0665a188 100644
--- a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.cpp
@@ -1,705 +1,833 @@
-#include "dialogcameralevel.h"
-#include "ui_dialogcameralevel.h"
-#include "WheelMeasurePresenter.h"
-#include "PathManager.h"
-#include "VrLog.h"
-#include "wheelArchHeigthMeasure_Export.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-DialogCameraLevel::DialogCameraLevel(QWidget *parent)
- : QDialog(parent)
- , ui(new Ui::DialogCameraLevel)
- , m_pConfig(nullptr)
- , m_pConfigResult(nullptr)
- , m_currentCameraIndex(-1)
-{
- ui->setupUi(this);
-
- // 初始化结果显示区域
- ui->label_level_result->setText("请选择相机,然后点击调平按钮\n开始相机调平操作");
- ui->label_level_result->setAlignment(Qt::AlignCenter);
-}
-
-DialogCameraLevel::~DialogCameraLevel()
-{
- // 清理扫描数据缓存
- clearScanDataCache();
-
- // 确保恢复Presenter的状态回调
- restorePresenterStatusCallback();
-
- delete ui;
-}
-
-void DialogCameraLevel::setCameraList(const std::vector>& cameraList,
- WheelMeasurePresenter* presenter)
-{
- m_cameraList = cameraList;
- m_presenter = presenter;
-
- LOG_INFO("setCameraList called with %zu cameras\n", cameraList.size());
-
- // 详细记录每个相机的信息
- for (size_t i = 0; i < cameraList.size(); ++i) {
- const auto& camera = cameraList[i];
- LOG_INFO(" Camera %zu: name='%s', device=%s\n",
- i + 1,
- camera.first.c_str(),
- (camera.second != nullptr ? "connected" : "not connected"));
- }
-
- // 初始化/重新初始化相机选择框
- initializeCameraCombo();
-}
-
-void DialogCameraLevel::setConfig(IVrWheelMeasureConfig* config, WheelMeasureConfigResult* configResult)
-{
- m_pConfig = config;
- m_pConfigResult = configResult;
-
- // 如果相机已经选择,重新加载当前相机的标定状态
- // 修复:打开页面时配置可能在相机列表之后设置,导致初始加载失败
- if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast(m_cameraList.size())) {
- checkAndDisplayCalibrationStatus(m_currentCameraIndex);
- }
-}
-
-void DialogCameraLevel::initializeCameraCombo()
-{
- LOG_INFO("initializeCameraCombo called, camera list size: %zu\n", m_cameraList.size());
-
- ui->combo_camera->clear();
-
- if (m_cameraList.empty()) {
- ui->combo_camera->setEnabled(false);
-
- if (!m_presenter) {
- ui->label_level_result->setText("Presenter未初始化\n无法获取相机列表");
- LOG_ERROR("Presenter is null in initializeCameraCombo\n");
- } else {
- ui->label_level_result->setText("相机列表为空\n\n可能原因:\n1. 配置文件中未配置相机\n2. 系统正在初始化中\n3. 所有相机连接失败");
- LOG_WARNING("Camera list is empty in initializeCameraCombo\n");
- }
-
- ui->label_level_result->setAlignment(Qt::AlignCenter);
- } else {
- LOG_INFO("Adding %zu cameras to combo box\n", m_cameraList.size());
-
- // 添加所有相机到下拉列表
- for (size_t i = 0; i < m_cameraList.size(); ++i) {
- const auto& camera = m_cameraList[i];
- QString cameraName = QString::fromStdString(camera.first);
-
- // 如果相机没有连接,在名称后添加标记
- if (camera.second == nullptr) {
- cameraName += " [未连接]";
- }
-
- ui->combo_camera->addItem(cameraName);
- LOG_INFO(" Added camera %zu: %s (device=%s)\n",
- i + 1,
- camera.first.c_str(),
- (camera.second != nullptr ? "OK" : "NULL"));
- }
- ui->combo_camera->setEnabled(true);
-
- // 获取默认相机索引
- int defaultCameraIndex = 0;
- if (m_presenter) {
- int presenterDefaultIndex = m_presenter->GetDefaultCameraIndex();
- LOG_INFO("Presenter default camera index (1-based): %d\n", presenterDefaultIndex);
-
- if (presenterDefaultIndex > 0 && presenterDefaultIndex <= static_cast(m_cameraList.size())) {
- defaultCameraIndex = presenterDefaultIndex - 1;
- }
- }
-
- // 设置默认选中的相机
- if (defaultCameraIndex >= 0 && defaultCameraIndex < static_cast(m_cameraList.size())) {
- ui->combo_camera->setCurrentIndex(defaultCameraIndex);
- m_currentCameraIndex = defaultCameraIndex;
- }
-
- // 检查并显示当前选中相机的标定状态
- if (m_currentCameraIndex >= 0) {
- checkAndDisplayCalibrationStatus(m_currentCameraIndex);
- }
- }
-}
-
-void DialogCameraLevel::on_btn_apply_clicked()
-{
- ui->label_level_result->setAlignment(Qt::AlignLeft);
-
- // 检查是否有可用的相机
- if (m_cameraList.empty()) {
- QMessageBox::warning(this, "错误", "无可用相机设备!");
- return;
- }
-
- // 获取选中的相机
- int selectedIndex = ui->combo_camera->currentIndex();
- if (selectedIndex < 0 || selectedIndex >= static_cast(m_cameraList.size())) {
- QMessageBox::warning(this, "错误", "请选择有效的相机!");
- return;
- }
-
- // 清空之前的结果显示
- ui->label_level_result->setText("调平计算中,请稍候...");
-
- // 显示进度提示
- ui->btn_apply->setEnabled(false);
- QApplication::processEvents();
-
- try {
- // 执行相机调平
- if (performCameraLeveling()) {
- // 调平成功
- } else {
- ui->label_level_result->setText("调平失败!\n\n请检查:\n1. 相机连接是否正常\n2. 地面扫描数据是否充足\n3. 扫描区域是否有足够的地面");
- }
- } catch (const std::exception& e) {
- LOG_ERROR("Camera leveling failed with exception: %s\n", e.what());
- QMessageBox::critical(this, "错误", QString("调平过程发生异常:%1").arg(e.what()));
- }
-
- // 恢复按钮状态
- ui->btn_apply->setEnabled(true);
-}
-
-void DialogCameraLevel::on_btn_cancel_clicked()
-{
- reject();
-}
-
-bool DialogCameraLevel::performCameraLeveling()
-{
- try {
- // 获取选中的相机索引
- int selectedIndex = ui->combo_camera->currentIndex();
-
- // 先检查索引有效性,再设置回调
- if (selectedIndex < 0 || selectedIndex >= static_cast(m_cameraList.size())) {
- LOG_ERROR("Invalid camera index: %d\n", selectedIndex);
- return false;
- }
-
- LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex);
-
- // 1. 设置调平状态回调(在索引检查之后)
- setLevelingStatusCallback();
-
- // 2. 清空之前的扫描数据
- clearScanDataCache();
-
- // 3. 启动相机扫描地面数据
- if (!startCameraScan(selectedIndex)) {
- LOG_ERROR("Failed to start camera scan for leveling\n");
- restorePresenterStatusCallback(); // 恢复回调
- return false;
- }
-
- // 4. 等待扫描完成
- LOG_INFO("Collecting ground scan data, waiting for swing finish signal...\n");
- int waitTime = 0;
- const int maxWaitTime = 10000; // 最大等待10秒
- const int checkInterval = 100;
-
- while (!m_swingFinished && waitTime < maxWaitTime) {
- QThread::msleep(checkInterval);
- QApplication::processEvents();
- waitTime += checkInterval;
- }
-
- // 5. 停止扫描
- stopCameraScan(selectedIndex);
-
- if (m_swingFinished) {
- LOG_INFO("Camera swing finished signal received, scan completed\n");
- } else if (waitTime >= maxWaitTime) {
- LOG_WARNING("Timeout waiting for camera swing finish signal\n");
- }
-
- // 6. 调用调平算法计算
- double planeCalib[9];
- double planeHeight;
- double invRMatrix[9];
-
- if (!calculatePlaneCalibration(planeCalib, planeHeight, invRMatrix)) {
- LOG_ERROR("Failed to calculate plane calibration\n");
- restorePresenterStatusCallback(); // 恢复回调
- return false;
- }
-
- LOG_INFO("Camera leveling calculation completed\n");
-
- // 7. 更新界面显示
- updateLevelingResults(planeCalib, planeHeight, invRMatrix);
-
- // 8. 保存结果到配置
- int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
- QString cameraName;
-
- if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast(m_cameraList.size())) {
- cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
- } else {
- cameraName = QString("Camera_%1").arg(cameraIndex);
- }
-
- if (!saveLevelingResults(planeCalib, planeHeight, invRMatrix, cameraIndex, cameraName)) {
- LOG_ERROR("Failed to save leveling results\n");
- restorePresenterStatusCallback(); // 恢复回调
- return false;
- }
-
- clearScanDataCache();
-
- // 9. 调平完成后恢复回调
- restorePresenterStatusCallback();
-
- LOG_INFO("Camera leveling completed successfully\n");
-
- return true;
-
- } catch (const std::exception& e) {
- LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what());
- restorePresenterStatusCallback(); // 异常时也恢复回调
- return false;
- }
-}
-
-void DialogCameraLevel::updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9])
-{
- // 构建显示文本
- QString resultText;
-
- resultText += QString("地面高度: %1 mm\n").arg(QString::number(planeHeight, 'f', 2));
-
- // 调平矩阵
- resultText += QString("调平矩阵:\n");
- for (int i = 0; i < 3; i++) {
- resultText += QString("[%1, %2, %3]\n")
- .arg(QString::number(planeCalib[i*3], 'f', 4))
- .arg(QString::number(planeCalib[i*3+1], 'f', 4))
- .arg(QString::number(planeCalib[i*3+2], 'f', 4));
- }
-
- resultText += QString("逆旋转矩阵:\n");
- for (int i = 0; i < 3; i++) {
- resultText += QString("[%1, %2, %3]\n")
- .arg(QString::number(invRMatrix[i*3], 'f', 4))
- .arg(QString::number(invRMatrix[i*3+1], 'f', 4))
- .arg(QString::number(invRMatrix[i*3+2], 'f', 4));
- }
-
- ui->label_level_result->setText(resultText);
- ui->label_level_result->setAlignment(Qt::AlignLeft | Qt::AlignTop);
-}
-
-bool DialogCameraLevel::startCameraScan(int cameraIndex)
-{
- if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
- LOG_ERROR("Invalid camera index for scan: %d\n", cameraIndex);
- return false;
- }
-
- IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
- if (!camera) {
- LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
- return false;
- }
-
- // 启动相机检测
- int result = camera->StartDetect(&DialogCameraLevel::StaticDetectionCallback, keResultDataType_Position, this);
- if (result != 0) {
- LOG_ERROR("Failed to start camera detection: %d\n", result);
- return false;
- }
-
- LOG_INFO("Camera scan started successfully for camera index: %d\n", cameraIndex);
- return true;
-}
-
-bool DialogCameraLevel::stopCameraScan(int cameraIndex)
-{
- if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
- LOG_ERROR("Invalid camera index for stop scan: %d\n", cameraIndex);
- return false;
- }
-
- IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
- if (!camera) {
- LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
- return false;
- }
-
- int result = camera->StopDetect();
- if (result != 0) {
- LOG_WARNING("Failed to stop camera detection, error: %d\n", result);
- return false;
- }
-
- LOG_INFO("Camera scan stopped successfully for camera index: %d\n", cameraIndex);
- return true;
-}
-
-void DialogCameraLevel::StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData)
-{
- DialogCameraLevel* pThis = reinterpret_cast(pUserData);
- if (pThis && pLaserLinePoint) {
- pThis->DetectionCallback(eDataType, pLaserLinePoint);
- }
-}
-
-void DialogCameraLevel::StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
-{
- DialogCameraLevel* pThis = reinterpret_cast(pInfoParam);
- if (pThis) {
- pThis->StatusCallback(eStatus, pExtData, nDataLength, pInfoParam);
- }
-}
-
-void DialogCameraLevel::StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
-{
- LOG_DEBUG("[Leveling Status Callback] received: status=%d\n", (int)eStatus);
-
- switch (eStatus) {
- case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
- {
- LOG_INFO("[Leveling Status Callback] Camera swing finished, scan completed\n");
- m_swingFinished = true;
- break;
- }
- default:
- LOG_DEBUG("[Leveling Status Callback] Other status: %d\n", (int)eStatus);
- break;
- }
-}
-
-void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
-{
- if (!pLaserLinePoint) {
- LOG_WARNING("[Leveling Callback] pLaserLinePoint is null\n");
- return;
- }
-
- if (pLaserLinePoint->nPointCount <= 0) {
- LOG_WARNING("[Leveling Callback] Point count is zero or negative: %d\n", pLaserLinePoint->nPointCount);
- return;
- }
-
- if (!pLaserLinePoint->p3DPoint) {
- LOG_WARNING("[Leveling Callback] p3DPoint is null\n");
- return;
- }
-
- // 将数据添加到缓存
- std::vector lineData;
- lineData.reserve(pLaserLinePoint->nPointCount);
-
- // p3DPoint 是 void*,需要转换为 SVzNL3DPosition*
- SVzNL3DPosition* p3DPoints = reinterpret_cast(pLaserLinePoint->p3DPoint);
- for (int i = 0; i < pLaserLinePoint->nPointCount; ++i) {
- lineData.push_back(p3DPoints[i]);
- }
-
- std::lock_guard lock(m_scanDataMutex);
- m_scanDataCache.push_back(std::move(lineData));
-}
-
-bool DialogCameraLevel::calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9])
-{
- std::lock_guard lock(m_scanDataMutex);
-
- if (m_scanDataCache.empty()) {
- LOG_ERROR("No scan data available for plane calibration\n");
- return false;
- }
-
- LOG_INFO("Calculating plane calibration from %zu scan lines\n", m_scanDataCache.size());
-
- try {
- // 调用 wheelArchHeigthMeasure SDK 的调平算法
- SSG_planeCalibPara calibResult = wd_horizonCamera_getGroundCalibPara(m_scanDataCache);
-
- // 复制调平矩阵
- for (int i = 0; i < 9; i++) {
- planeCalib[i] = calibResult.planeCalib[i];
- invRMatrix[i] = calibResult.invRMatrix[i];
- }
- planeHeight = calibResult.planeHeight;
-
- LOG_INFO("Plane calibration calculated successfully\n");
- LOG_INFO(" planeHeight: %.3f\n", planeHeight);
- LOG_INFO(" planeCalib: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
- planeCalib[0], planeCalib[1], planeCalib[2],
- planeCalib[3], planeCalib[4], planeCalib[5],
- planeCalib[6], planeCalib[7], planeCalib[8]);
- LOG_INFO(" invRMatrix: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
- invRMatrix[0], invRMatrix[1], invRMatrix[2],
- invRMatrix[3], invRMatrix[4], invRMatrix[5],
- invRMatrix[6], invRMatrix[7], invRMatrix[8]);
-
- return true;
-
- } catch (const std::exception& e) {
- LOG_ERROR("Exception in calculatePlaneCalibration: %s\n", e.what());
- return false;
- }
-}
-
-void DialogCameraLevel::clearScanDataCache()
-{
- std::lock_guard lock(m_scanDataMutex);
-
- LOG_DEBUG("Clearing scan data cache, current size: %zu\n", m_scanDataCache.size());
- m_scanDataCache.clear();
- LOG_DEBUG("Scan data cache cleared successfully\n");
-}
-
-bool DialogCameraLevel::saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
- int cameraIndex, const QString& cameraName)
-{
- try {
- if (!m_pConfig || !m_pConfigResult) {
- LOG_ERROR("Config is null, cannot save leveling results\n");
- return false;
- }
-
- if (cameraIndex <= 0) {
- LOG_ERROR("Invalid camera index: %d\n", cameraIndex);
- return false;
- }
-
- if (cameraName.isEmpty()) {
- LOG_ERROR("Camera name is empty\n");
- return false;
- }
-
- // 获取UI中的误差补偿值
- double errorCompensation = ui->edit_error_compensation->text().toDouble();
-
- // 创建或更新相机调平参数
- WheelCameraPlaneCalibParam cameraParam;
- cameraParam.cameraIndex = cameraIndex;
- cameraParam.cameraName = cameraName.toStdString();
- cameraParam.planeHeight = planeHeight;
- cameraParam.isCalibrated = true;
- cameraParam.errorCompensation = errorCompensation;
-
- // 复制校准矩阵
- for (int i = 0; i < 9; i++) {
- cameraParam.planeCalib[i] = planeCalib[i];
- cameraParam.invRMatrix[i] = invRMatrix[i];
- }
-
- // 查找是否已有该相机的调平参数
- bool found = false;
- for (auto& param : m_pConfigResult->planeCalibParams) {
- if (param.cameraIndex == cameraIndex) {
- param = cameraParam;
- found = true;
- break;
- }
- }
-
- if (!found) {
- m_pConfigResult->planeCalibParams.push_back(cameraParam);
- }
-
- // 保存配置
- QString configPath = PathManager::GetInstance().GetConfigFilePath();
- bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
- if (!saveResult) {
- LOG_ERROR("Failed to save config with leveling results\n");
- return false;
- }
-
- LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
- cameraIndex, cameraName.toUtf8().constData());
- LOG_INFO("Plane height: %.3f, Error compensation: %.2f\n", planeHeight, errorCompensation);
-
- return true;
-
- } catch (const std::exception& e) {
- LOG_ERROR("Exception in saveLevelingResults: %s\n", e.what());
- return false;
- }
-}
-
-bool DialogCameraLevel::loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
- double planeCalib[9], double& planeHeight, double invRMatrix[9])
-{
- try {
- if (!m_pConfigResult) {
- LOG_ERROR("Config result is null, cannot load calibration data\n");
- return false;
- }
-
- // 查找对应相机的调平参数
- for (const auto& param : m_pConfigResult->planeCalibParams) {
- if (param.cameraIndex == cameraIndex && param.isCalibrated) {
- for (int i = 0; i < 9; i++) {
- planeCalib[i] = param.planeCalib[i];
- invRMatrix[i] = param.invRMatrix[i];
- }
- planeHeight = param.planeHeight;
-
- // 加载该相机的误差补偿值到UI
- ui->edit_error_compensation->setText(QString::number(param.errorCompensation, 'f', 1));
-
- LOG_INFO("Calibration data loaded successfully for camera %d (%s)\n",
- cameraIndex, cameraName.toUtf8().constData());
- return true;
- }
- }
-
- // 没有找到标定数据时,设置默认误差补偿值
- ui->edit_error_compensation->setText(QString::number(-5.0, 'f', 1));
-
- LOG_INFO("No calibration data found for camera %d (%s)\n",
- cameraIndex, cameraName.toUtf8().constData());
- return false;
-
- } catch (const std::exception& e) {
- LOG_ERROR("Exception in loadCameraCalibrationData: %s\n", e.what());
- return false;
- }
-}
-
-void DialogCameraLevel::checkAndDisplayCalibrationStatus(int cameraIndex)
-{
- if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
- LOG_WARNING("Invalid camera index for status check: %d\n", cameraIndex);
- ui->label_level_result->setText("无效的相机索引");
- ui->label_level_result->setAlignment(Qt::AlignCenter);
- return;
- }
-
- QString cameraName = QString::fromStdString(m_cameraList[cameraIndex].first);
- int configCameraIndex = cameraIndex + 1;
-
- double planeCalib[9];
- double planeHeight;
- double invRMatrix[9];
-
- if (loadCameraCalibrationData(configCameraIndex, cameraName, planeCalib, planeHeight, invRMatrix)) {
- // 有标定数据,显示
- LOG_INFO("Displaying existing calibration data for camera %s\n", cameraName.toUtf8().constData());
- updateLevelingResults(planeCalib, planeHeight, invRMatrix);
- } else {
- // 没有标定数据
- LOG_INFO("No calibration data found for camera %s\n", cameraName.toUtf8().constData());
- ui->label_level_result->setText(QString("相机: %1\n\n请点击调平按钮开始调平操作").arg(cameraName));
- ui->label_level_result->setAlignment(Qt::AlignCenter);
- }
-}
-
-void DialogCameraLevel::on_combo_camera_currentIndexChanged(int index)
-{
- m_currentCameraIndex = index;
-
- if (index >= 0 && index < static_cast(m_cameraList.size())) {
- LOG_INFO("Camera selection changed to index: %d (%s)\n", index,
- QString::fromStdString(m_cameraList[index].first).toUtf8().constData());
-
- checkAndDisplayCalibrationStatus(m_currentCameraIndex);
- } else {
- LOG_WARNING("Invalid camera index selected: %d\n", index);
- ui->label_level_result->setText("无效的相机选择");
- ui->label_level_result->setAlignment(Qt::AlignCenter);
- }
-}
-
-void DialogCameraLevel::setLevelingStatusCallback()
-{
- if (!m_presenter) {
- LOG_ERROR("Presenter is null, cannot set leveling status callback\n");
- return;
- }
-
- m_presenter->SetCameraStatusCallback(&DialogCameraLevel::StaticStatusCallback, this);
-
- m_swingFinished = false;
- m_callbackRestored = false;
-
- LOG_INFO("Leveling status callback set for all cameras\n");
-}
-
-void DialogCameraLevel::restorePresenterStatusCallback()
-{
- if (m_callbackRestored.exchange(true)) {
- LOG_DEBUG("Presenter status callback already restored, skipping\n");
- return;
- }
-
- if (!m_presenter) {
- LOG_ERROR("Presenter is null, cannot restore status callback\n");
- return;
- }
-
- m_presenter->SetCameraStatusCallback(&WheelMeasurePresenter::_StaticCameraNotify, m_presenter);
-
- LOG_INFO("Presenter status callback restored for all cameras\n");
-}
-
-void DialogCameraLevel::on_btn_save_compensation_clicked()
-{
- // 保存误差补偿值到当前相机的调平参数
- if (!m_pConfig || !m_pConfigResult) {
- LOG_ERROR("Config is null, cannot save error compensation\n");
- return;
- }
-
- if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast(m_cameraList.size())) {
- LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
- return;
- }
-
- // 获取UI中的误差补偿值
- double errorCompensation = ui->edit_error_compensation->text().toDouble();
- int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
- QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
-
- LOG_INFO("Saving error compensation for camera %d (%s): %.2f\n",
- cameraIndex, cameraName.toUtf8().constData(), errorCompensation);
-
- // 查找或创建相机调平参数
- bool found = false;
- for (auto& param : m_pConfigResult->planeCalibParams) {
- if (param.cameraIndex == cameraIndex) {
- param.errorCompensation = errorCompensation;
- found = true;
- break;
- }
- }
-
- // 如果没有找到现有记录,创建一个新的(仅包含误差补偿,其他值为默认)
- if (!found) {
- WheelCameraPlaneCalibParam newParam;
- newParam.cameraIndex = cameraIndex;
- newParam.cameraName = cameraName.toStdString();
- newParam.errorCompensation = errorCompensation;
- newParam.isCalibrated = false; // 尚未标定
- m_pConfigResult->planeCalibParams.push_back(newParam);
- }
-
- // 保存配置到文件
- QString configPath = PathManager::GetInstance().GetConfigFilePath();
- bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
- if (saveResult) {
- LOG_INFO("Error compensation saved successfully for camera %d: %.2f\n", cameraIndex, errorCompensation);
- } else {
- LOG_ERROR("Failed to save error compensation\n");
- }
-}
+#include "dialogcameralevel.h"
+#include "ui_dialogcameralevel.h"
+#include "WheelMeasurePresenter.h"
+#include "PathManager.h"
+#include "VrLog.h"
+#include "wheelArchHeigthMeasure_Export.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+DialogCameraLevel::DialogCameraLevel(QWidget *parent)
+ : QDialog(parent)
+ , ui(new Ui::DialogCameraLevel)
+ , m_pConfig(nullptr)
+ , m_pConfigResult(nullptr)
+ , m_currentCameraIndex(-1)
+{
+ ui->setupUi(this);
+
+ // 初始化结果显示区域
+ ui->label_level_result->setText("请选择相机,然后点击调平按钮\n开始相机调平操作");
+ ui->label_level_result->setAlignment(Qt::AlignCenter);
+}
+
+DialogCameraLevel::~DialogCameraLevel()
+{
+ // 清理扫描数据缓存
+ clearScanDataCache();
+
+ // 确保恢复Presenter的状态回调
+ restorePresenterStatusCallback();
+
+ delete ui;
+}
+
+void DialogCameraLevel::setCameraList(const std::vector>& cameraList,
+ WheelMeasurePresenter* presenter)
+{
+ m_cameraList = cameraList;
+ m_presenter = presenter;
+
+ LOG_INFO("setCameraList called with %zu cameras\n", cameraList.size());
+
+ // 详细记录每个相机的信息
+ for (size_t i = 0; i < cameraList.size(); ++i) {
+ const auto& camera = cameraList[i];
+ LOG_INFO(" Camera %zu: name='%s', device=%s\n",
+ i + 1,
+ camera.first.c_str(),
+ (camera.second != nullptr ? "connected" : "not connected"));
+ }
+
+ // 初始化/重新初始化相机选择框
+ initializeCameraCombo();
+}
+
+void DialogCameraLevel::setConfig(IVrWheelMeasureConfig* config, WheelMeasureConfigResult* configResult)
+{
+ m_pConfig = config;
+ m_pConfigResult = configResult;
+
+ // 如果相机已经选择,重新加载当前相机的标定状态
+ // 修复:打开页面时配置可能在相机列表之后设置,导致初始加载失败
+ if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast(m_cameraList.size())) {
+ checkAndDisplayCalibrationStatus(m_currentCameraIndex);
+ loadCameraRoiRange(m_currentCameraIndex);
+ }
+}
+
+void DialogCameraLevel::initializeCameraCombo()
+{
+ LOG_INFO("initializeCameraCombo called, camera list size: %zu\n", m_cameraList.size());
+
+ ui->combo_camera->clear();
+
+ if (m_cameraList.empty()) {
+ ui->combo_camera->setEnabled(false);
+
+ if (!m_presenter) {
+ ui->label_level_result->setText("Presenter未初始化\n无法获取相机列表");
+ LOG_ERROR("Presenter is null in initializeCameraCombo\n");
+ } else {
+ ui->label_level_result->setText("相机列表为空\n\n可能原因:\n1. 配置文件中未配置相机\n2. 系统正在初始化中\n3. 所有相机连接失败");
+ LOG_WARNING("Camera list is empty in initializeCameraCombo\n");
+ }
+
+ ui->label_level_result->setAlignment(Qt::AlignCenter);
+ } else {
+ LOG_INFO("Adding %zu cameras to combo box\n", m_cameraList.size());
+
+ // 添加所有相机到下拉列表
+ for (size_t i = 0; i < m_cameraList.size(); ++i) {
+ const auto& camera = m_cameraList[i];
+ QString cameraName = QString::fromStdString(camera.first);
+
+ // 如果相机没有连接,在名称后添加标记
+ if (camera.second == nullptr) {
+ cameraName += " [未连接]";
+ }
+
+ ui->combo_camera->addItem(cameraName);
+ LOG_INFO(" Added camera %zu: %s (device=%s)\n",
+ i + 1,
+ camera.first.c_str(),
+ (camera.second != nullptr ? "OK" : "NULL"));
+ }
+ ui->combo_camera->setEnabled(true);
+
+ // 获取默认相机索引
+ int defaultCameraIndex = 0;
+ if (m_presenter) {
+ int presenterDefaultIndex = m_presenter->GetDefaultCameraIndex();
+ LOG_INFO("Presenter default camera index (1-based): %d\n", presenterDefaultIndex);
+
+ if (presenterDefaultIndex > 0 && presenterDefaultIndex <= static_cast(m_cameraList.size())) {
+ defaultCameraIndex = presenterDefaultIndex - 1;
+ }
+ }
+
+ // 设置默认选中的相机
+ if (defaultCameraIndex >= 0 && defaultCameraIndex < static_cast(m_cameraList.size())) {
+ ui->combo_camera->setCurrentIndex(defaultCameraIndex);
+ m_currentCameraIndex = defaultCameraIndex;
+ }
+
+ // 检查并显示当前选中相机的标定状态
+ if (m_currentCameraIndex >= 0) {
+ checkAndDisplayCalibrationStatus(m_currentCameraIndex);
+ }
+ }
+}
+
+void DialogCameraLevel::on_btn_apply_clicked()
+{
+ ui->label_level_result->setAlignment(Qt::AlignLeft);
+
+ // 检查是否有可用的相机
+ if (m_cameraList.empty()) {
+ QMessageBox::warning(this, "错误", "无可用相机设备!");
+ return;
+ }
+
+ // 获取选中的相机
+ int selectedIndex = ui->combo_camera->currentIndex();
+ if (selectedIndex < 0 || selectedIndex >= static_cast(m_cameraList.size())) {
+ QMessageBox::warning(this, "错误", "请选择有效的相机!");
+ return;
+ }
+
+ // 清空之前的结果显示
+ ui->label_level_result->setText("调平计算中,请稍候...");
+
+ // 显示进度提示
+ ui->btn_apply->setEnabled(false);
+ QApplication::processEvents();
+
+ try {
+ // 执行相机调平
+ if (performCameraLeveling()) {
+ // 调平成功
+ } else {
+ ui->label_level_result->setText("调平失败!\n\n请检查:\n1. 相机连接是否正常\n2. 地面扫描数据是否充足\n3. 扫描区域是否有足够的地面");
+ }
+ } catch (const std::exception& e) {
+ LOG_ERROR("Camera leveling failed with exception: %s\n", e.what());
+ QMessageBox::critical(this, "错误", QString("调平过程发生异常:%1").arg(e.what()));
+ }
+
+ // 恢复按钮状态
+ ui->btn_apply->setEnabled(true);
+}
+
+void DialogCameraLevel::on_btn_cancel_clicked()
+{
+ reject();
+}
+
+bool DialogCameraLevel::performCameraLeveling()
+{
+ try {
+ // 获取选中的相机索引
+ int selectedIndex = ui->combo_camera->currentIndex();
+
+ // 先检查索引有效性,再设置回调
+ if (selectedIndex < 0 || selectedIndex >= static_cast(m_cameraList.size())) {
+ LOG_ERROR("Invalid camera index: %d\n", selectedIndex);
+ return false;
+ }
+
+ LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex);
+
+ // 1. 设置调平状态回调(在索引检查之后)
+ setLevelingStatusCallback();
+
+ // 2. 清空之前的扫描数据
+ clearScanDataCache();
+
+ // 3. 启动相机扫描地面数据
+ if (!startCameraScan(selectedIndex)) {
+ LOG_ERROR("Failed to start camera scan for leveling\n");
+ restorePresenterStatusCallback(); // 恢复回调
+ return false;
+ }
+
+ // 4. 等待扫描完成
+ LOG_INFO("Collecting ground scan data, waiting for swing finish signal...\n");
+ int waitTime = 0;
+ const int maxWaitTime = 10000; // 最大等待10秒
+ const int checkInterval = 100;
+
+ while (!m_swingFinished && waitTime < maxWaitTime) {
+ QThread::msleep(checkInterval);
+ QApplication::processEvents();
+ waitTime += checkInterval;
+ }
+
+ // 5. 停止扫描
+ stopCameraScan(selectedIndex);
+
+ if (m_swingFinished) {
+ LOG_INFO("Camera swing finished signal received, scan completed\n");
+ } else if (waitTime >= maxWaitTime) {
+ LOG_WARNING("Timeout waiting for camera swing finish signal\n");
+ }
+
+ // 6. 调用调平算法计算
+ double planeCalib[9];
+ double planeHeight;
+ double invRMatrix[9];
+
+ if (!calculatePlaneCalibration(planeCalib, planeHeight, invRMatrix)) {
+ LOG_ERROR("Failed to calculate plane calibration\n");
+ restorePresenterStatusCallback(); // 恢复回调
+ return false;
+ }
+
+ LOG_INFO("Camera leveling calculation completed\n");
+
+ // 7. 更新界面显示
+ updateLevelingResults(planeCalib, planeHeight, invRMatrix);
+
+ // 8. 保存结果到配置
+ int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
+ QString cameraName;
+
+ if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast(m_cameraList.size())) {
+ cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
+ } else {
+ cameraName = QString("Camera_%1").arg(cameraIndex);
+ }
+
+ if (!saveLevelingResults(planeCalib, planeHeight, invRMatrix, cameraIndex, cameraName)) {
+ LOG_ERROR("Failed to save leveling results\n");
+ restorePresenterStatusCallback(); // 恢复回调
+ return false;
+ }
+
+ clearScanDataCache();
+
+ // 9. 调平完成后恢复回调
+ restorePresenterStatusCallback();
+
+ LOG_INFO("Camera leveling completed successfully\n");
+
+ return true;
+
+ } catch (const std::exception& e) {
+ LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what());
+ restorePresenterStatusCallback(); // 异常时也恢复回调
+ return false;
+ }
+}
+
+void DialogCameraLevel::updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9])
+{
+ // 构建显示文本
+ QString resultText;
+
+ resultText += QString("地面高度: %1 mm\n").arg(QString::number(planeHeight, 'f', 2));
+
+ // 调平矩阵
+ resultText += QString("调平矩阵:\n");
+ for (int i = 0; i < 3; i++) {
+ resultText += QString("[%1, %2, %3]\n")
+ .arg(QString::number(planeCalib[i*3], 'f', 4))
+ .arg(QString::number(planeCalib[i*3+1], 'f', 4))
+ .arg(QString::number(planeCalib[i*3+2], 'f', 4));
+ }
+
+ resultText += QString("逆旋转矩阵:\n");
+ for (int i = 0; i < 3; i++) {
+ resultText += QString("[%1, %2, %3]\n")
+ .arg(QString::number(invRMatrix[i*3], 'f', 4))
+ .arg(QString::number(invRMatrix[i*3+1], 'f', 4))
+ .arg(QString::number(invRMatrix[i*3+2], 'f', 4));
+ }
+
+ ui->label_level_result->setText(resultText);
+ ui->label_level_result->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+}
+
+bool DialogCameraLevel::startCameraScan(int cameraIndex)
+{
+ if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_ERROR("Invalid camera index for scan: %d\n", cameraIndex);
+ return false;
+ }
+
+ IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
+ if (!camera) {
+ LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
+ return false;
+ }
+
+ // 启动相机检测
+ int result = camera->StartDetect(&DialogCameraLevel::StaticDetectionCallback, keResultDataType_Position, this);
+ if (result != 0) {
+ LOG_ERROR("Failed to start camera detection: %d\n", result);
+ return false;
+ }
+
+ LOG_INFO("Camera scan started successfully for camera index: %d\n", cameraIndex);
+ return true;
+}
+
+bool DialogCameraLevel::stopCameraScan(int cameraIndex)
+{
+ if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_ERROR("Invalid camera index for stop scan: %d\n", cameraIndex);
+ return false;
+ }
+
+ IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
+ if (!camera) {
+ LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
+ return false;
+ }
+
+ int result = camera->StopDetect();
+ if (result != 0) {
+ LOG_WARNING("Failed to stop camera detection, error: %d\n", result);
+ return false;
+ }
+
+ LOG_INFO("Camera scan stopped successfully for camera index: %d\n", cameraIndex);
+ return true;
+}
+
+void DialogCameraLevel::StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData)
+{
+ DialogCameraLevel* pThis = reinterpret_cast(pUserData);
+ if (pThis && pLaserLinePoint) {
+ pThis->DetectionCallback(eDataType, pLaserLinePoint);
+ }
+}
+
+void DialogCameraLevel::StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
+{
+ DialogCameraLevel* pThis = reinterpret_cast(pInfoParam);
+ if (pThis) {
+ pThis->StatusCallback(eStatus, pExtData, nDataLength, pInfoParam);
+ }
+}
+
+void DialogCameraLevel::StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
+{
+ LOG_DEBUG("[Leveling Status Callback] received: status=%d\n", (int)eStatus);
+
+ switch (eStatus) {
+ case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
+ {
+ LOG_INFO("[Leveling Status Callback] Camera swing finished, scan completed\n");
+ m_swingFinished = true;
+ break;
+ }
+ default:
+ LOG_DEBUG("[Leveling Status Callback] Other status: %d\n", (int)eStatus);
+ break;
+ }
+}
+
+void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
+{
+ if (!pLaserLinePoint) {
+ LOG_WARNING("[Leveling Callback] pLaserLinePoint is null\n");
+ return;
+ }
+
+ if (pLaserLinePoint->nPointCount <= 0) {
+ LOG_WARNING("[Leveling Callback] Point count is zero or negative: %d\n", pLaserLinePoint->nPointCount);
+ return;
+ }
+
+ if (!pLaserLinePoint->p3DPoint) {
+ LOG_WARNING("[Leveling Callback] p3DPoint is null\n");
+ return;
+ }
+
+ // 将数据添加到缓存
+ std::vector lineData;
+ lineData.reserve(pLaserLinePoint->nPointCount);
+
+ // p3DPoint 是 void*,需要转换为 SVzNL3DPosition*
+ SVzNL3DPosition* p3DPoints = reinterpret_cast(pLaserLinePoint->p3DPoint);
+ for (int i = 0; i < pLaserLinePoint->nPointCount; ++i) {
+ lineData.push_back(p3DPoints[i]);
+ }
+
+ std::lock_guard lock(m_scanDataMutex);
+ m_scanDataCache.push_back(std::move(lineData));
+}
+
+bool DialogCameraLevel::calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9])
+{
+ std::lock_guard lock(m_scanDataMutex);
+
+ if (m_scanDataCache.empty()) {
+ LOG_ERROR("No scan data available for plane calibration\n");
+ return false;
+ }
+
+ LOG_INFO("Calculating plane calibration from %zu scan lines\n", m_scanDataCache.size());
+
+ try {
+ // 调用 wheelArchHeigthMeasure SDK 的调平算法
+ SSG_planeCalibPara calibResult = wd_horizonCamera_getGroundCalibPara(m_scanDataCache);
+
+ // 复制调平矩阵
+ for (int i = 0; i < 9; i++) {
+ planeCalib[i] = calibResult.planeCalib[i];
+ invRMatrix[i] = calibResult.invRMatrix[i];
+ }
+ planeHeight = calibResult.planeHeight;
+
+ LOG_INFO("Plane calibration calculated successfully\n");
+ LOG_INFO(" planeHeight: %.3f\n", planeHeight);
+ LOG_INFO(" planeCalib: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
+ planeCalib[0], planeCalib[1], planeCalib[2],
+ planeCalib[3], planeCalib[4], planeCalib[5],
+ planeCalib[6], planeCalib[7], planeCalib[8]);
+ LOG_INFO(" invRMatrix: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
+ invRMatrix[0], invRMatrix[1], invRMatrix[2],
+ invRMatrix[3], invRMatrix[4], invRMatrix[5],
+ invRMatrix[6], invRMatrix[7], invRMatrix[8]);
+
+ return true;
+
+ } catch (const std::exception& e) {
+ LOG_ERROR("Exception in calculatePlaneCalibration: %s\n", e.what());
+ return false;
+ }
+}
+
+void DialogCameraLevel::clearScanDataCache()
+{
+ std::lock_guard lock(m_scanDataMutex);
+
+ LOG_DEBUG("Clearing scan data cache, current size: %zu\n", m_scanDataCache.size());
+ m_scanDataCache.clear();
+ LOG_DEBUG("Scan data cache cleared successfully\n");
+}
+
+bool DialogCameraLevel::saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
+ int cameraIndex, const QString& cameraName)
+{
+ try {
+ if (!m_pConfig || !m_pConfigResult) {
+ LOG_ERROR("Config is null, cannot save leveling results\n");
+ return false;
+ }
+
+ if (cameraIndex <= 0) {
+ LOG_ERROR("Invalid camera index: %d\n", cameraIndex);
+ return false;
+ }
+
+ if (cameraName.isEmpty()) {
+ LOG_ERROR("Camera name is empty\n");
+ return false;
+ }
+
+ // 获取UI中的误差补偿值
+ double errorCompensation = ui->edit_error_compensation->text().toDouble();
+
+ // 创建或更新相机调平参数
+ WheelCameraPlaneCalibParam cameraParam;
+ cameraParam.cameraIndex = cameraIndex;
+ cameraParam.cameraName = cameraName.toStdString();
+ cameraParam.planeHeight = planeHeight;
+ cameraParam.isCalibrated = true;
+ cameraParam.errorCompensation = errorCompensation;
+
+ // 复制校准矩阵
+ for (int i = 0; i < 9; i++) {
+ cameraParam.planeCalib[i] = planeCalib[i];
+ cameraParam.invRMatrix[i] = invRMatrix[i];
+ }
+
+ // 查找是否已有该相机的调平参数
+ bool found = false;
+ for (auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == cameraIndex) {
+ param = cameraParam;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ m_pConfigResult->planeCalibParams.push_back(cameraParam);
+ }
+
+ // 保存配置
+ QString configPath = PathManager::GetInstance().GetConfigFilePath();
+ bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
+ if (!saveResult) {
+ LOG_ERROR("Failed to save config with leveling results\n");
+ return false;
+ }
+
+ LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
+ cameraIndex, cameraName.toUtf8().constData());
+ LOG_INFO("Plane height: %.3f, Error compensation: %.2f\n", planeHeight, errorCompensation);
+
+ return true;
+
+ } catch (const std::exception& e) {
+ LOG_ERROR("Exception in saveLevelingResults: %s\n", e.what());
+ return false;
+ }
+}
+
+bool DialogCameraLevel::loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
+ double planeCalib[9], double& planeHeight, double invRMatrix[9])
+{
+ try {
+ if (!m_pConfigResult) {
+ LOG_ERROR("Config result is null, cannot load calibration data\n");
+ return false;
+ }
+
+ // 查找对应相机的调平参数
+ for (const auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == cameraIndex && param.isCalibrated) {
+ for (int i = 0; i < 9; i++) {
+ planeCalib[i] = param.planeCalib[i];
+ invRMatrix[i] = param.invRMatrix[i];
+ }
+ planeHeight = param.planeHeight;
+
+ // 加载该相机的误差补偿值到UI
+ ui->edit_error_compensation->setText(QString::number(param.errorCompensation, 'f', 1));
+
+ LOG_INFO("Calibration data loaded successfully for camera %d (%s)\n",
+ cameraIndex, cameraName.toUtf8().constData());
+ return true;
+ }
+ }
+
+ // 没有找到标定数据时,设置默认误差补偿值
+ ui->edit_error_compensation->setText(QString::number(-5.0, 'f', 1));
+
+ LOG_INFO("No calibration data found for camera %d (%s)\n",
+ cameraIndex, cameraName.toUtf8().constData());
+ return false;
+
+ } catch (const std::exception& e) {
+ LOG_ERROR("Exception in loadCameraCalibrationData: %s\n", e.what());
+ return false;
+ }
+}
+
+void DialogCameraLevel::checkAndDisplayCalibrationStatus(int cameraIndex)
+{
+ if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_WARNING("Invalid camera index for status check: %d\n", cameraIndex);
+ ui->label_level_result->setText("无效的相机索引");
+ ui->label_level_result->setAlignment(Qt::AlignCenter);
+ return;
+ }
+
+ QString cameraName = QString::fromStdString(m_cameraList[cameraIndex].first);
+ int configCameraIndex = cameraIndex + 1;
+
+ double planeCalib[9];
+ double planeHeight;
+ double invRMatrix[9];
+
+ if (loadCameraCalibrationData(configCameraIndex, cameraName, planeCalib, planeHeight, invRMatrix)) {
+ // 有标定数据,显示
+ LOG_INFO("Displaying existing calibration data for camera %s\n", cameraName.toUtf8().constData());
+ updateLevelingResults(planeCalib, planeHeight, invRMatrix);
+ } else {
+ // 没有标定数据
+ LOG_INFO("No calibration data found for camera %s\n", cameraName.toUtf8().constData());
+ ui->label_level_result->setText(QString("相机: %1\n\n请点击调平按钮开始调平操作").arg(cameraName));
+ ui->label_level_result->setAlignment(Qt::AlignCenter);
+ }
+}
+
+void DialogCameraLevel::on_combo_camera_currentIndexChanged(int index)
+{
+ m_currentCameraIndex = index;
+
+ if (index >= 0 && index < static_cast(m_cameraList.size())) {
+ LOG_INFO("Camera selection changed to index: %d (%s)\n", index,
+ QString::fromStdString(m_cameraList[index].first).toUtf8().constData());
+
+ checkAndDisplayCalibrationStatus(m_currentCameraIndex);
+ loadCameraRoiRange(m_currentCameraIndex);
+ } else {
+ LOG_WARNING("Invalid camera index selected: %d\n", index);
+ ui->label_level_result->setText("无效的相机选择");
+ ui->label_level_result->setAlignment(Qt::AlignCenter);
+ }
+}
+
+void DialogCameraLevel::setLevelingStatusCallback()
+{
+ if (!m_presenter) {
+ LOG_ERROR("Presenter is null, cannot set leveling status callback\n");
+ return;
+ }
+
+ m_presenter->SetCameraStatusCallback(&DialogCameraLevel::StaticStatusCallback, this);
+
+ m_swingFinished = false;
+ m_callbackRestored = false;
+
+ LOG_INFO("Leveling status callback set for all cameras\n");
+}
+
+void DialogCameraLevel::restorePresenterStatusCallback()
+{
+ if (m_callbackRestored.exchange(true)) {
+ LOG_DEBUG("Presenter status callback already restored, skipping\n");
+ return;
+ }
+
+ if (!m_presenter) {
+ LOG_ERROR("Presenter is null, cannot restore status callback\n");
+ return;
+ }
+
+ m_presenter->SetCameraStatusCallback(&WheelMeasurePresenter::_StaticCameraNotify, m_presenter);
+
+ LOG_INFO("Presenter status callback restored for all cameras\n");
+}
+
+void DialogCameraLevel::on_btn_save_compensation_clicked()
+{
+ // 保存误差补偿值到当前相机的调平参数
+ if (!m_pConfig || !m_pConfigResult) {
+ LOG_ERROR("Config is null, cannot save error compensation\n");
+ return;
+ }
+
+ if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
+ return;
+ }
+
+ // 获取UI中的误差补偿值
+ double errorCompensation = ui->edit_error_compensation->text().toDouble();
+ int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
+ QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
+
+ LOG_INFO("Saving error compensation for camera %d (%s): %.2f\n",
+ cameraIndex, cameraName.toUtf8().constData(), errorCompensation);
+
+ // 查找或创建相机调平参数
+ bool found = false;
+ for (auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == cameraIndex) {
+ param.errorCompensation = errorCompensation;
+ found = true;
+ break;
+ }
+ }
+
+ // 如果没有找到现有记录,创建一个新的(仅包含误差补偿,其他值为默认)
+ if (!found) {
+ WheelCameraPlaneCalibParam newParam;
+ newParam.cameraIndex = cameraIndex;
+ newParam.cameraName = cameraName.toStdString();
+ newParam.errorCompensation = errorCompensation;
+ newParam.isCalibrated = false; // 尚未标定
+ m_pConfigResult->planeCalibParams.push_back(newParam);
+ }
+
+ // 保存配置到文件
+ QString configPath = PathManager::GetInstance().GetConfigFilePath();
+ bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
+ if (saveResult) {
+ LOG_INFO("Error compensation saved successfully for camera %d: %.2f\n", cameraIndex, errorCompensation);
+ } else {
+ LOG_ERROR("Failed to save error compensation\n");
+ }
+}
+
+void DialogCameraLevel::loadCameraRoiRange(int cameraIndex)
+{
+ if (!m_pConfig || !m_pConfigResult) {
+ LOG_WARNING("Config is null, cannot load ROI range\n");
+ return;
+ }
+
+ if (cameraIndex < 0 || cameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_WARNING("Invalid camera index: %d\n", cameraIndex);
+ return;
+ }
+
+ int configCameraIndex = cameraIndex + 1; // 转换为1-based索引
+
+ // 查找相机的调平参数
+ for (const auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == configCameraIndex) {
+ // 加载ROI范围到UI
+ ui->edit_roi_x_min->setText(QString::number(param.wheelRoi3d_xMin, 'f', 1));
+ ui->edit_roi_x_max->setText(QString::number(param.wheelRoi3d_xMax, 'f', 1));
+ ui->edit_roi_y_min->setText(QString::number(param.wheelRoi3d_yMin, 'f', 1));
+ ui->edit_roi_y_max->setText(QString::number(param.wheelRoi3d_yMax, 'f', 1));
+ ui->edit_roi_z_min->setText(QString::number(param.wheelRoi3d_zMin, 'f', 1));
+ ui->edit_roi_z_max->setText(QString::number(param.wheelRoi3d_zMax, 'f', 1));
+
+ LOG_INFO("Loaded ROI range for camera %d: X[%.1f, %.1f], Y[%.1f, %.1f], Z[%.1f, %.1f]\n",
+ configCameraIndex,
+ param.wheelRoi3d_xMin, param.wheelRoi3d_xMax,
+ param.wheelRoi3d_yMin, param.wheelRoi3d_yMax,
+ param.wheelRoi3d_zMin, param.wheelRoi3d_zMax);
+ return;
+ }
+ }
+
+ // 如果没有找到,使用默认值
+ ui->edit_roi_x_min->setText("-1000.0");
+ ui->edit_roi_x_max->setText("1000.0");
+ ui->edit_roi_y_min->setText("-1000.0");
+ ui->edit_roi_y_max->setText("1000.0");
+ ui->edit_roi_z_min->setText("-1000.0");
+ ui->edit_roi_z_max->setText("1000.0");
+ LOG_INFO("No ROI range found for camera %d, using default values\n", configCameraIndex);
+}
+
+void DialogCameraLevel::saveCameraRoiRange()
+{
+ if (!m_pConfig || !m_pConfigResult) {
+ LOG_ERROR("Config is null, cannot save ROI range\n");
+ QMessageBox::warning(this, "错误", "配置对象为空,无法保存ROI范围");
+ return;
+ }
+
+ if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast(m_cameraList.size())) {
+ LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
+ QMessageBox::warning(this, "错误", "请先选择相机");
+ return;
+ }
+
+ // 获取UI中的ROI范围值
+ double xMin = ui->edit_roi_x_min->text().toDouble();
+ double xMax = ui->edit_roi_x_max->text().toDouble();
+ double yMin = ui->edit_roi_y_min->text().toDouble();
+ double yMax = ui->edit_roi_y_max->text().toDouble();
+ double zMin = ui->edit_roi_z_min->text().toDouble();
+ double zMax = ui->edit_roi_z_max->text().toDouble();
+
+ // 验证范围有效性
+ if (xMin >= xMax || yMin >= yMax || zMin >= zMax) {
+ QMessageBox::warning(this, "错误", "ROI范围无效:最小值必须小于最大值");
+ return;
+ }
+
+ int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
+ QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
+
+ LOG_INFO("Saving ROI range for camera %d (%s): X[%.1f, %.1f], Y[%.1f, %.1f], Z[%.1f, %.1f]\n",
+ cameraIndex, cameraName.toUtf8().constData(),
+ xMin, xMax, yMin, yMax, zMin, zMax);
+
+ // 查找或创建相机调平参数
+ bool found = false;
+ for (auto& param : m_pConfigResult->planeCalibParams) {
+ if (param.cameraIndex == cameraIndex) {
+ param.wheelRoi3d_xMin = xMin;
+ param.wheelRoi3d_xMax = xMax;
+ param.wheelRoi3d_yMin = yMin;
+ param.wheelRoi3d_yMax = yMax;
+ param.wheelRoi3d_zMin = zMin;
+ param.wheelRoi3d_zMax = zMax;
+ found = true;
+ break;
+ }
+ }
+
+ // 如果没有找到现有记录,创建一个新的
+ if (!found) {
+ WheelCameraPlaneCalibParam newParam;
+ newParam.cameraIndex = cameraIndex;
+ newParam.cameraName = cameraName.toStdString();
+ newParam.wheelRoi3d_xMin = xMin;
+ newParam.wheelRoi3d_xMax = xMax;
+ newParam.wheelRoi3d_yMin = yMin;
+ newParam.wheelRoi3d_yMax = yMax;
+ newParam.wheelRoi3d_zMin = zMin;
+ newParam.wheelRoi3d_zMax = zMax;
+ newParam.isCalibrated = false; // 尚未标定
+ m_pConfigResult->planeCalibParams.push_back(newParam);
+ }
+
+ // 保存配置到文件
+ QString configPath = PathManager::GetInstance().GetConfigFilePath();
+ bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
+ if (saveResult) {
+ LOG_INFO("ROI range saved successfully for camera %d\n", cameraIndex);
+ QMessageBox::information(this, "成功", "ROI范围已保存");
+ } else {
+ LOG_ERROR("Failed to save ROI range\n");
+ QMessageBox::critical(this, "错误", "保存ROI范围失败");
+ }
+}
+
+void DialogCameraLevel::on_btn_save_roi_clicked()
+{
+ saveCameraRoiRange();
+}
diff --git a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
index b2ff263d..785d08e3 100644
--- a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
+++ b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.h
@@ -1,118 +1,123 @@
-#ifndef DIALOGCAMERALEVEL_H
-#define DIALOGCAMERALEVEL_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "IVrEyeDevice.h"
-#include "IVrWheelMeasureConfig.h"
-#include "VZNL_Types.h"
-
-// 前向声明
-class WheelMeasurePresenter;
-
-namespace Ui {
-class DialogCameraLevel;
-}
-
-class DialogCameraLevel : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit DialogCameraLevel(QWidget *parent = nullptr);
- ~DialogCameraLevel();
-
- /**
- * @brief 设置相机列表和presenter
- * @param cameraList 相机列表
- * @param presenter Presenter指针
- */
- void setCameraList(const std::vector>& cameraList,
- WheelMeasurePresenter* presenter);
-
- /**
- * @brief 设置配置对象
- * @param config 配置接口
- * @param configResult 配置结果
- */
- void setConfig(IVrWheelMeasureConfig* config, WheelMeasureConfigResult* configResult);
-
-private slots:
- void on_btn_apply_clicked();
- void on_btn_cancel_clicked();
- void on_combo_camera_currentIndexChanged(int index);
- void on_btn_save_compensation_clicked();
-
-private:
- Ui::DialogCameraLevel *ui;
-
- // 相机列表和名称
- std::vector> m_cameraList;
- WheelMeasurePresenter* m_presenter = nullptr;
-
- // 配置对象
- IVrWheelMeasureConfig* m_pConfig = nullptr;
- WheelMeasureConfigResult* m_pConfigResult = nullptr;
-
- // 当前选中的相机索引
- int m_currentCameraIndex = -1;
-
- // 扫描数据缓存
- std::vector> m_scanDataCache;
- std::mutex m_scanDataMutex;
-
- // 状态回调相关
- std::atomic m_swingFinished{false};
- std::atomic m_callbackRestored{false};
-
- // 初始化相机选择框
- void initializeCameraCombo();
-
- // 执行相机调平
- bool performCameraLeveling();
-
- // 直接使用相机接口进行扫描
- bool startCameraScan(int cameraIndex);
- bool stopCameraScan(int cameraIndex);
-
- // 检测数据回调函数
- static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
- void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
-
- // 状态回调函数
- static void StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
- void StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
-
- // 设置和恢复状态回调
- void setLevelingStatusCallback();
- void restorePresenterStatusCallback();
-
- // 处理扫描到的地面数据进行调平计算
- bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]);
-
- // 清空扫描数据缓存
- void clearScanDataCache();
-
- // 更新调平结果显示
- void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]);
-
- // 保存调平结果到配置
- bool saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
- int cameraIndex, const QString& cameraName);
-
- // 加载相机标定数据
- bool loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
- double planeCalib[9], double& planeHeight, double invRMatrix[9]);
-
- // 检查并显示相机标定状态
- void checkAndDisplayCalibrationStatus(int cameraIndex);
-};
-
-#endif // DIALOGCAMERALEVEL_H
+#ifndef DIALOGCAMERALEVEL_H
+#define DIALOGCAMERALEVEL_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "IVrEyeDevice.h"
+#include "IVrWheelMeasureConfig.h"
+#include "VZNL_Types.h"
+
+// 前向声明
+class WheelMeasurePresenter;
+
+namespace Ui {
+class DialogCameraLevel;
+}
+
+class DialogCameraLevel : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DialogCameraLevel(QWidget *parent = nullptr);
+ ~DialogCameraLevel();
+
+ /**
+ * @brief 设置相机列表和presenter
+ * @param cameraList 相机列表
+ * @param presenter Presenter指针
+ */
+ void setCameraList(const std::vector>& cameraList,
+ WheelMeasurePresenter* presenter);
+
+ /**
+ * @brief 设置配置对象
+ * @param config 配置接口
+ * @param configResult 配置结果
+ */
+ void setConfig(IVrWheelMeasureConfig* config, WheelMeasureConfigResult* configResult);
+
+private slots:
+ void on_btn_apply_clicked();
+ void on_btn_cancel_clicked();
+ void on_combo_camera_currentIndexChanged(int index);
+ void on_btn_save_compensation_clicked();
+ void on_btn_save_roi_clicked();
+
+private:
+ Ui::DialogCameraLevel *ui;
+
+ // 相机列表和名称
+ std::vector> m_cameraList;
+ WheelMeasurePresenter* m_presenter = nullptr;
+
+ // 配置对象
+ IVrWheelMeasureConfig* m_pConfig = nullptr;
+ WheelMeasureConfigResult* m_pConfigResult = nullptr;
+
+ // 当前选中的相机索引
+ int m_currentCameraIndex = -1;
+
+ // 扫描数据缓存
+ std::vector> m_scanDataCache;
+ std::mutex m_scanDataMutex;
+
+ // 状态回调相关
+ std::atomic m_swingFinished{false};
+ std::atomic m_callbackRestored{false};
+
+ // 初始化相机选择框
+ void initializeCameraCombo();
+
+ // 执行相机调平
+ bool performCameraLeveling();
+
+ // 直接使用相机接口进行扫描
+ bool startCameraScan(int cameraIndex);
+ bool stopCameraScan(int cameraIndex);
+
+ // 检测数据回调函数
+ static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
+ void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
+
+ // 状态回调函数
+ static void StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
+ void StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
+
+ // 设置和恢复状态回调
+ void setLevelingStatusCallback();
+ void restorePresenterStatusCallback();
+
+ // 处理扫描到的地面数据进行调平计算
+ bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]);
+
+ // 清空扫描数据缓存
+ void clearScanDataCache();
+
+ // 更新调平结果显示
+ void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]);
+
+ // 保存调平结果到配置
+ bool saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
+ int cameraIndex, const QString& cameraName);
+
+ // 加载相机标定数据
+ bool loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
+ double planeCalib[9], double& planeHeight, double invRMatrix[9]);
+
+ // 检查并显示相机标定状态
+ void checkAndDisplayCalibrationStatus(int cameraIndex);
+
+ // 加载和保存ROI范围
+ void loadCameraRoiRange(int cameraIndex);
+ void saveCameraRoiRange();
+};
+
+#endif // DIALOGCAMERALEVEL_H
diff --git a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
index c62508ce..b9378f76 100644
--- a/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
+++ b/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.ui
@@ -1,306 +1,754 @@
-
-
- DialogCameraLevel
-
-
-
- 0
- 0
- 659
- 453
-
-
-
- 相机调平
-
-
- background-color: rgb(25, 26, 28);color: rgb(221, 225, 233);
-
-
-
-
- 20
- 110
- 101
- 31
-
-
-
-
- 16
-
-
-
- color: rgb(221, 225, 233);
-
-
- 调平结果:
-
-
-
-
-
- 20
- 10
- 621
- 45
-
-
-
-
- 18
-
-
-
- color: rgb(221, 225, 233);
-
-
- 相机调平
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
-
-
- 170
- 400
- 101
- 38
-
-
-
-
- 18
-
-
-
- image: url(:/common/resource/dialog_ok.png);
-
-
-
-
-
-
-
-
- 380
- 400
- 111
- 38
-
-
-
-
- 18
-
-
-
- image: url(:/common/resource/dialog_cancel.png);
-
-
-
-
-
-
-
-
- 130
- 110
- 511
- 271
-
-
-
-
- 14
-
-
-
- color: rgb(221, 225, 233);
-background-color: rgb(47, 48, 52);
-border: 1px solid #3B3D47;
-padding: 5px;
-
-
-
-
-
- Qt::AlignCenter
-
-
-
-
-
- 20
- 60
- 634
- 41
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 16
-
-
-
- color: rgb(221, 225, 233);
-
-
- 选择相机:
-
-
-
- -
-
-
-
- 200
- 35
-
-
-
-
- 16
-
-
-
- color: rgb(221, 225, 233);
-background-color: rgb(47, 48, 52);
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 16
-
-
-
- color: rgb(221, 225, 233);
-
-
- 误差补偿:
-
-
-
- -
-
-
-
- 100
- 35
-
-
-
-
- 100
- 16777215
-
-
-
-
- 16
-
-
-
- color: rgb(221, 225, 233);
-background-color: rgb(47, 48, 52);
-
-
- -5.0
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 14
-
-
-
- color: rgb(221, 225, 233);
-
-
- mm
-
-
-
- -
-
-
-
- 60
- 35
-
-
-
-
- 60
- 35
-
-
-
-
- 14
-
-
-
- QPushButton {
- color: rgb(221, 225, 233);
- background-color: rgb(60, 63, 65);
- border: 1px solid #3B3D47;
- border-radius: 4px;
-}
-QPushButton:hover {
- background-color: rgb(80, 83, 85);
-}
-QPushButton:pressed {
- background-color: rgb(45, 48, 50);
-}
-
-
- 保存
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
-
+
+
+ DialogCameraLevel
+
+
+
+ 0
+ 0
+ 659
+ 599
+
+
+
+ 相机调平
+
+
+ background-color: rgb(25, 26, 28);color: rgb(221, 225, 233);
+
+
+
+
+ 20
+ 110
+ 101
+ 31
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ 调平结果:
+
+
+
+
+
+ 20
+ 10
+ 621
+ 45
+
+
+
+
+ 18
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ 相机调平
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+
+
+ 170
+ 550
+ 101
+ 38
+
+
+
+
+ 18
+
+
+
+ image: url(:/common/resource/dialog_ok.png);
+
+
+
+
+
+
+
+
+ 380
+ 550
+ 111
+ 38
+
+
+
+
+ 18
+
+
+
+ image: url(:/common/resource/dialog_cancel.png);
+
+
+
+
+
+
+
+
+ 130
+ 110
+ 511
+ 271
+
+
+
+
+ 14
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+border: 1px solid #3B3D47;
+padding: 5px;
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ 20
+ 60
+ 634
+ 41
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ 选择相机:
+
+
+
+ -
+
+
+
+ 200
+ 35
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ 误差补偿:
+
+
+
+ -
+
+
+
+ 100
+ 35
+
+
+
+
+ 100
+ 16777215
+
+
+
+
+ 16
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ -5.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 14
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ mm
+
+
+
+ -
+
+
+
+ 60
+ 35
+
+
+
+
+ 60
+ 35
+
+
+
+
+ 14
+
+
+
+ QPushButton {
+ color: rgb(221, 225, 233);
+ background-color: rgb(60, 63, 65);
+ border: 1px solid #3B3D47;
+ border-radius: 4px;
+}
+QPushButton:hover {
+ background-color: rgb(80, 83, 85);
+}
+QPushButton:pressed {
+ background-color: rgb(45, 48, 50);
+}
+
+
+ 保存
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+ 20
+ 390
+ 621
+ 150
+
+
+
+
+ 14
+
+
+
+ QGroupBox {
+ color: rgb(221, 225, 233);
+ border: 1px solid #3B3D47;
+ border-radius: 4px;
+ margin-top: 10px;
+ padding-top: 10px;
+}
+QGroupBox::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding: 0 5px;
+}
+
+
+ 轮胎存在检测ROI范围 (mm)
+
+
+
+ 15
+
+
+ 15
+
+ -
+
+
+
+ 20
+ 0
+
+
+
+
+ 20
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ ~
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ -1000.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 80
+ 35
+
+
+
+
+ 80
+ 35
+
+
+
+
+ 14
+
+
+
+ QPushButton {
+ color: rgb(221, 225, 233);
+ background-color: rgb(60, 63, 65);
+ border: 1px solid #3B3D47;
+ border-radius: 4px;
+}
+QPushButton:hover {
+ background-color: rgb(80, 83, 85);
+}
+QPushButton:pressed {
+ background-color: rgb(45, 48, 50);
+}
+
+
+ 保存
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ 500.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 70
+ 0
+
+
+
+
+ 70
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ X范围:
+
+
+
+ -
+
+
+
+ 70
+ 0
+
+
+
+
+ 70
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ Z范围:
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ -500.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 20
+ 0
+
+
+
+
+ 20
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ ~
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 20
+ 0
+
+
+
+
+ 20
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ ~
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ 1000.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ 1000.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 80
+ 30
+
+
+
+
+ 80
+ 30
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+background-color: rgb(47, 48, 52);
+
+
+ -1000.0
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 70
+ 0
+
+
+
+
+ 70
+ 16777215
+
+
+
+
+ 13
+
+
+
+ color: rgb(221, 225, 233);
+
+
+ Y范围:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
diff --git a/App/WheelMeasure/WheelMeasureApp/main.cpp b/App/WheelMeasure/WheelMeasureApp/main.cpp
index daced818..e8634b95 100644
--- a/App/WheelMeasure/WheelMeasureApp/main.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/main.cpp
@@ -1,75 +1,82 @@
-#include "mainwindow.h"
-#include "IWheelMeasureStatus.h"
-#include "IVrWheelMeasureConfig.h"
-#include "CrashHandler.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "Version.h"
-
-int main(int argc, char *argv[])
-{
- QApplication a(argc, argv);
-
- // 设置应用程序信息
- a.setApplicationName("WheelMeasureApp");
- a.setApplicationVersion(GetWheelMeasureFullVersion());
- a.setOrganizationName("VisionRobot");
-
- // 注册Qt元类型
- qRegisterMetaType>("QVector");
- qRegisterMetaType>("QList");
- qRegisterMetaType("QAbstractItemModel::LayoutChangeHint");
- qRegisterMetaType("Qt::SortOrder");
-
- // 注册自定义元类型
- qRegisterMetaType("WheelCameraParam");
- qRegisterMetaType("WheelCameraPlaneCalibParam");
- qRegisterMetaType("WheelMeasureConfigResult");
- qRegisterMetaType("WheelMeasureData");
- qRegisterMetaType("WheelMeasureResult");
-
- // 单实例检查
- const QString appKey = "WheelMeasureApp_SingleInstance_Key";
-
- QSystemSemaphore semaphore(appKey + "_semaphore", 1);
- semaphore.acquire();
-
- QSharedMemory sharedMemory(appKey + "_memory");
-
- bool isRunning = false;
-
- if (sharedMemory.attach()) {
- isRunning = true;
- } else {
- if (!sharedMemory.create(1)) {
- qDebug() << "Unable to create shared memory segment:" << sharedMemory.errorString();
- isRunning = true;
- }
- }
-
- semaphore.release();
-
- if (isRunning) {
- QMessageBox::information(nullptr,
- QObject::tr("应用程序已运行"),
- QObject::tr("车轮拱高测量应用程序已经在运行中,请勿重复启动!"),
- QMessageBox::Ok);
- return 0;
- }
-
- MainWindow w;
- w.show();
- return a.exec();
-}
+#include "mainwindow.h"
+#include "IWheelMeasureStatus.h"
+#include "IVrWheelMeasureConfig.h"
+#include "CrashHandler.h"
+#include "AuthView.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Version.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ // 设置应用程序信息
+ a.setApplicationName("WheelMeasureApp");
+ a.setApplicationVersion(GetWheelMeasureFullVersion());
+ a.setOrganizationName("VisionRobot");
+
+ // 注册Qt元类型
+ qRegisterMetaType>("QVector");
+ qRegisterMetaType>("QList");
+ qRegisterMetaType("QAbstractItemModel::LayoutChangeHint");
+ qRegisterMetaType("Qt::SortOrder");
+
+ // 注册自定义元类型
+ qRegisterMetaType("WheelCameraParam");
+ qRegisterMetaType("WheelCameraPlaneCalibParam");
+ qRegisterMetaType("WheelMeasureConfigResult");
+ qRegisterMetaType("WheelMeasureData");
+ qRegisterMetaType("WheelMeasureResult");
+
+ // 单实例检查
+ const QString appKey = "WheelMeasureApp_SingleInstance_Key";
+
+ QSystemSemaphore semaphore(appKey + "_semaphore", 1);
+ semaphore.acquire();
+
+ QSharedMemory sharedMemory(appKey + "_memory");
+
+ bool isRunning = false;
+
+ if (sharedMemory.attach()) {
+ isRunning = true;
+ } else {
+ if (!sharedMemory.create(1)) {
+ qDebug() << "Unable to create shared memory segment:" << sharedMemory.errorString();
+ isRunning = true;
+ }
+ }
+
+ semaphore.release();
+
+ if (isRunning) {
+ QMessageBox::information(nullptr,
+ QObject::tr("应用程序已运行"),
+ QObject::tr("车轮拱高测量应用程序已经在运行中,请勿重复启动!"),
+ QMessageBox::Ok);
+ return 0;
+ }
+
+ // 检查授权,无授权则显示授权对话框
+ if (!AuthView::CheckAndShow(nullptr)) {
+ // 用户取消授权或授权失败,退出程序
+ return 0;
+ }
+
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp b/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
index a102dc08..9cc6afcb 100644
--- a/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
+++ b/App/WheelMeasure/WheelMeasureApp/mainwindow.cpp
@@ -1,561 +1,563 @@
-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-#include "Version.h"
-#include "widgets/ImageGridWidget.h"
-#include "widgets/DeviceStatusWidget.h"
-#include "widgets/MeasureResultListWidget.h"
-#include "dialogcameralevel.h"
-#include "dialogalgoarg.h"
-#include "dialogcamera.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "VrLog.h"
-#include "IVrUtils.h"
-#include "StyledMessageBox.h"
-
-MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
- , ui(new Ui::MainWindow)
-{
- ui->setupUi(this);
-
- // 设置窗口图标
- this->setWindowIcon(QIcon(":/common/resource/logo.png"));
-
- // 设置状态栏字体
- QFont statusFont = statusBar()->font();
- statusFont.setPointSize(12);
- statusBar()->setFont(statusFont);
-
- // 设置状态栏颜色和padding
- statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
-
- // 隐藏标题栏
- setWindowFlags(Qt::FramelessWindowHint);
-
- // 启动后自动最大化显示
- this->showMaximized();
-
- // 初始化时隐藏工作状态标签
- ui->label_work->setVisible(false);
-
- // 创建组合控件
- m_gridView = new ImageGridWidget();
- m_deviceStatusWidget = new DeviceStatusWidget();
- m_measureResultWidget = new MeasureResultListWidget();
-
- // 将设备状态widget添加到frame_dev中
- QVBoxLayout* frameResultImageLayout = new QVBoxLayout(ui->detect_result);
- frameResultImageLayout->setContentsMargins(0, 0, 0, 0);
- frameResultImageLayout->addWidget(m_gridView);
-
- // 将MeasureResultListWidget添加到detect_data中
- QVBoxLayout* frameDataLayout = new QVBoxLayout(ui->detect_data);
- frameDataLayout->setContentsMargins(0, 0, 0, 0);
- frameDataLayout->addWidget(m_measureResultWidget);
-
- QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->device_status);
- frameDevLayout->setContentsMargins(0, 0, 0, 0);
- frameDevLayout->addWidget(m_deviceStatusWidget);
-
- // 初始化Presenter
- m_presenter = new WheelMeasurePresenter();
-
- // 将设备状态控件与Presenter关联
- m_presenter->setStatusUpdate(this);
-
- // 连接配置更新信号
- connect(m_presenter, &WheelMeasurePresenter::configUpdated, this, &MainWindow::onConfigSaved);
-
- // 连接设备点击信号到重新检测槽函数
- connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked);
-
- // 连接图像右键点击信号到保存数据槽函数
- connect(m_gridView, &ImageGridWidget::tileRightClicked, this, &MainWindow::onTileRightClicked);
-
- // 设置版本信息显示
- setupVersionDisplay();
-
- // 初始化日志辅助类
- m_logHelper = new DetectLogHelper(ui->detect_log, this);
-
- m_presenter->Init();
-}
-
-MainWindow::~MainWindow()
-{
- // 先清除回调,防止后台线程继续调用
- if (m_presenter) {
- m_presenter->setStatusUpdate(nullptr);
- }
-
- if (m_gridView) {
- delete m_gridView;
- m_gridView = nullptr;
- }
-
- if (m_deviceStatusWidget) {
- delete m_deviceStatusWidget;
- m_deviceStatusWidget = nullptr;
- }
-
- if (m_measureResultWidget) {
- delete m_measureResultWidget;
- m_measureResultWidget = nullptr;
- }
-
- if (m_versionLabel) {
- delete m_versionLabel;
- m_versionLabel = nullptr;
- }
-
- if (m_dialogAlgoArg) {
- delete m_dialogAlgoArg;
- m_dialogAlgoArg = nullptr;
- }
-
- if (m_dialogCamera) {
- delete m_dialogCamera;
- m_dialogCamera = nullptr;
- }
-
- if (m_dialogCameraLevel) {
- delete m_dialogCameraLevel;
- m_dialogCameraLevel = nullptr;
- }
-
- if (m_presenter) {
- delete m_presenter;
- m_presenter = nullptr;
- }
-
- delete ui;
- LOG_DEBUG("~MainWindow finish \n");
-}
-
-void MainWindow::resizeEvent(QResizeEvent* event)
-{
- QMainWindow::resizeEvent(event);
-}
-
-void MainWindow::on_btn_hide_clicked()
-{
- this->showMinimized();
-}
-
-void MainWindow::on_btn_close_clicked()
-{
- this->close();
-}
-
-void MainWindow::on_btn_test_clicked()
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- // 设置选中状态
- ui->btn_test->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_data_test_s.png); background-color: rgb(38, 40, 47); border: none; }"
- );
-
- // 打开文件选择对话框
- QString fileName = QFileDialog::getOpenFileName(
- this,
- tr("选择调试数据文件"),
- QString(),
- tr("激光数据文件 (*.txt);;所有文件 (*.*)")
- );
-
- // 恢复未选中状态
- ui->btn_test->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_data_test.png); background-color: rgb(38, 40, 47); border: none; }"
- "QPushButton:pressed { image: url(:/common/resource/config_data_test_s.png); }"
- );
-
- if (fileName.isEmpty()) {
- return;
- }
-
- // 清空当前检测数据列表
- if (m_measureResultWidget) {
- m_measureResultWidget->clearAllResults();
- }
-
- // if (m_logHelper) m_logHelper->appendLog(QString("正在加载调试数据: %1").arg(fileName));
-
- // 在后台线程中执行加载和检测
- std::thread t([this, fileName]() {
- int result = m_presenter->LoadDebugDataAndDetect(fileName.toStdString());
- if (result == 0) {
- QMetaObject::invokeMethod(this, [this]() {
- if (m_logHelper) m_logHelper->appendLog("调试数据加载和检测成功");
- }, Qt::QueuedConnection);
- } else {
- QMetaObject::invokeMethod(this, [this, result]() {
- if (m_logHelper) m_logHelper->appendLog(QString("调试数据复检失败: %1").arg(result));
- }, Qt::QueuedConnection);
- }
- });
- t.detach();
-}
-
-void MainWindow::on_btn_start_clicked()
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- // 启动所有相机的检测
- m_presenter->StartAllDetection();
- if (m_logHelper) m_logHelper->appendLog("已启动所有相机检测");
-}
-
-void MainWindow::on_btn_stop_clicked()
-{
- if (!m_presenter) {
- return;
- }
-
- // 停止所有相机的检测
- m_presenter->StopAllDetection();
- if (m_logHelper) m_logHelper->appendLog("已停止所有相机检测");
-}
-
-void MainWindow::on_btn_camera_config_clicked()
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- if (!m_dialogCamera) {
- m_dialogCamera = new DialogCamera(this);
- m_dialogCamera->SetPresenter(m_presenter);
- connect(m_dialogCamera, &DialogCamera::configSaved, this, &MainWindow::onConfigSaved);
- // 连接关闭信号恢复按钮状态
- connect(m_dialogCamera, &QDialog::finished, this, [this]() {
- ui->btn_camera_config->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_camera.png); background-color: rgb(38, 40, 47); border: none; }"
- "QPushButton:pressed { image: url(:/common/resource/config_camera_s.png); }"
- );
- });
- }
-
- // 设置选中状态
- ui->btn_camera_config->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_camera_s.png); background-color: rgb(38, 40, 47); border: none; }"
- );
- m_dialogCamera->show();
-}
-
-void MainWindow::on_btn_algo_config_clicked()
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- if (!m_dialogAlgoArg) {
- m_dialogAlgoArg = new DialogAlgoArg(m_presenter->GetConfig(),
- m_presenter->GetConfigResult(), this);
- // 连接关闭信号恢复按钮状态
- connect(m_dialogAlgoArg, &QDialog::finished, this, [this]() {
- ui->btn_algo_config->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_algo.png); background-color: rgb(38, 40, 47); border: none; }"
- "QPushButton:pressed { image: url(:/common/resource/config_algo_s.png); }"
- );
- });
- }
-
- // 设置选中状态
- ui->btn_algo_config->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_algo_s.png); background-color: rgb(38, 40, 47); border: none; }"
- );
- m_dialogAlgoArg->Init();
- m_dialogAlgoArg->show();
-}
-
-void MainWindow::on_btn_camera_level_clicked()
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- if (!m_dialogCameraLevel) {
- m_dialogCameraLevel = new DialogCameraLevel(this);
- // 连接关闭信号恢复按钮状态
- connect(m_dialogCameraLevel, &QDialog::finished, this, [this]() {
- ui->btn_camera_level->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_camera_level.png); background-color: rgb(38, 40, 47); border: none; }"
- "QPushButton:pressed { image: url(:/common/resource/config_camera_level_s.png); }"
- );
- });
- }
-
- // 设置相机列表
- m_dialogCameraLevel->setCameraList(m_presenter->GetCameraList(), m_presenter);
-
- // 设置配置对象
- m_dialogCameraLevel->setConfig(m_presenter->GetConfig(), m_presenter->GetConfigResult());
-
- // 设置选中状态
- ui->btn_camera_level->setStyleSheet(
- "QPushButton { image: url(:/common/resource/config_camera_level_s.png); background-color: rgb(38, 40, 47); border: none; }"
- );
- m_dialogCameraLevel->show();
-}
-
-void MainWindow::onDeviceClicked(const QString& deviceName)
-{
- if (!m_presenter) {
- QMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- // 查找相机索引
- auto cameraList = m_presenter->GetCameraList();
- int foundIndex = -1;
- for (int i = 0; i < static_cast(cameraList.size()); ++i) {
- if (QString::fromStdString(cameraList[i].first) == deviceName) {
- foundIndex = i;
- break;
- }
- }
-
- if (foundIndex < 0) {
- if (m_logHelper) m_logHelper->appendLog(QString("未找到相机: %1").arg(deviceName));
- return;
- }
-
- // 清空指定设备的检测结果
- if (m_measureResultWidget) {
- m_measureResultWidget->clearDeviceResult(deviceName);
- }
-
- // 直接开始检测
- m_presenter->ResetDetect(foundIndex);
- if (m_logHelper) m_logHelper->appendLog(QString("已启动相机 \"%1\" 的检测").arg(deviceName));
-}
-
-void MainWindow::onConfigSaved()
-{
- // 配置已在 WheelMeasurePresenter::OnConfigChanged 中更新
- // 算法参数和调平参数的修改不需要重新初始化相机
- LOG_INFO("Config saved, configuration updated in memory\n");
-}
-
-void MainWindow::onTileRightClicked(int index, const QString& alias)
-{
- if (!m_presenter) {
- StyledMessageBox::warning(this, "错误", "系统未初始化完成!");
- return;
- }
-
- // 获取当前检测的相机索引(0-based)
- int currentDetectIndex = m_presenter->GetDetectIndex() - 1; // 转换为0-based
-
- // 检查点击的是否是当前检测的相机
- if (index != currentDetectIndex) {
- if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias));
- StyledMessageBox::information(this, "提示",
- QString("设备 \"%1\" 无缓存数据\n\n当前缓存的是设备 %2 的数据")
- .arg(alias)
- .arg(currentDetectIndex >= 0 ? m_gridView->getAlias(currentDetectIndex) : "无"));
- return;
- }
-
- // 检查是否有缓存数据
- int cacheSize = m_presenter->GetDetectionDataCacheSize();
- if (cacheSize <= 0) {
- if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias));
- StyledMessageBox::information(this, "提示", QString("设备 \"%1\" 无缓存数据").arg(alias));
- return;
- }
-
- // 弹出文件保存对话框
- QString defaultFileName = QString("%1_%2.txt")
- .arg(alias)
- .arg(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"));
-
- QString filePath = QFileDialog::getSaveFileName(
- this,
- tr("保存检测数据"),
- defaultFileName,
- tr("文本文件 (*.txt);;所有文件 (*.*)")
- );
-
- if (filePath.isEmpty()) {
- return;
- }
-
- // 调用Presenter保存数据
- int result = m_presenter->SaveDetectionDataToFile(filePath.toStdString());
- if (result == 0) {
- if (m_logHelper) m_logHelper->appendLog(QString("检测数据已保存: %1").arg(filePath));
- StyledMessageBox::information(this, "成功", QString("检测数据已保存到:\n%1").arg(filePath));
- } else {
- if (m_logHelper) m_logHelper->appendLog(QString("保存检测数据失败: %1").arg(result));
- StyledMessageBox::warning(this, "失败", QString("保存检测数据失败,错误码: %1").arg(result));
- }
-}
-
-// IWheelMeasureStatus接口方法实现
-void MainWindow::OnStatusUpdate(const QString &statusMessage)
-{
- if (m_logHelper) m_logHelper->appendLog(statusMessage);
- LOG_DEBUG("Status update: %s \n", statusMessage.toStdString().c_str());
-}
-
-void MainWindow::OnNeedShowImageCount(const QStringList &cameraNames)
-{
- if (cameraNames.isEmpty()) {
- m_gridView->initImages(0);
- LOG_DEBUG("No images to display\n");
- } else {
- m_gridView->initImages(cameraNames.size());
-
- // 为每个tile设置别名
- for (int i = 0; i < cameraNames.size(); ++i) {
- m_gridView->setTileAlias(i, cameraNames.at(i));
- }
-
- // 初始化设备状态列表
- if (m_deviceStatusWidget && m_presenter) {
- QList devices;
- for (const QString& name : cameraNames) {
- devices.append(WheelDeviceDisplayInfo(name, name, "", DeviceStatus::Offline, true));
- }
- m_deviceStatusWidget->setDevices(devices);
- }
-
- // 初始化检测结果列表
- if (m_measureResultWidget) {
- m_measureResultWidget->setDeviceList(cameraNames);
- }
- }
-}
-
-void MainWindow::OnMeasureResult(const WheelMeasureResult &result)
-{
- // 直接调用处理方法(Presenter在后台线程,需要使用invokeMethod确保线程安全)
- QMetaObject::invokeMethod(this, [this, result]() {
- // 如果图像有效,显示在网格控件中
- if (result.bImageValid && !result.image.isNull()) {
- m_gridView->setImages(result.aliasName, result.image);
- }
-
- // 更新设备检测结果列表
- if (m_measureResultWidget) {
- // 获取第一个结果数据(如果有的话)
- WheelMeasureData data;
- if (!result.result.empty()) {
- data = result.result[0];
- }
- m_measureResultWidget->updateDeviceResult(result.cameraName, data, result.bResultValid);
- }
- }, Qt::QueuedConnection);
-}
-
-void MainWindow::OnCameraConnected(const QString &cameraName)
-{
- QString message = QString("相机已连接: %1").arg(cameraName);
- if (m_logHelper) m_logHelper->appendLog(message);
- LOG_DEBUG("%s \n", message.toStdString().c_str());
-}
-
-void MainWindow::OnCameraDisconnected(const QString &cameraName)
-{
- QString message = QString("相机断开连接: %1").arg(cameraName);
- if (m_logHelper) m_logHelper->appendLog(message);
- LOG_DEBUG("%s \n", message.toStdString().c_str());
-}
-
-void MainWindow::OnWorkStatusChangedImpl(WorkStatus status)
-{
- QString statusStr;
- switch (status) {
- case WorkStatus::InitIng:
- statusStr = "初始化中";
- break;
- case WorkStatus::Ready:
- statusStr = "准备就绪";
- break;
- case WorkStatus::Working:
- statusStr = "正在检测";
- break;
- case WorkStatus::Detecting:
- statusStr = "正在检测";
- break;
- case WorkStatus::Completed:
- statusStr = "检测完成";
- break;
- case WorkStatus::Error:
- statusStr = "设备异常";
- break;
- default:
- statusStr = "未知状态";
- break;
- }
-
- QString message = QString("工作状态: %1").arg(statusStr);
- if (m_logHelper) m_logHelper->appendLog(message);
- LOG_DEBUG("%s \n", message.toStdString().c_str());
-}
-
-void MainWindow::OnErrorOccurred(const QString &errorMessage)
-{
- if (m_logHelper) m_logHelper->appendLog("错误: " + errorMessage);
- LOG_ERROR("Error occurred: %s \n", errorMessage.toStdString().c_str());
-}
-
-void MainWindow::OnDeviceStatusChanged(const QString &deviceName, int deviceStatus)
-{
- if (m_deviceStatusWidget) {
- m_deviceStatusWidget->updateDeviceStatus(deviceName, static_cast(deviceStatus));
- }
-}
-
-void MainWindow::OnClearMeasureData()
-{
- if (m_measureResultWidget) {
- m_measureResultWidget->clearAllResults();
- }
-}
-
-void MainWindow::setupVersionDisplay()
-{
- m_versionLabel = new QLabel(this);
-
- // 使用与 Workpiece 一致的版本格式
- QString versionText = QString("%1_%2%3%4%5%6%7")
- .arg(GetWheelMeasureFullVersion())
- .arg(YEAR)
- .arg(MONTH, 2, 10, QChar('0'))
- .arg(DAY, 2, 10, QChar('0'))
- .arg(HOUR, 2, 10, QChar('0'))
- .arg(MINUTE, 2, 10, QChar('0'))
- .arg(SECOND, 2, 10, QChar('0'));
-
- m_versionLabel->setText(versionText);
- m_versionLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
-
- m_versionLabel->setStyleSheet("QLabel { color: rgb(239, 241, 245); font-size: 24px; margin-right: 10px; }");
-
- statusBar()->addPermanentWidget(m_versionLabel);
-
- LOG_INFO("Version display initialized: %s\n", versionText.toStdString().c_str());
-}
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include "Version.h"
+#include "widgets/ImageGridWidget.h"
+#include "widgets/DeviceStatusWidget.h"
+#include "widgets/MeasureResultListWidget.h"
+#include "dialogcameralevel.h"
+#include "dialogalgoarg.h"
+#include "dialogcamera.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "VrLog.h"
+#include "IVrUtils.h"
+#include "StyledMessageBox.h"
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ // 设置窗口图标
+ this->setWindowIcon(QIcon(":/common/resource/logo.png"));
+
+ // 设置状态栏字体
+ QFont statusFont = statusBar()->font();
+ statusFont.setPointSize(12);
+ statusBar()->setFont(statusFont);
+
+ // 设置状态栏颜色和padding
+ statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }");
+
+ // 隐藏标题栏
+ setWindowFlags(Qt::FramelessWindowHint);
+
+ // 启动后自动最大化显示
+ this->showMaximized();
+
+ // 初始化时隐藏工作状态标签
+ ui->label_work->setVisible(false);
+
+ // 创建组合控件
+ m_gridView = new ImageGridWidget();
+ m_deviceStatusWidget = new DeviceStatusWidget();
+ m_measureResultWidget = new MeasureResultListWidget();
+
+ // 将设备状态widget添加到frame_dev中
+ QVBoxLayout* frameResultImageLayout = new QVBoxLayout(ui->detect_result);
+ frameResultImageLayout->setContentsMargins(0, 0, 0, 0);
+ frameResultImageLayout->addWidget(m_gridView);
+
+ // 将MeasureResultListWidget添加到detect_data中
+ QVBoxLayout* frameDataLayout = new QVBoxLayout(ui->detect_data);
+ frameDataLayout->setContentsMargins(0, 0, 0, 0);
+ frameDataLayout->addWidget(m_measureResultWidget);
+
+ QVBoxLayout* frameDevLayout = new QVBoxLayout(ui->device_status);
+ frameDevLayout->setContentsMargins(0, 0, 0, 0);
+ frameDevLayout->addWidget(m_deviceStatusWidget);
+
+ // 初始化Presenter
+ m_presenter = new WheelMeasurePresenter();
+
+ // 将设备状态控件与Presenter关联
+ m_presenter->setStatusUpdate(this);
+
+ // 连接配置更新信号
+ connect(m_presenter, &WheelMeasurePresenter::configUpdated, this, &MainWindow::onConfigSaved);
+
+ // 连接设备点击信号到重新检测槽函数
+ connect(m_deviceStatusWidget, &DeviceStatusWidget::deviceClicked, this, &MainWindow::onDeviceClicked);
+
+ // 连接图像右键点击信号到保存数据槽函数
+ connect(m_gridView, &ImageGridWidget::tileRightClicked, this, &MainWindow::onTileRightClicked);
+
+ // 设置版本信息显示
+ setupVersionDisplay();
+
+ // 初始化日志辅助类
+ m_logHelper = new DetectLogHelper(ui->detect_log, this);
+
+ m_presenter->Init();
+}
+
+MainWindow::~MainWindow()
+{
+ // 先清除回调,防止后台线程继续调用
+ if (m_presenter) {
+ m_presenter->setStatusUpdate(nullptr);
+ }
+
+ if (m_gridView) {
+ delete m_gridView;
+ m_gridView = nullptr;
+ }
+
+ if (m_deviceStatusWidget) {
+ delete m_deviceStatusWidget;
+ m_deviceStatusWidget = nullptr;
+ }
+
+ if (m_measureResultWidget) {
+ delete m_measureResultWidget;
+ m_measureResultWidget = nullptr;
+ }
+
+ if (m_versionLabel) {
+ delete m_versionLabel;
+ m_versionLabel = nullptr;
+ }
+
+ if (m_dialogAlgoArg) {
+ delete m_dialogAlgoArg;
+ m_dialogAlgoArg = nullptr;
+ }
+
+ if (m_dialogCamera) {
+ delete m_dialogCamera;
+ m_dialogCamera = nullptr;
+ }
+
+ if (m_dialogCameraLevel) {
+ delete m_dialogCameraLevel;
+ m_dialogCameraLevel = nullptr;
+ }
+
+ if (m_presenter) {
+ delete m_presenter;
+ m_presenter = nullptr;
+ }
+
+ delete ui;
+ LOG_DEBUG("~MainWindow finish \n");
+}
+
+void MainWindow::resizeEvent(QResizeEvent* event)
+{
+ QMainWindow::resizeEvent(event);
+}
+
+void MainWindow::on_btn_hide_clicked()
+{
+ this->showMinimized();
+}
+
+void MainWindow::on_btn_close_clicked()
+{
+ this->close();
+}
+
+void MainWindow::on_btn_test_clicked()
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ // 设置选中状态
+ ui->btn_test->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_data_test_s.png); background-color: rgb(38, 40, 47); border: none; }"
+ );
+
+ // 打开文件选择对话框
+ QString fileName = QFileDialog::getOpenFileName(
+ this,
+ tr("选择调试数据文件"),
+ QString(),
+ tr("激光数据文件 (*.txt);;所有文件 (*.*)")
+ );
+
+ // 恢复未选中状态
+ ui->btn_test->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_data_test.png); background-color: rgb(38, 40, 47); border: none; }"
+ "QPushButton:pressed { image: url(:/common/resource/config_data_test_s.png); }"
+ );
+
+ if (fileName.isEmpty()) {
+ return;
+ }
+
+ // 清空当前检测数据列表
+ if (m_measureResultWidget) {
+ m_measureResultWidget->clearAllResults();
+ }
+
+ // if (m_logHelper) m_logHelper->appendLog(QString("正在加载调试数据: %1").arg(fileName));
+
+ // 在后台线程中执行加载和检测
+ std::thread t([this, fileName]() {
+ int result = m_presenter->LoadDebugDataAndDetect(fileName.toStdString());
+ if (result == 0) {
+ QMetaObject::invokeMethod(this, [this]() {
+ if (m_logHelper) m_logHelper->appendLog("调试数据加载和检测成功");
+ }, Qt::QueuedConnection);
+ } else {
+ QMetaObject::invokeMethod(this, [this, result]() {
+ if (m_logHelper) m_logHelper->appendLog(QString("调试数据复检失败: %1").arg(result));
+ }, Qt::QueuedConnection);
+ }
+ });
+ t.detach();
+}
+
+void MainWindow::on_btn_start_clicked()
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ // 启动所有相机的检测
+ m_presenter->StartAllDetection();
+ if (m_logHelper) m_logHelper->appendLog("已启动所有相机检测");
+}
+
+void MainWindow::on_btn_stop_clicked()
+{
+ if (!m_presenter) {
+ return;
+ }
+
+ // 停止所有相机的检测
+ m_presenter->StopAllDetection();
+ if (m_logHelper) m_logHelper->appendLog("已停止所有相机检测");
+}
+
+void MainWindow::on_btn_camera_config_clicked()
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ if (!m_dialogCamera) {
+ m_dialogCamera = new DialogCamera(this);
+ m_dialogCamera->SetPresenter(m_presenter);
+ connect(m_dialogCamera, &DialogCamera::configSaved, this, &MainWindow::onConfigSaved);
+ // 连接关闭信号恢复按钮状态
+ connect(m_dialogCamera, &QDialog::finished, this, [this]() {
+ ui->btn_camera_config->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_camera.png); background-color: rgb(38, 40, 47); border: none; }"
+ "QPushButton:pressed { image: url(:/common/resource/config_camera_s.png); }"
+ );
+ });
+ }
+
+ // 设置选中状态
+ ui->btn_camera_config->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_camera_s.png); background-color: rgb(38, 40, 47); border: none; }"
+ );
+ m_dialogCamera->show();
+}
+
+void MainWindow::on_btn_algo_config_clicked()
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ if (!m_dialogAlgoArg) {
+ m_dialogAlgoArg = new DialogAlgoArg(m_presenter->GetConfig(),
+ m_presenter->GetConfigResult(), this);
+ // 连接关闭信号恢复按钮状态
+ connect(m_dialogAlgoArg, &QDialog::finished, this, [this]() {
+ ui->btn_algo_config->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_algo.png); background-color: rgb(38, 40, 47); border: none; }"
+ "QPushButton:pressed { image: url(:/common/resource/config_algo_s.png); }"
+ );
+ });
+ }
+
+ // 设置选中状态
+ ui->btn_algo_config->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_algo_s.png); background-color: rgb(38, 40, 47); border: none; }"
+ );
+ m_dialogAlgoArg->Init();
+ m_dialogAlgoArg->show();
+}
+
+void MainWindow::on_btn_camera_level_clicked()
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ if (!m_dialogCameraLevel) {
+ m_dialogCameraLevel = new DialogCameraLevel(this);
+ // 连接关闭信号恢复按钮状态
+ connect(m_dialogCameraLevel, &QDialog::finished, this, [this]() {
+ ui->btn_camera_level->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_camera_level.png); background-color: rgb(38, 40, 47); border: none; }"
+ "QPushButton:pressed { image: url(:/common/resource/config_camera_level_s.png); }"
+ );
+ });
+ }
+
+ // 设置相机列表
+ m_dialogCameraLevel->setCameraList(m_presenter->GetCameraList(), m_presenter);
+
+ // 设置配置对象
+ m_dialogCameraLevel->setConfig(m_presenter->GetConfig(), m_presenter->GetConfigResult());
+
+ // 设置选中状态
+ ui->btn_camera_level->setStyleSheet(
+ "QPushButton { image: url(:/common/resource/config_camera_level_s.png); background-color: rgb(38, 40, 47); border: none; }"
+ );
+ m_dialogCameraLevel->show();
+}
+
+void MainWindow::onDeviceClicked(const QString& deviceName)
+{
+ if (!m_presenter) {
+ QMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ // 查找相机索引
+ auto cameraList = m_presenter->GetCameraList();
+ int foundIndex = -1;
+ for (int i = 0; i < static_cast(cameraList.size()); ++i) {
+ if (QString::fromStdString(cameraList[i].first) == deviceName) {
+ foundIndex = i;
+ break;
+ }
+ }
+
+ if (foundIndex < 0) {
+ if (m_logHelper) m_logHelper->appendLog(QString("未找到相机: %1").arg(deviceName));
+ return;
+ }
+
+ // 清空指定设备的检测结果
+ if (m_measureResultWidget) {
+ m_measureResultWidget->clearDeviceResult(deviceName);
+ }
+
+ // 直接开始检测
+ m_presenter->ResetDetect(foundIndex);
+ if (m_logHelper) m_logHelper->appendLog(QString("已启动相机 \"%1\" 的检测").arg(deviceName));
+}
+
+void MainWindow::onConfigSaved()
+{
+ // 配置已在 WheelMeasurePresenter::OnConfigChanged 中更新
+ // 算法参数和调平参数的修改不需要重新初始化相机
+ LOG_INFO("Config saved, configuration updated in memory\n");
+}
+
+void MainWindow::onTileRightClicked(int index, const QString& alias)
+{
+ if (!m_presenter) {
+ StyledMessageBox::warning(this, "错误", "系统未初始化完成!");
+ return;
+ }
+
+ // 获取当前检测的相机索引(0-based)
+ int currentDetectIndex = m_presenter->GetDetectIndex() - 1; // 转换为0-based
+
+ // 检查点击的是否是当前检测的相机
+ if (index != currentDetectIndex) {
+ if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias));
+ StyledMessageBox::information(this, "提示",
+ QString("设备 \"%1\" 无缓存数据\n\n当前缓存的是设备 %2 的数据")
+ .arg(alias)
+ .arg(currentDetectIndex >= 0 ? m_gridView->getAlias(currentDetectIndex) : "无"));
+ return;
+ }
+
+ // 检查是否有缓存数据
+ int cacheSize = m_presenter->GetDetectionDataCacheSize();
+ if (cacheSize <= 0) {
+ if (m_logHelper) m_logHelper->appendLog(QString("设备 \"%1\" 无缓存数据").arg(alias));
+ StyledMessageBox::information(this, "提示", QString("设备 \"%1\" 无缓存数据").arg(alias));
+ return;
+ }
+
+ // 弹出文件保存对话框
+ QString defaultFileName = QString("%1_%2.txt")
+ .arg(alias)
+ .arg(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"));
+
+ QString filePath = QFileDialog::getSaveFileName(
+ this,
+ tr("保存检测数据"),
+ defaultFileName,
+ tr("文本文件 (*.txt);;所有文件 (*.*)")
+ );
+
+ if (filePath.isEmpty()) {
+ return;
+ }
+
+ // 调用Presenter保存数据
+ int result = m_presenter->SaveDetectionDataToFile(filePath.toStdString());
+ if (result == 0) {
+ if (m_logHelper) m_logHelper->appendLog(QString("检测数据已保存: %1").arg(filePath));
+ StyledMessageBox::information(this, "成功", QString("检测数据已保存到:\n%1").arg(filePath));
+ } else {
+ if (m_logHelper) m_logHelper->appendLog(QString("保存检测数据失败: %1").arg(result));
+ StyledMessageBox::warning(this, "失败", QString("保存检测数据失败,错误码: %1").arg(result));
+ }
+}
+
+// IWheelMeasureStatus接口方法实现
+void MainWindow::OnStatusUpdate(const QString &statusMessage)
+{
+ if (m_logHelper) m_logHelper->appendLog(statusMessage);
+ LOG_DEBUG("Status update: %s \n", statusMessage.toStdString().c_str());
+}
+
+void MainWindow::OnNeedShowImageCount(const QStringList &cameraNames)
+{
+ if (cameraNames.isEmpty()) {
+ m_gridView->initImages(0);
+ LOG_DEBUG("No images to display\n");
+ } else {
+ m_gridView->initImages(cameraNames.size());
+
+ // 为每个tile设置别名
+ for (int i = 0; i < cameraNames.size(); ++i) {
+ m_gridView->setTileAlias(i, cameraNames.at(i));
+ }
+
+ // 初始化设备状态列表
+ if (m_deviceStatusWidget && m_presenter) {
+ QList devices;
+ for (const QString& name : cameraNames) {
+ devices.append(WheelDeviceDisplayInfo(name, name, "", DeviceStatus::Offline, true));
+ }
+ m_deviceStatusWidget->setDevices(devices);
+ }
+
+ // 初始化检测结果列表
+ if (m_measureResultWidget) {
+ m_measureResultWidget->setDeviceList(cameraNames);
+ }
+ }
+}
+
+void MainWindow::OnMeasureResult(const WheelMeasureResult &result)
+{
+ // 直接调用处理方法(Presenter在后台线程,需要使用invokeMethod确保线程安全)
+ QMetaObject::invokeMethod(this, [this, result]() {
+ // 如果图像有效,显示在网格控件中
+ if (result.bImageValid && !result.image.isNull()) {
+ m_gridView->setImages(result.aliasName, result.image);
+ }
+
+ // 更新设备检测结果列表
+ if (m_measureResultWidget) {
+ // 获取第一个结果数据(如果有的话)
+ WheelMeasureData data;
+ if (!result.result.empty()) {
+ data = result.result[0];
+ }
+ m_measureResultWidget->updateDeviceResult(result.cameraName, data, result.bResultValid);
+ }
+ }, Qt::QueuedConnection);
+}
+
+void MainWindow::OnCameraConnected(const QString &cameraName)
+{
+ QString message = QString("相机已连接: %1").arg(cameraName);
+ if (m_logHelper) m_logHelper->appendLog(message);
+ LOG_DEBUG("%s \n", message.toStdString().c_str());
+}
+
+void MainWindow::OnCameraDisconnected(const QString &cameraName)
+{
+ QString message = QString("相机断开连接: %1").arg(cameraName);
+ if (m_logHelper) m_logHelper->appendLog(message);
+ LOG_DEBUG("%s \n", message.toStdString().c_str());
+}
+
+void MainWindow::OnWorkStatusChangedImpl(WorkStatus status)
+{
+ QString statusStr;
+ switch (status) {
+ case WorkStatus::InitIng:
+ statusStr = "初始化中";
+ break;
+ case WorkStatus::Ready:
+ statusStr = "准备就绪";
+ break;
+ case WorkStatus::Working:
+ statusStr = "正在检测";
+ break;
+ case WorkStatus::Detecting:
+ statusStr = "正在检测";
+ break;
+ case WorkStatus::Completed:
+ statusStr = "检测完成";
+ break;
+ case WorkStatus::Error:
+ statusStr = "设备异常";
+ break;
+ default:
+ statusStr = "未知状态";
+ break;
+ }
+
+ QString message = QString("工作状态: %1").arg(statusStr);
+ if (m_logHelper) m_logHelper->appendLog(message);
+ LOG_DEBUG("%s \n", message.toStdString().c_str());
+}
+
+void MainWindow::OnErrorOccurred(const QString &errorMessage)
+{
+ if (m_logHelper) m_logHelper->appendLog("错误: " + errorMessage);
+ LOG_ERROR("Error occurred: %s \n", errorMessage.toStdString().c_str());
+}
+
+void MainWindow::OnDeviceStatusChanged(const QString &deviceName, int deviceStatus)
+{
+ if (m_deviceStatusWidget) {
+ m_deviceStatusWidget->updateDeviceStatus(deviceName, static_cast(deviceStatus));
+ }
+}
+
+void MainWindow::OnClearMeasureData()
+{
+ if (m_logHelper) m_logHelper->clearLog();
+
+ if (m_measureResultWidget) {
+ m_measureResultWidget->clearAllResults();
+ }
+}
+
+void MainWindow::setupVersionDisplay()
+{
+ m_versionLabel = new QLabel(this);
+
+ // 使用与 Workpiece 一致的版本格式
+ QString versionText = QString("%1_%2%3%4%5%6%7")
+ .arg(GetWheelMeasureFullVersion())
+ .arg(YEAR)
+ .arg(MONTH, 2, 10, QChar('0'))
+ .arg(DAY, 2, 10, QChar('0'))
+ .arg(HOUR, 2, 10, QChar('0'))
+ .arg(MINUTE, 2, 10, QChar('0'))
+ .arg(SECOND, 2, 10, QChar('0'));
+
+ m_versionLabel->setText(versionText);
+ m_versionLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+
+ m_versionLabel->setStyleSheet("QLabel { color: rgb(239, 241, 245); font-size: 24px; margin-right: 10px; }");
+
+ statusBar()->addPermanentWidget(m_versionLabel);
+
+ LOG_INFO("Version display initialized: %s\n", versionText.toStdString().c_str());
+}
diff --git a/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h b/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
index 991c79c4..96deaa67 100644
--- a/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
+++ b/App/WheelMeasure/WheelMeasureConfig/Inc/IVrWheelMeasureConfig.h
@@ -1,236 +1,246 @@
-#ifndef IVRWHEELMEASURECONFIG_H
-#define IVRWHEELMEASURECONFIG_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "VrCommonConfig.h" // 包含公共配置结构体
-
-/**
- * @brief 数据类型枚举
- */
-enum class WheelMeasureDataType {
- Text = 0x01,
- Image = 0x02,
- ReadConfig = 0x03,
- WriteConfig = 0x04,
-};
-
-/**
- * @brief 服务器信息结构
- */
-struct WheelServerInfo
-{
- std::string name; // 服务器名称
- std::string ip; // 服务器IP地址
- int port = 5800; // 服务器端口
-};
-
-/**
- * @brief 相机配置参数
- */
-struct WheelCameraParam
-{
- int cameraIndex = 0; // 相机索引(1-based)
- std::string name = ""; // 相机名称
- std::string cameraIP = ""; // 相机IP地址
- bool enabled = true; // 是否启用
-
- // 相机工作参数(参考 GrabBag)
- double exposure = 100.0; // 曝光时间 (微秒)
- double gain = 1.0; // 增益值
- double frameRate = 500.0; // 帧率
- double swingSpeed = 30.0; // 摆动速度
- double swingStartAngle = 0.0; // 开始角度
- double swingStopAngle = 76.0; // 结束角度
-};
-
-/**
- * @brief 相机调平参数
- */
-struct WheelCameraPlaneCalibParam
-{
- int cameraIndex = 0; // 相机索引
- std::string cameraName = ""; // 相机名称
- double planeCalib[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; // 旋转矩阵(将点云旋转到水平)
- double planeHeight = -1; // 地面高度
- double invRMatrix[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; // 逆旋转矩阵(回到原坐标系)
- bool isCalibrated = false; // 是否已标定
- double errorCompensation = -5.0; // 误差补偿(mm)
-};
-
-/**
- * @brief 角点参数
- */
-struct WheelCornerParam
-{
- double minEndingGap = 20.0; // y方向,最短结束间隙
- double minEndingGap_z = 20.0; // z方向,最短结束间隙
- double scale = 50.0; // 计算方向角的窗口比例
- double cornerTh = 45.0; // 空角阈值,大于此阈值为有效空点
- double jumpCornerTh_1 = 10.0; // 判断空角是否为跳变的阈值
- double jumpCornerTh_2 = 60.0; // 判断空角是否为跳变的阈值
-};
-
-/**
- * @brief 线段参数
- */
-struct WheelLineSegParam
-{
- double segGapTh_y = 5.0; // y方向,最短段间隙阈值
- double segGapTh_z = 10.0; // z方向,最短段间隙阈值
- double maxDist = 1.0; // 最大距离
-};
-
-/**
- * @brief 离群点过滤参数
- */
-struct WheelOutlierFilterParam
-{
- double continuityTh = 20.0; // 连续性阈值
- double outlierTh = 5.0; // 离群点阈值
-};
-
-/**
- * @brief 树生长参数
- */
-struct WheelTreeGrowParam
-{
- double yDeviation_max = 5.0; // 生长时允许的最大Y偏差
- double zDeviation_max = 2.0; // 生长时允许的最大Z偏差
- int maxLineSkipNum = 10; // 生长时允许的最大跳线数
- double maxSkipDistance = 5.0; // 当maxLineSkipNum为-1时使用
- double minLTypeTreeLen = 100.0; // 最少的L型节点数目
- double minVTypeTreeLen = 100.0; // 最少的V型节点数目
-};
-
-/**
- * @brief 车轮拱高测量算法参数
- */
-struct WheelMeasureAlgorithmParams
-{
- WheelCornerParam cornerParam; // 角点参数
- WheelLineSegParam lineSegParam; // 线段参数
- WheelOutlierFilterParam filterParam; // 离群点过滤参数
- WheelTreeGrowParam growParam; // 树生长参数
-};
-
-/**
- * @brief 配置加载结果
- */
-struct WheelMeasureConfigResult
-{
- std::vector cameras; // 相机列表
- std::vector planeCalibParams; // 相机调平参数列表
- std::vector servers; // 服务器列表
- WheelMeasureAlgorithmParams algorithmParams; // 算法参数
- VrDebugParam debugParam; // 调试参数(使用公共VrDebugParam)
-
- int serverPort = 5900; // 服务器端口
- int tcpPort = 5800; // TCP协议端口
-
- // 构造函数
- WheelMeasureConfigResult() {}
-};
-
-/**
- * @brief 测量结果数据
- */
-struct WheelMeasureData
-{
- int id = 0; // 测量ID
- double archToCenterHeight = 0.0; // 拱高到中心的高度
- double archToGroundHeight = 0.0; // 拱高到地面的高度
- double wheelArchPosX = 0.0; // 拱点X坐标
- double wheelArchPosY = 0.0; // 拱点Y坐标
- double wheelArchPosZ = 0.0; // 拱点Z坐标
- double wheelUpPosX = 0.0; // 上点X坐标
- double wheelUpPosY = 0.0; // 上点Y坐标
- double wheelUpPosZ = 0.0; // 上点Z坐标
- double wheelDownPosX = 0.0; // 下点X坐标
- double wheelDownPosY = 0.0; // 下点Y坐标
- double wheelDownPosZ = 0.0; // 下点Z坐标
- QString timestamp = ""; // 时间戳
-};
-
-/**
- * @brief 测量结果
- */
-struct WheelMeasureResult
-{
- QString cameraName = ""; // 相机名称
- QString aliasName = ""; // 别名
- QImage image; // 图像
- bool bImageValid = false; // 图像是否有效
- bool bResultValid = false; // 结果是否有效
- std::vector result; // 测量结果列表
-};
-
-/**
- * @brief 配置改变通知接口
- */
-class IVrWheelMeasureConfigChangeNotify
-{
-public:
- virtual ~IVrWheelMeasureConfigChangeNotify() {}
-
- /**
- * @brief 配置数据改变通知
- * @param configResult 新的配置数据
- */
- virtual void OnConfigChanged(const WheelMeasureConfigResult& configResult) = 0;
-};
-
-/**
- * @brief WheelMeasureConfig接口类
- */
-class IVrWheelMeasureConfig
-{
-public:
- /**
- * @brief 虚析构函数
- */
- virtual ~IVrWheelMeasureConfig() = default;
-
- /**
- * @brief 创建实例
- * @return 实例
- */
- static bool CreateInstance(IVrWheelMeasureConfig** ppVrConfig);
-
- /**
- * @brief 加载配置文件
- * @param filePath 配置文件路径
- * @return 加载的配置结果
- */
- virtual WheelMeasureConfigResult LoadConfig(const std::string& filePath) = 0;
-
- /**
- * @brief 保存配置文件
- * @param filePath 配置文件路径
- * @param configResult 配置结果
- * @return 是否保存成功
- */
- virtual bool SaveConfig(const std::string& filePath, WheelMeasureConfigResult& configResult) = 0;
-
- /**
- * @brief 设置配置改变通知回调
- * @param notify 通知接口指针
- */
- virtual void SetConfigChangeNotify(IVrWheelMeasureConfigChangeNotify* notify) = 0;
-};
-
-// 声明元类型,以便在QVariant中使用
-Q_DECLARE_METATYPE(WheelServerInfo)
-Q_DECLARE_METATYPE(WheelCameraParam)
-Q_DECLARE_METATYPE(WheelCameraPlaneCalibParam)
-Q_DECLARE_METATYPE(WheelMeasureConfigResult)
-Q_DECLARE_METATYPE(WheelMeasureData)
-Q_DECLARE_METATYPE(WheelMeasureResult)
-
-#endif // IVRWHEELMEASURECONFIG_H
+#ifndef IVRWHEELMEASURECONFIG_H
+#define IVRWHEELMEASURECONFIG_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "VrCommonConfig.h" // 包含公共配置结构体
+
+/**
+ * @brief 数据类型枚举
+ */
+enum class WheelMeasureDataType {
+ Text = 0x01,
+ Image = 0x02,
+ ReadConfig = 0x03,
+ WriteConfig = 0x04,
+};
+
+/**
+ * @brief 服务器信息结构
+ */
+struct WheelServerInfo
+{
+ std::string name; // 服务器名称
+ std::string ip; // 服务器IP地址
+ int port = 5000; // 服务器端口
+};
+
+/**
+ * @brief 相机配置参数
+ */
+struct WheelCameraParam
+{
+ int cameraIndex = 0; // 相机索引(1-based)
+ std::string name = ""; // 相机名称
+ std::string cameraIP = ""; // 相机IP地址
+ bool enabled = true; // 是否启用
+
+ // 相机工作参数(参考 GrabBag)
+ double exposure = 100.0; // 曝光时间 (微秒)
+ double gain = 1.0; // 增益值
+ double frameRate = 500.0; // 帧率
+ double swingSpeed = 30.0; // 摆动速度
+ double swingStartAngle = 0.0; // 开始角度
+ double swingStopAngle = 76.0; // 结束角度
+};
+
+/**
+ * @brief 相机调平参数
+ */
+struct WheelCameraPlaneCalibParam
+{
+ int cameraIndex = 0; // 相机索引
+ std::string cameraName = ""; // 相机名称
+ double planeCalib[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; // 旋转矩阵(将点云旋转到水平)
+ double planeHeight = -1; // 地面高度
+ double invRMatrix[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; // 逆旋转矩阵(回到原坐标系)
+ bool isCalibrated = false; // 是否已标定
+ double errorCompensation = -5.0; // 误差补偿(mm)
+
+ // 轮胎存在检测的3D ROI范围
+ double wheelRoi3d_xMin = -1000.0; // X方向最小值(mm)
+ double wheelRoi3d_xMax = 1000.0; // X方向最大值(mm)
+ double wheelRoi3d_yMin = -1000.0; // Y方向最小值(mm)
+ double wheelRoi3d_yMax = 1000.0; // Y方向最大值(mm)
+ double wheelRoi3d_zMin = -1000.0; // Z方向最小值(mm)
+ double wheelRoi3d_zMax = 1000.0; // Z方向最大值(mm)
+};
+
+/**
+ * @brief 角点参数
+ */
+struct WheelCornerParam
+{
+ double minEndingGap = 20.0; // y方向,最短结束间隙
+ double minEndingGap_z = 20.0; // z方向,最短结束间隙
+ double scale = 50.0; // 计算方向角的窗口比例
+ double cornerTh = 45.0; // 空角阈值,大于此阈值为有效空点
+ double jumpCornerTh_1 = 10.0; // 判断空角是否为跳变的阈值
+ double jumpCornerTh_2 = 60.0; // 判断空角是否为跳变的阈值
+};
+
+/**
+ * @brief 线段参数
+ */
+struct WheelLineSegParam
+{
+ double segGapTh_y = 5.0; // y方向,最短段间隙阈值
+ double segGapTh_z = 10.0; // z方向,最短段间隙阈值
+ double maxDist = 1.0; // 最大距离
+};
+
+/**
+ * @brief 离群点过滤参数
+ */
+struct WheelOutlierFilterParam
+{
+ double continuityTh = 20.0; // 连续性阈值
+ double outlierTh = 5.0; // 离群点阈值
+};
+
+/**
+ * @brief 树生长参数
+ */
+struct WheelTreeGrowParam
+{
+ double yDeviation_max = 5.0; // 生长时允许的最大Y偏差
+ double zDeviation_max = 2.0; // 生长时允许的最大Z偏差
+ int maxLineSkipNum = 10; // 生长时允许的最大跳线数
+ double maxSkipDistance = 5.0; // 当maxLineSkipNum为-1时使用
+ double minLTypeTreeLen = 100.0; // 最少的L型节点数目
+ double minVTypeTreeLen = 100.0; // 最少的V型节点数目
+};
+
+/**
+ * @brief 车轮拱高测量算法参数
+ */
+struct WheelMeasureAlgorithmParams
+{
+ WheelCornerParam cornerParam; // 角点参数
+ WheelLineSegParam lineSegParam; // 线段参数
+ WheelOutlierFilterParam filterParam; // 离群点过滤参数
+ WheelTreeGrowParam growParam; // 树生长参数
+};
+
+/**
+ * @brief 配置加载结果
+ */
+struct WheelMeasureConfigResult
+{
+ std::vector cameras; // 相机列表
+ std::vector planeCalibParams; // 相机调平参数列表
+ std::vector servers; // 服务器列表
+ WheelMeasureAlgorithmParams algorithmParams; // 算法参数
+ VrDebugParam debugParam; // 调试参数(使用公共VrDebugParam)
+
+ int serverPort = 5900; // 服务器端口
+ int tcpPort = 5800; // TCP协议端口
+
+ // 构造函数
+ WheelMeasureConfigResult() {}
+};
+
+/**
+ * @brief 测量结果数据
+ */
+struct WheelMeasureData
+{
+ int id = 0; // 测量ID
+ double archToCenterHeight = 0.0; // 拱高到中心的高度
+ double archToGroundHeight = 0.0; // 拱高到地面的高度
+ double wheelArchPosX = 0.0; // 拱点X坐标
+ double wheelArchPosY = 0.0; // 拱点Y坐标
+ double wheelArchPosZ = 0.0; // 拱点Z坐标
+ double wheelUpPosX = 0.0; // 上点X坐标
+ double wheelUpPosY = 0.0; // 上点Y坐标
+ double wheelUpPosZ = 0.0; // 上点Z坐标
+ double wheelDownPosX = 0.0; // 下点X坐标
+ double wheelDownPosY = 0.0; // 下点Y坐标
+ double wheelDownPosZ = 0.0; // 下点Z坐标
+ QString timestamp = ""; // 时间戳
+};
+
+/**
+ * @brief 测量结果
+ */
+struct WheelMeasureResult
+{
+ QString cameraName = ""; // 相机名称
+ QString aliasName = ""; // 别名
+ QImage image; // 图像
+ bool bImageValid = false; // 图像是否有效
+ bool bResultValid = false; // 结果是否有效
+ int errorCode = 0; // 错误码(0表示成功,401表示工件为空)
+ QString errorMessage = ""; // 错误信息
+ std::vector result; // 测量结果列表
+};
+
+/**
+ * @brief 配置改变通知接口
+ */
+class IVrWheelMeasureConfigChangeNotify
+{
+public:
+ virtual ~IVrWheelMeasureConfigChangeNotify() {}
+
+ /**
+ * @brief 配置数据改变通知
+ * @param configResult 新的配置数据
+ */
+ virtual void OnConfigChanged(const WheelMeasureConfigResult& configResult) = 0;
+};
+
+/**
+ * @brief WheelMeasureConfig接口类
+ */
+class IVrWheelMeasureConfig
+{
+public:
+ /**
+ * @brief 虚析构函数
+ */
+ virtual ~IVrWheelMeasureConfig() = default;
+
+ /**
+ * @brief 创建实例
+ * @return 实例
+ */
+ static bool CreateInstance(IVrWheelMeasureConfig** ppVrConfig);
+
+ /**
+ * @brief 加载配置文件
+ * @param filePath 配置文件路径
+ * @return 加载的配置结果
+ */
+ virtual WheelMeasureConfigResult LoadConfig(const std::string& filePath) = 0;
+
+ /**
+ * @brief 保存配置文件
+ * @param filePath 配置文件路径
+ * @param configResult 配置结果
+ * @return 是否保存成功
+ */
+ virtual bool SaveConfig(const std::string& filePath, WheelMeasureConfigResult& configResult) = 0;
+
+ /**
+ * @brief 设置配置改变通知回调
+ * @param notify 通知接口指针
+ */
+ virtual void SetConfigChangeNotify(IVrWheelMeasureConfigChangeNotify* notify) = 0;
+};
+
+// 声明元类型,以便在QVariant中使用
+Q_DECLARE_METATYPE(WheelServerInfo)
+Q_DECLARE_METATYPE(WheelCameraParam)
+Q_DECLARE_METATYPE(WheelCameraPlaneCalibParam)
+Q_DECLARE_METATYPE(WheelMeasureConfigResult)
+Q_DECLARE_METATYPE(WheelMeasureData)
+Q_DECLARE_METATYPE(WheelMeasureResult)
+
+#endif // IVRWHEELMEASURECONFIG_H
diff --git a/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp b/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
index 3d2ffd14..a8cee672 100644
--- a/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
+++ b/App/WheelMeasure/WheelMeasureConfig/Src/VrWheelMeasureConfig.cpp
@@ -1,435 +1,461 @@
-#include "VrWheelMeasureConfig.h"
-#include "IVrWheelMeasureConfig.h"
-#include
-#include
-#include "VrLog.h"
-#include
-#include
-#include
-#include
-#include
-#include
-
-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;
- }
-
- // 读取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));
-
- // 保存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;
-}
+#include "VrWheelMeasureConfig.h"
+#include "IVrWheelMeasureConfig.h"
+#include
+#include
+#include "VrLog.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+ }
+
+ // 读取轮胎存在检测的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));
+
+ // 保存轮胎存在检测的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;
+}
diff --git a/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libbaseAlgorithm.so b/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libbaseAlgorithm.so
index 452ad8e7..1b637bd8 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libbaseAlgorithm.so and b/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libbaseAlgorithm.so differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libwheelArchHeigthMeasure.so b/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libwheelArchHeigthMeasure.so
index 561247c9..561bd7cd 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libwheelArchHeigthMeasure.so and b/AppAlgo/wheelArchHeigthMeasure/Arm/aarch64/libwheelArchHeigthMeasure.so differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_algo_Export.h b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_algo_Export.h
index f53e18ea..2ab702ea 100644
--- a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_algo_Export.h
+++ b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_algo_Export.h
@@ -1,22 +1,22 @@
-#pragma once
-
-#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
-# define Q_DECL_EXPORT __declspec(dllexport)
-# define Q_DECL_IMPORT __declspec(dllimport)
-#else
-# define Q_DECL_EXPORT __attribute__((visibility("default")))
-# define Q_DECL_IMPORT __attribute__((visibility("default")))
-#endif
-
-#if defined(SG_API_LIBRARY)
-# define SG_APISHARED_EXPORT Q_DECL_EXPORT
-#else
-# define SG_APISHARED_EXPORT Q_DECL_IMPORT
-#endif
-
-#include "SG_baseDataType.h"
-
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846 // pi
-#endif // !M_PI
+#pragma once
+
+#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+# define Q_DECL_EXPORT __declspec(dllexport)
+# define Q_DECL_IMPORT __declspec(dllimport)
+#else
+# define Q_DECL_EXPORT __attribute__((visibility("default")))
+# define Q_DECL_IMPORT __attribute__((visibility("default")))
+#endif
+
+#if defined(SG_API_LIBRARY)
+# define SG_APISHARED_EXPORT Q_DECL_EXPORT
+#else
+# define SG_APISHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#include "SG_baseDataType.h"
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 // pi
+#endif // !M_PI
diff --git a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_baseDataType.h b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_baseDataType.h
index 6630ea81..267b8539 100644
--- a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_baseDataType.h
+++ b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_baseDataType.h
@@ -1,547 +1,614 @@
-#pragma once
-
-#include
-#include
-#include
-
-#define PI 3.14159265358979323846
-
-// ŷǽṹ壨λȣ
-typedef struct{
- double roll; // Xת
- double pitch; // Yת
- double yaw; // Zתƫ
-}SSG_EulerAngles;
-
-//ԹΪX(ɨ跽ƽеZᴹֱΪYᣬֱΪZ
-typedef struct
-{
- bool validFlag; //ָʾǷЧ
- double x;
- double y;
- double z;
- double pitchAngle; //ǣYƫת,
- double rollAngle; //תǣXƫת,
- double yawAngle; //ƫתǣZƫת,
-}SSG_6AxisAttitude;
-
-typedef struct
-{
- bool validFlag; //ָʾǷЧ
- double x;
- double y;
- double z;
-}SSG_3AxisAttitude;
-
-typedef enum
-{
- keSG_PoseSorting_Uknown = 0,
- keSG_PoseSorting_ZMin2Max, ///Z
- keSG_PoseSorting_L2R_T2B, ///ңϵ
- keSG_PoseSorting_T2B_L2R, ///ϵ£
-} ESG_poseSortingMode;
-
-typedef struct
-{
- int data_0;
- int data_1;
- int idx;
-}SSG_intPair;
-
-typedef struct
-{
- int featurType;
- int featureIdx_v;
- int featureIdx_h;
- int clusterID;
- int flag;
- int lineIdx;
- int ptIdx;
-}SSG_featureClusteringInfo;
-
-typedef struct
-{
- double left;
- double right;
- double top;
- double bottom;
-}SSG_ROIRectD;
-
-struct HSV {
- double h; // ɫ (0-360)
- double s; // Ͷ (0-1)
- double v; // (0-1)
-};
-
-struct RGB {
- int r;
- int g;
- int b;
-};
-
-#define LINE_FEATURE_NUM 16
-#define LINE_FEATURE_UNDEF 0
-#define LINE_FEATURE_L_JUMP_H2L 1
-#define LINE_FEATURE_L_JUMP_L2H 2
-#define LINE_FEATURE_L_SLOPE_H2L 3
-#define LINE_FEATURE_L_SLOPE_L2H 4
-#define LINE_FEATURE_V_SLOPE 5
-#define LINE_FEATURE_LINE_ENDING_0 6 //ending
-#define LINE_FEATURE_LINE_ENDING_1 7 //endingյ
-#define LINE_FEATURE_RGN_EDGE 8 //ʱѾõĿıԵ
-#define LINE_FEATURE_RIGHT_ANGLE_HR 9 //ֱ:ˮƽ-
-#define LINE_FEATURE_RIGHT_ANGLE_HF 10 //ֱ:ˮƽ-½
-#define LINE_FEATURE_RIGHT_ANGLE_RH 11 //ֱ:-ˮƽ
-#define LINE_FEATURE_RIGHT_ANGLE_FH 12 //ֱ:½-ˮƽ
-#define LINE_FEATURE_PEAK_TOP 13
-#define LINE_FEATURE_PEAK_BOTTOM 14
-#define LINE_FEATURE_CORNER_V 15
-
-
-typedef struct
-{
- int featureType;
- SVzNL2DPoint jumpPos2D;
- SVzNL3DPoint jumpPos;
- double featureValue;
-}SSG_basicFeature1D;
-
-typedef struct
-{
- int lineIdx;
- double gap_start;
- double gap_width;
- double gap_depth;
- SVzNL3DPosition gapPt_0; //gapĶ˵
- SVzNL3DPosition gapPt_1; //gapĶ˵
- SSG_ROIRectD roi;
-}SSG_basicFeatureGap;
-
-#define FEATURE_FLAG_UNDEF 0
-#define FEATURE_FLAG_INVLD_START 1
-#define FEATURE_FLAG_INVLD_END 2
-#define FEATURE_FLAG_VALID_START 3
-#define FEATURE_FLAG_VALID_END 4
-#define FEATURE_FLAG_INVALID 5
-typedef struct
-{
- int flag;
- int lineIdx;
- int startPtIdx;
- int endPtIdx;
- int midPtIdx;
- SVzNL3DPoint midPt;
- double width;
- double pkHeight;
-}SSG_featureSemiCircle;
-
-typedef struct
-{
- int lineIdx;
- std::vector features;
- std::vector endings;
-}SSG_lineFeature;
-
-typedef struct
-{
- /* ǷޣСڴޣΪ */
- double continuityTh; //ޡʹzжʱΪzޣʹõжʱΪ
- /* жޣεĵСڴޣΪ */
- double outlierTh;
-}SSG_outlierFilterParam;
-
-typedef struct
-{
- double LSlopeZWin; //LSlope¶ȼĴڳ
- double validSlopeH;
- double minLJumpH;
- double minEndingGap;//ޡڴޣΪ
-}SSG_slopeParam;
-
-typedef struct
-{
- double minEndingGap; //yޡڴޣΪ
- double minEndingGap_z; //zޡڴޣΪ
- double scale; //㷽ǵĴڱ
- double cornerTh; //սޣڴޣΪЧյ
- double jumpCornerTh_1; //жϹսǷΪޡһjumpCornerTh_1һСjumpCornerTh_2ʱ
- double jumpCornerTh_2;
-}SSG_cornerParam;
-
-typedef struct
-{
- double segGapTh_y; //yޡڴޣΪ
- double segGapTh_z; //zޡڴޣΪ
- double maxDist; //㷽ǵĴڱ
-}SSG_lineSegParam;
-
-typedef struct
-{
- double scale_angle; //㷽ǵĴڱ
- double scale_corner; //㷽תǵĴڱ
- double cornerTh; //սޣڴޣΪЧArc
-}SSG_gloveArcParam;
-
-typedef struct
-{
- double H_len; //ֱˮƽεij
- double V_len; //ֱֱεij
- double maxDelta;
-}SSG_lineRightAngleParam;
-
-typedef struct
-{
- double valleyMinH;
- double valleyMaxW;
-}SSG_VFeatureParam;
-
-typedef struct
-{
- int lineIdx;
- int startPtIdx;
- int endPtIdx;
- SVzNL3DPoint startPt;
- SVzNL3DPoint endPt;
-}SWD_segFeature;
-
-typedef struct
-{
- double sameGapTh;
- int gapChkWin;
-}SSG_tearFeatureExtactPara;
-typedef struct
-{
- double yDeviation_max;//ʱYƫ
- double zDeviation_max; //ʱZƫ
- int maxLineSkipNum; //ʱ -1ʱʹmaxDkipDistance
- double maxSkipDistance; //maxLineSkipNumΪ-1 ʹô˲.Ϊ-1ʱ˲Ч
- double minLTypeTreeLen; //ٵĽڵĿСڴĿƳ
- double minVTypeTreeLen; //ٵĽڵĿСڴĿƳ
-}SSG_treeGrowParam;
-
-typedef struct
-{
- double bagL; //
- double bagW; //
- double bagH; //
-}SSG_bagParam;
-
-typedef struct
-{
- double length; //
- double width; //
- double height; //
-}SWD_sizeParam;
-
-typedef struct
-{
- SVzNLRangeD xRange; //< XΧ
- SVzNLRangeD yRange; //< YΧ
- SVzNLRangeD zRange; //< ZΧ
- double scale_x;
- double scale_y;
-} SWD_pointCloudPara;
-
-typedef struct
-{
- ESG_poseSortingMode sortMode;
-}SSG_objSortParam;
-
-typedef struct
-{
- double angleStep;
- double radiusStep;
-}SSG_polarScanParam;
-
-typedef struct
-{
- int treeState;
- int treeType;
- int sLineIdx;
- int eLineIdx;
- double tree_value;
- SSG_ROIRectD roi;
- std::vector< SSG_basicFeature1D> treeNodes;
- int angleChkScalePos; //ڼangleCheckٶ
-}SSG_featureTree;
-
-typedef struct
-{
- int treeState;
- int treeType;
- int sLineIdx;
- int eLineIdx;
- double tree_value;
- SSG_ROIRectD roi;
- std::vector< SSG_basicFeatureGap> treeNodes;
- int angleChkScalePos; //ڼangleCheckٶ
-}SSG_gapFeatureTree;
-
-typedef struct
-{
- int treeState;
- int treeType;
- int sLineIdx;
- int eLineIdx;
- SSG_ROIRectD roi;
- SVzNL3DPoint centerPt;
- SVzNL2DPoint centerPos;
- int treeMidType; //1:Ѿӹ
- std::vector< SSG_featureSemiCircle> treeNodes;
-}SSG_semiCircleFeatureTree;
-
-typedef struct
-{
- int treeState;
- int sLineIdx;
- int eLineIdx;
- double tree_value;
- std::vector< SWD_segFeature> treeNodes;
-}SWD_segFeatureTree;
-
-typedef struct
-{
- int vTreeFlag;
- int treeIdx;
- int treeType;
- int sLineIdx;
- int eLineIdx;
- SSG_ROIRectD roi;
-}SSG_treeInfo;
-
-typedef struct
-{
- int seachW_lines;
- int searchW_pts;
-}SSG_localPkParam;
-
-typedef struct
-{
- int x;
- int y;
- int value;
- double valueD;
- int sideID; //1-T, 2-B, 3-L, 4-R
-}SSG_2DValueI;
-
-typedef struct
-{
- int start;
- int len;
- int value;
-}SSG_RUN;
-
-typedef struct
-{
- int start;
- int len;
- int value;
- bool start_zRising; //z־
- bool end_zRising;//յz־
-}SSG_RUN_EX;
-
-typedef struct
-{
- double mean;
- double var;
-}SSG_meanVar;
-
-typedef struct
-{
- int x;
- int y;
- int type;
- int edgeId;
- int blockFlag;//ڵ־
- double scanDist;
- SVzNL3DPoint edgePt;
-}SSG_contourPtInfo;
-
-typedef struct
-{
- int lineIdx;
- std::vector contourPts;
-}SSG_lineConotours;
-
-typedef struct
-{
- int lineIdx;
- int edgeId_0;
- int edgeId_1;
- double ptPairDist;
- SSG_contourPtInfo contourPt_0;
- SSG_contourPtInfo contourPt_1;
-}SSG_conotourPair;
-
-typedef struct
-{
- double x;
- double y;
- double z;
- double x_roll;
- double y_pitch;
- double z_yaw;
-}SSG_6DOF;
-
-typedef struct
-{
- double L;
- double W;
- double H;
- double angle;
- SVzNL3DPoint endings[4];
-} SSG_boxCarDimension;
-
-typedef struct
-{
- SVzNL3DPoint opCenter; //λ
- double objR;
-}SWD_motorStatorPosition;
-
-typedef struct
-{
- int objID;
- double grasperAngle;
- double rotateAngle; //ץ0λʱΪѾΣ120ȡ
- double graspR;
-}SWD_statorOuterGrasper;
-
-typedef struct
-{
- int pkRgnIdx;
- SVzNLSizeD objSize;
- SVzNL2DPoint pos2D;
- SSG_6DOF centerPos;
-}SSG_peakRgnInfo;
-
-typedef struct
-{
- int pkRgnIdx;
- SVzNLSizeD objSize;
- SVzNL2DPoint pos2D;
- SSG_6DOF centerPos;
- int orienFlag; //0-δ֪1 - 棬 2-
-}SSG_peakOrienRgnInfo;
-
-typedef struct
-{
- SVzNL3DPoint sPt;
- SVzNL3DPoint ePt;
- double scanDist;
- int ptNum;
-}SSG_contourEdgeInfo;
-
-typedef struct
-{
- double meanDist;
- double varDist;
- double minDist;
- double maxDist;
- int matchNum;
- int level2_num; //level2Ϊ߿Ŷ(ΪJumpEnding;
- int level1_num; //level1-ΪпŶȣһΪJumpEnding
- SSG_ROIRectD roi;
-}SSG_edgeMatchInfo;
-
-typedef struct
-{
- int id1;
- int id2;
- int matchPts;
- int matchType; //Ŷȣ 2Ϊ߿Ŷ(ΪJumpEnding; 1-ΪпŶȣһΪJumpEnding0-ΪͿŶ
- double matchValue;
- double varValue;
- double minMatchValue;
- double maxMatchValue;
- SSG_ROIRectD roi;
-}SSG_matchPair;
-
-typedef struct
-{
- int objIdx;
- bool isValid; //ǷΪϸĿꡣĿ꣬֯ţɨ赽ߣΪϸĿ
- SSG_ROIRectD objROI;
- SVzNL3DPoint objPos;
- SSG_6DOF graspPos;
-}SSG_sideBagInfo;
-
-typedef struct
-{
- SVzNLRect roi;
- int ptCounter;
- int labelID;
-}SSG_Region;
-
-typedef struct
-{
- double planeCalib[9]; //תƵƽ
- double planeHeight;//ƽĸ߶ȣȥ
- double invRMatrix[9]; //תصԭϵ
-}SSG_planeCalibPara;
-
-typedef struct
-{
- int pntIdx;
- int type;
- double forwardAngle; //ǰ
- double backwardAngle; //
- double corner; //ս
- double forwardDiffZ;
- double backwardDiffZ;
- double pre_stepDist;
- double post_stepDist;
- double forward_z;
- double backward_z;
-}SSG_pntDirAngle;
-
-// ͼݽṹ
-typedef struct {
- int width;
- int height;
- std::vector> gray; // Ҷͼ
- std::vector> markers; // ͼ-1ʾˮ룬0ʾδǣ>0ʾ
-}SWD_waterShedImage;
-
-//ƶάMark
-typedef struct
-{
- int markID;
- SVzNL3DPoint mark3D;
-}SWD_charuco3DMark;
-
-typedef struct
-{
- SVzNL3DPoint pt1;
- SVzNL3DPoint pt2;
-}SWD_3DPointPair;
-
-typedef struct
-{
- int pkId;
- int lineIdx;
- int ptIdx;
- int cptIndex; //Բɨϵĵ
- //double cornerAngle; //ԵΪĵҵļн
- double R;
- double angle;
- double x;
- double y;
- double z;
-}SWD_polarPt;
-
-typedef struct
-{
- int cptIndex;
- int L1_ptIndex;
- int L2_ptIndex;
- double cornerAngle;
- int cornerDir;
-}SWD_polarPeakInfo;
-
-typedef struct
-{
- int clusterIdx;
- int ptSize;
- SVzNL3DRangeD roi3D;
- SVzNLRect roi2D;
-}SWD_clustersInfo;
+#pragma once
+
+#include
+#include
+#include
+
+#define PI 3.14159265358979323846
+
+// ŷǽṹ壨λȣ
+typedef struct{
+ double roll; // Xת
+ double pitch; // Yת
+ double yaw; // Zתƫ
+}SSG_EulerAngles;
+
+//ԹΪX(ɨ跽ƽеZᴹֱΪYᣬֱΪZ
+typedef struct
+{
+ bool validFlag; //ָʾǷЧ
+ double x;
+ double y;
+ double z;
+ double pitchAngle; //ǣYƫת,
+ double rollAngle; //תǣXƫת,
+ double yawAngle; //ƫתǣZƫת,
+}SSG_6AxisAttitude;
+
+typedef struct
+{
+ double x;
+ double y;
+ double z;
+}SWD3DPoint;
+
+typedef struct
+{
+ int lineIdx;
+ int ptIdx;
+ SWD3DPoint point;
+}SWDIndexing3DPoint;
+
+typedef struct
+{
+ int start;
+ int end;
+}SWD_Interval; //
+
+typedef struct
+{
+ bool validFlag; //ָʾǷЧ
+ double x;
+ double y;
+ double z;
+}SSG_3AxisAttitude;
+
+typedef enum
+{
+ keSG_PoseSorting_Uknown = 0,
+ keSG_PoseSorting_ZMin2Max, ///Z
+ keSG_PoseSorting_L2R_T2B, ///ңϵ
+ keSG_PoseSorting_T2B_L2R, ///ϵ£
+} ESG_poseSortingMode;
+
+typedef enum
+{
+ KeWD_Mask_ValidPt = 0,
+ KeWD_Mask_NullPt,
+}EWD_maskMode;
+
+typedef struct
+{
+ int data_0;
+ int data_1;
+ int idx;
+}SSG_intPair;
+
+typedef struct
+{
+ int flag;
+ int validFlag;
+ int clusterID;
+}SSG_clusterLabel;
+
+typedef struct
+{
+ int featurType;
+ int featureIdx_v;
+ int featureIdx_h;
+ int clusterID;
+ int flag;
+ int lineIdx;
+ int ptIdx;
+}SSG_featureClusteringInfo;
+
+typedef struct
+{
+ double left;
+ double right;
+ double top;
+ double bottom;
+}SSG_ROIRectD;
+
+typedef struct
+{
+ double width;
+ double height;
+}SSG_size2D;
+
+typedef struct
+{
+ SVzNL3DPoint center;
+ double radius;
+}SWD_HoleInfo;
+
+struct HSV {
+ double h; // ɫ (0-360)
+ double s; // Ͷ (0-1)
+ double v; // (0-1)
+};
+
+struct RGB {
+ int r;
+ int g;
+ int b;
+};
+
+#define LINE_FEATURE_NUM 16
+#define LINE_FEATURE_UNDEF 0
+#define LINE_FEATURE_L_JUMP_H2L 1
+#define LINE_FEATURE_L_JUMP_L2H 2
+#define LINE_FEATURE_L_SLOPE_H2L 3
+#define LINE_FEATURE_L_SLOPE_L2H 4
+#define LINE_FEATURE_V_SLOPE 5
+#define LINE_FEATURE_LINE_ENDING_0 6 //ending
+#define LINE_FEATURE_LINE_ENDING_1 7 //endingյ
+#define LINE_FEATURE_RGN_EDGE 8 //ʱѾõĿıԵ
+#define LINE_FEATURE_RIGHT_ANGLE_HR 9 //ֱ:ˮƽ-
+#define LINE_FEATURE_RIGHT_ANGLE_HF 10 //ֱ:ˮƽ-½
+#define LINE_FEATURE_RIGHT_ANGLE_RH 11 //ֱ:-ˮƽ
+#define LINE_FEATURE_RIGHT_ANGLE_FH 12 //ֱ:½-ˮƽ
+#define LINE_FEATURE_PEAK_TOP 13
+#define LINE_FEATURE_PEAK_BOTTOM 14
+#define LINE_FEATURE_CORNER_V 15
+
+
+typedef struct
+{
+ int featureType;
+ SVzNL2DPoint jumpPos2D;
+ SVzNL3DPoint jumpPos;
+ double featureValue;
+}SSG_basicFeature1D;
+
+typedef struct
+{
+ int lineIdx;
+ double gap_start;
+ double gap_width;
+ double gap_depth;
+ SVzNL3DPosition gapPt_0; //gapĶ˵
+ SVzNL3DPosition gapPt_1; //gapĶ˵
+ SSG_ROIRectD roi;
+}SSG_basicFeatureGap;
+
+#define FEATURE_FLAG_UNDEF 0
+#define FEATURE_FLAG_INVLD_START 1
+#define FEATURE_FLAG_INVLD_END 2
+#define FEATURE_FLAG_VALID_START 3
+#define FEATURE_FLAG_VALID_END 4
+#define FEATURE_FLAG_INVALID 5
+typedef struct
+{
+ int flag;
+ int lineIdx;
+ int startPtIdx;
+ int endPtIdx;
+ int midPtIdx;
+ SVzNL3DPoint midPt;
+ double width;
+ double pkHeight;
+}SSG_featureSemiCircle;
+
+typedef struct
+{
+ int lineIdx;
+ std::vector features;
+ std::vector endings;
+}SSG_lineFeature;
+
+typedef struct
+{
+ /* ǷޣСڴޣΪ */
+ double continuityTh; //ޡʹzжʱΪzޣʹõжʱΪ
+ /* жޣεĵСڴޣΪ */
+ double outlierTh;
+}SSG_outlierFilterParam;
+
+typedef struct
+{
+ double LSlopeZWin; //LSlope¶ȼĴڳ
+ double validSlopeH;
+ double minLJumpH;
+ double minEndingGap;//ޡڴޣΪ
+}SSG_slopeParam;
+
+typedef struct
+{
+ double minEndingGap; //yޡڴޣΪ
+ double minEndingGap_z; //zޡڴޣΪ
+ double scale; //㷽ǵĴڱ
+ double cornerTh; //սޣڴޣΪЧյ
+ double jumpCornerTh_1; //жϹսǷΪޡһjumpCornerTh_1һСjumpCornerTh_2ʱ
+ double jumpCornerTh_2;
+}SSG_cornerParam;
+
+typedef struct
+{
+ double segGapTh_y; //yޡڴޣΪ
+ double segGapTh_z; //zޡڴޣΪ
+ double distScale; //㷽ǵĴڱ
+}SSG_lineSegParam;
+
+typedef struct
+{
+ double minJumpZ; //z
+ double minK; //Сб
+ SVzNLRangeD widthRange; //zޡڴޣΪ
+}SSG_raisedFeatureParam;
+
+typedef struct
+{
+ double scale_angle; //㷽ǵĴڱ
+ double scale_corner; //㷽תǵĴڱ
+ double cornerTh; //սޣڴޣΪЧArc
+}SSG_gloveArcParam;
+
+typedef struct
+{
+ double H_len; //ֱˮƽεij
+ double V_len; //ֱֱεij
+ double maxDelta;
+}SSG_lineRightAngleParam;
+
+typedef struct
+{
+ double valleyMinH;
+ double valleyMaxW;
+}SSG_VFeatureParam;
+
+typedef struct
+{
+ int lineIdx;
+ int startPtIdx;
+ int endPtIdx;
+ SVzNL3DPoint startPt;
+ SVzNL3DPoint endPt;
+ double featureValue;
+}SWD_segFeature;
+
+typedef struct
+{
+ double sameGapTh;
+ int gapChkWin;
+}SSG_tearFeatureExtactPara;
+typedef struct
+{
+ double yDeviation_max;//ʱYƫ
+ double zDeviation_max; //ʱZƫ
+ int maxLineSkipNum; //ʱ -1ʱʹmaxDkipDistance
+ double maxSkipDistance; //maxLineSkipNumΪ-1 ʹô˲.Ϊ-1ʱ˲Ч
+ double minLTypeTreeLen; //ٵĽڵĿСڴĿƳ
+ double minVTypeTreeLen; //ٵĽڵĿСڴĿƳ
+}SSG_treeGrowParam;
+
+typedef struct
+{
+ double bagL; //
+ double bagW; //
+ double bagH; //
+}SSG_bagParam;
+
+typedef struct
+{
+ double length; //
+ double width; //
+ double height; //
+}SWD_sizeParam;
+
+typedef struct
+{
+ SVzNLRangeD xRange; //< XΧ
+ SVzNLRangeD yRange; //< YΧ
+ SVzNLRangeD zRange; //< ZΧ
+ double scale_x;
+ double scale_y;
+} SWD_pointCloudPara;
+
+typedef struct
+{
+ ESG_poseSortingMode sortMode;
+}SSG_objSortParam;
+
+typedef struct
+{
+ double angleStep;
+ double radiusStep;
+}SSG_polarScanParam;
+
+typedef struct
+{
+ int treeState;
+ int treeType;
+ int sLineIdx;
+ int eLineIdx;
+ double tree_value;
+ SSG_ROIRectD roi;
+ std::vector< SSG_basicFeature1D> treeNodes;
+ int angleChkScalePos; //ڼangleCheckٶ
+}SSG_featureTree;
+
+typedef struct
+{
+ int treeState;
+ int treeType;
+ int sLineIdx;
+ int eLineIdx;
+ double tree_value;
+ SSG_ROIRectD roi;
+ std::vector< SSG_basicFeatureGap> treeNodes;
+ int angleChkScalePos; //ڼangleCheckٶ
+}SSG_gapFeatureTree;
+
+typedef struct
+{
+ int treeState;
+ int treeType;
+ int sLineIdx;
+ int eLineIdx;
+ SSG_ROIRectD roi;
+ SVzNL3DPoint centerPt;
+ SVzNL2DPoint centerPos;
+ int treeMidType; //1:Ѿӹ
+ std::vector< SSG_featureSemiCircle> treeNodes;
+}SSG_semiCircleFeatureTree;
+
+typedef struct
+{
+ int treeState;
+ int sLineIdx;
+ int eLineIdx;
+ double tree_value;
+ std::vector< SWD_segFeature> treeNodes;
+}SWD_segFeatureTree;
+
+typedef struct
+{
+ int vTreeFlag;
+ int treeIdx;
+ int treeType;
+ int sLineIdx;
+ int eLineIdx;
+ SSG_ROIRectD roi;
+}SSG_treeInfo;
+
+typedef struct
+{
+ int seachW_lines;
+ int searchW_pts;
+}SSG_localPkParam;
+
+typedef struct
+{
+ int x;
+ int y;
+ int value;
+ double valueD;
+ int sideID; //1-T, 2-B, 3-L, 4-R
+}SSG_2DValueI;
+
+typedef struct
+{
+ int start;
+ int len;
+ int value;
+}SSG_RUN;
+
+typedef struct
+{
+ int start;
+ int len;
+ int value;
+ bool start_zRising; //z־
+ bool end_zRising;//յz־
+}SSG_RUN_EX;
+
+typedef struct
+{
+ double mean;
+ double var;
+}SSG_meanVar;
+
+typedef struct
+{
+ int x;
+ int y;
+ int type;
+ int edgeId;
+ int blockFlag;//ڵ־
+ double scanDist;
+ SVzNL3DPoint edgePt;
+}SSG_contourPtInfo;
+
+typedef struct
+{
+ int lineIdx;
+ std::vector contourPts;
+}SSG_lineConotours;
+
+typedef struct
+{
+ int lineIdx;
+ int edgeId_0;
+ int edgeId_1;
+ double ptPairDist;
+ SSG_contourPtInfo contourPt_0;
+ SSG_contourPtInfo contourPt_1;
+}SSG_conotourPair;
+
+typedef struct
+{
+ double x;
+ double y;
+ double z;
+ double x_roll;
+ double y_pitch;
+ double z_yaw;
+}SSG_6DOF;
+
+typedef struct
+{
+ double L;
+ double W;
+ double H;
+ double angle;
+ SVzNL3DPoint endings[4];
+} SSG_boxCarDimension;
+
+typedef struct
+{
+ int objID;
+ SSG_6DOF opCenter; //λ
+}SWD_statorInnerGrasper;
+
+typedef struct
+{
+ int objID;
+ double grasperAngle;
+ double rotateAngle; //ץ0λʱΪѾΣ120ȡ
+ double graspR;
+}SWD_statorOuterGrasper;
+
+typedef struct
+{
+ int pkRgnIdx;
+ SVzNLSizeD objSize;
+ SVzNL2DPoint pos2D;
+ SSG_6DOF centerPos;
+}SSG_peakRgnInfo;
+
+typedef struct
+{
+ int pkRgnIdx;
+ SVzNLSizeD objSize;
+ SVzNL2DPoint pos2D;
+ SSG_6DOF centerPos;
+ int orienFlag; //0-δ֪1 - 棬 2-
+}SSG_peakOrienRgnInfo;
+
+typedef struct
+{
+ SVzNL3DPoint sPt;
+ SVzNL3DPoint ePt;
+ double scanDist;
+ int ptNum;
+}SSG_contourEdgeInfo;
+
+typedef struct
+{
+ double meanDist;
+ double varDist;
+ double minDist;
+ double maxDist;
+ int matchNum;
+ int level2_num; //level2Ϊ߿Ŷ(ΪJumpEnding;
+ int level1_num; //level1-ΪпŶȣһΪJumpEnding
+ SSG_ROIRectD roi;
+}SSG_edgeMatchInfo;
+
+typedef struct
+{
+ int id1;
+ int id2;
+ int matchPts;
+ int matchType; //Ŷȣ 2Ϊ߿Ŷ(ΪJumpEnding; 1-ΪпŶȣһΪJumpEnding0-ΪͿŶ
+ double matchValue;
+ double varValue;
+ double minMatchValue;
+ double maxMatchValue;
+ SSG_ROIRectD roi;
+}SSG_matchPair;
+
+typedef struct
+{
+ int objIdx;
+ bool isValid; //ǷΪϸĿꡣĿ꣬֯ţɨ赽ߣΪϸĿ
+ SSG_ROIRectD objROI;
+ SVzNL3DPoint objPos;
+ SSG_6DOF graspPos;
+}SSG_sideBagInfo;
+
+typedef struct
+{
+ SVzNLRect roi;
+ int ptCounter;
+ int labelID;
+}SSG_Region;
+
+typedef struct
+{
+ double planeCalib[9]; //תƵƽ
+ double planeHeight;//ƽĸ߶ȣȥ
+ double invRMatrix[9]; //תصԭϵ
+}SSG_planeCalibPara;
+
+typedef struct
+{
+ int pkId;
+ int lineIdx;
+ int ptIdx;
+ int cptIndex; //Բɨϵĵ
+ //double cornerAngle; //ԵΪĵҵļн
+ double R;
+ double angle;
+ double x;
+ double y;
+ double z;
+}SWD_polarPt;
+
+typedef struct
+{
+ int pntIdx;
+ int type;
+ double forwardAngle; //ǰ
+ double backwardAngle; //
+ double corner; //ս
+ double forwardDiffZ;
+ double backwardDiffZ;
+ double pre_stepDist;
+ double post_stepDist;
+ double forward_z;
+ double backward_z;
+}SSG_pntDirAngle;
+
+typedef struct
+{
+ double forwardAngle; //ǰ
+ double backwardAngle; //
+ double corner; //ս
+ int pntIdx;
+ int forward_pntIdx;
+ int backward_pntIdx;
+ int flag;
+ SWD_polarPt point;
+}SSG_dirCornerAngle;
+
+// ͼݽṹ
+typedef struct {
+ int width;
+ int height;
+ std::vector> gray; // Ҷͼ
+ std::vector> markers; // ͼ-1ʾˮ룬0ʾδǣ>0ʾ
+}SWD_waterShedImage;
+
+//ƶάMark
+typedef struct
+{
+ int markID;
+ SVzNL3DPoint mark3D;
+}SWD_charuco3DMark;
+
+typedef struct
+{
+ SVzNL3DPoint pt1;
+ SVzNL3DPoint pt2;
+}SWD_3DPointPair;
+
+typedef struct
+{
+ int cptIndex;
+ int L1_ptIndex;
+ int L2_ptIndex;
+ double cornerAngle;
+ int cornerDir;
+ int flag;
+ SWD_polarPt point;
+}SWD_polarPeakInfo;
+
+typedef struct
+{
+ int clusterIdx;
+ int ptSize;
+ SVzNL3DRangeD roi3D;
+ SVzNLRect roi2D;
+}SWD_clustersInfo;
diff --git a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_errCode.h b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_errCode.h
index 0c90f71d..2b493b57 100644
--- a/AppAlgo/wheelArchHeigthMeasure/Inc/SG_errCode.h
+++ b/AppAlgo/wheelArchHeigthMeasure/Inc/SG_errCode.h
@@ -1,30 +1,38 @@
-#pragma once
-
-#define SG_ERR_3D_DATA_INVLD -1000
-#define SG_ERR_3D_DATA_NULL -1001
-#define SG_ERR_FOUND_NO_TOP_PLANE -1002
-#define SG_ERR_NOT_GRID_FORMAT -1003
-#define SG_ERR_LABEL_INFO_ERROR -1004
-#define SG_ERR_INVLD_SORTING_MODE -1005
-#define SG_ERR_INVLD_Q_SCALE -1006
-
-//BQ_workpiece
-#define SX_ERR_INVLD_VTREE_NUM -2001
-#define SX_ERR_INVLD_HTREE_NUM -2002
-#define SX_ERR_INVLD_EDGE_LINK_NUM -2003
-#define SX_ERR_INVLD_CLOSES_PT -2004
-#define SX_ERR_ZERO_CONTOUR_PT -2005
-#define SX_ERR_INVLID_RPEAK_NUM -2006
-#define SX_ERR_INVLID_RPEAK_PAIR -2007
-#define SX_ERR_INVLID_MARK_NUM -2008
-
-//ץȡ
-#define SX_ERR_INVLID_CUTTING_Z -2101
-#define SX_ERR_ZERO_OBJ -2102
-
-//
-#define SX_BAG_TRAY_EMPTY -2201
-
-//ü߶Ȳ
-#define SX_ERR_INVALID_ARC -2301
-
+#pragma once
+
+#define SG_ERR_3D_DATA_INVLD -1000
+#define SG_ERR_3D_DATA_NULL -1001
+#define SG_ERR_FOUND_NO_TOP_PLANE -1002
+#define SG_ERR_NOT_GRID_FORMAT -1003
+#define SG_ERR_LABEL_INFO_ERROR -1004
+#define SG_ERR_INVLD_SORTING_MODE -1005
+#define SG_ERR_INVLD_Q_SCALE -1006
+#define SG_ERR_ZERO_OBJECTS -1007
+#define SG_ERR_LASER_DIR_NOT_SUPPORTED -1008
+#define SG_ERR_SCAN_DIR_NOT_SUPPORTED -1009
+
+//BQ_workpiece
+#define SX_ERR_INVLD_VTREE_NUM -2001
+#define SX_ERR_INVLD_HTREE_NUM -2002
+#define SX_ERR_INVLD_EDGE_LINK_NUM -2003
+#define SX_ERR_INVLD_CLOSES_PT -2004
+#define SX_ERR_ZERO_CONTOUR_PT -2005
+#define SX_ERR_INVLID_RPEAK_NUM -2006
+#define SX_ERR_INVLID_RPEAK_PAIR -2007
+#define SX_ERR_INVLID_MARK_NUM -2008
+
+//ץȡ
+#define SX_ERR_INVLID_CUTTING_Z -2101
+#define SX_ERR_ZERO_OBJ_TOPLAYER -2102
+#define SX_ERR_ZERO_OBJ_BTMLAYER -2103
+#define SX_ERR_GET_INVALID_PALTE -2104 //ȡ
+
+//
+#define SX_BAG_TRAY_EMPTY -2201
+
+//ü߶Ȳ
+#define SX_ERR_INVALID_ARC -2301
+
+//ǴӲ
+#define SX_ERR_NO_MARK -2401
+
diff --git a/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h b/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
index d2b89128..0f952de9 100644
--- a/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
+++ b/AppAlgo/wheelArchHeigthMeasure/Inc/wheelArchHeigthMeasure_Export.h
@@ -1,44 +1,49 @@
-#pragma once
-
-#include "SG_algo_Export.h"
-#include
-
-#define _OUTPUT_DEBUG_DATA 1
-
-typedef struct
-{
- SVzNL3DPoint wheelArchPos;
- SVzNL3DPoint wheelUpPos;
- SVzNL3DPoint wheelDownPos;
- SVzNL3DPoint arcLine[2];
- SVzNL3DPoint upLine[2];
- SVzNL3DPoint downLine[2];
- SVzNL3DPoint centerLine[2];
- double archToCenterHeigth;
- double archToGroundHeigth;
-}WD_wheelArchInfo;
-
-//汾
-SG_APISHARED_EXPORT const char* wd_wheelArchHeigthMeasureVersion(void);
-
-//ˮƽװƽ
-//ZƽеʱҪԵΪգˮƽ
-//תΪƽƽ淨ΪֱIJ
-SG_APISHARED_EXPORT SSG_planeCalibPara wd_horizonCamera_getGroundCalibPara(
- std::vector< std::vector>& scanLines);
-
-//ˮƽʱ̬ƽȥ
-SG_APISHARED_EXPORT void wd_horizonCamera_lineDataR(
- std::vector< SVzNL3DPosition>& a_line,
- const double* camPoseR,
- double groundH);
-
-//ȡǵ㼰λϢ
-SG_APISHARED_EXPORT WD_wheelArchInfo wd_wheelArchHeigthMeasure(
- std::vector< std::vector>& scanLines,
- const SSG_cornerParam cornerPara,
- const SSG_lineSegParam lineSegPara,
- const SSG_outlierFilterParam filterParam,
- const SSG_treeGrowParam growParam,
- const SSG_planeCalibPara groundCalibPara,
- int* errCode);
+#pragma once
+
+#include "SG_algo_Export.h"
+#include
+
+#define _OUTPUT_DEBUG_DATA 1
+
+typedef struct
+{
+ SVzNL3DPoint wheelArchPos;
+ SVzNL3DPoint wheelUpPos;
+ SVzNL3DPoint wheelDownPos;
+ SVzNL3DPoint arcLine[2];
+ SVzNL3DPoint upLine[2];
+ SVzNL3DPoint downLine[2];
+ SVzNL3DPoint centerLine[2];
+ double archToCenterHeigth;
+ double archToGroundHeigth;
+}WD_wheelArchInfo;
+
+//汾
+SG_APISHARED_EXPORT const char* wd_wheelArchHeigthMeasureVersion(void);
+
+//ˮƽװƽ
+//ZƽеʱҪԵΪգˮƽ
+//תΪƽƽ淨ΪֱIJ
+SG_APISHARED_EXPORT SSG_planeCalibPara wd_horizonCamera_getGroundCalibPara(
+ std::vector< std::vector>& scanLines);
+
+//ˮƽʱ̬ƽȥ
+SG_APISHARED_EXPORT void wd_horizonCamera_lineDataR(
+ std::vector< SVzNL3DPosition>& a_line,
+ const double* camPoseR,
+ double groundH);
+
+//ˮƽʱ̬ƽȥ
+SG_APISHARED_EXPORT bool wd_wheelPresenseDetection(
+ std::vector>& scanLine,
+ const SVzNL3DRangeD wheelRoi3d);
+
+//ȡǵ㼰λϢ
+SG_APISHARED_EXPORT WD_wheelArchInfo wd_wheelArchHeigthMeasure(
+ std::vector< std::vector>& scanLines,
+ const SSG_cornerParam cornerPara,
+ const SSG_lineSegParam lineSegPara,
+ const SSG_outlierFilterParam filterParam,
+ const SSG_treeGrowParam growParam,
+ const SSG_planeCalibPara groundCalibPara,
+ int* errCode);
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll
index 51ec9995..39a69344 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.lib b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.lib
index a5111f24..9f759a09 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.lib and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.lib differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb
index 2dd5e466..1e91f1a1 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/baseAlgorithm.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll
index c5773bdb..8f85a243 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.lib b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.lib
index 1cd911f9..e191b052 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.lib and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.lib differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb
index fe7d6754..982d1627 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Debug/wheelArchHeigthMeasure.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll
index 818d8d15..fd5f4d9a 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.lib b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.lib
index 2aeb591c..b77e18b4 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.lib and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.lib differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb
index a1f35417..2ce77bcc 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/baseAlgorithm.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll
index 8458365c..d3553fc0 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.dll differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.lib b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.lib
index 2a0ff173..11866f50 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.lib and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.lib differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb
index e9cc296b..099c0d52 100644
Binary files a/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb and b/AppAlgo/wheelArchHeigthMeasure/Windows/x64/Release/wheelArchHeigthMeasure.pdb differ
diff --git a/AppAlgo/wheelArchHeigthMeasure/wheelArchHeigthMeasure_test.cpp b/AppAlgo/wheelArchHeigthMeasure/wheelArchHeigthMeasure_test.cpp
index e70f1b0f..20081c8d 100644
--- a/AppAlgo/wheelArchHeigthMeasure/wheelArchHeigthMeasure_test.cpp
+++ b/AppAlgo/wheelArchHeigthMeasure/wheelArchHeigthMeasure_test.cpp
@@ -1,2839 +1,2849 @@
-// wheelArchHeigthMeasure_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
-//
-#include
-#include
-#include
-#include
-#include
-#include
-#include "wheelArchHeigthMeasure_Export.h"
-#include
-#ifdef _WIN32
-#include
-#include "direct.h"
-#endif
-
-typedef struct
-{
- int nPointIdx;
- double x;
- double y;
- double z;
- float r;
- float g;
- float b;
-} SPointXYZRGB;
-
-SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
-{
- SVzNL3DPoint _r_pt;
- _r_pt.x = pt3D.x * matrix3d[0] + pt3D.y * matrix3d[1] + pt3D.z * matrix3d[2];
- _r_pt.y = pt3D.x * matrix3d[3] + pt3D.y * matrix3d[4] + pt3D.z * matrix3d[5];
- _r_pt.z = pt3D.x * matrix3d[6] + pt3D.y * matrix3d[7] + pt3D.z * matrix3d[8];
- return _r_pt;
-}
-
-SVzNLPointXYZRGBA _ptRotate_RGBD(SVzNLPointXYZRGBA pt3D, double matrix3d[9])
-{
- SVzNLPointXYZRGBA _r_pt;
- _r_pt.x = pt3D.x * matrix3d[0] + pt3D.y * matrix3d[1] + pt3D.z * matrix3d[2];
- _r_pt.y = pt3D.x * matrix3d[3] + pt3D.y * matrix3d[4] + pt3D.z * matrix3d[5];
- _r_pt.z = pt3D.x * matrix3d[6] + pt3D.y * matrix3d[7] + pt3D.z * matrix3d[8];
- return _r_pt;
-}
-
-#define DATA_VER_OLD 0
-#define DATA_VER_NEW 1
-#define DATA_VER_FROM_CUSTOM 2
-#define VZ_LASER_LINE_PT_MAX_NUM 4096
-SVzNLXYZRGBDLaserLine* vzReadLaserScanPointFromFile_XYZRGB(const char* fileName, int* scanLineNum, float* scanV,
- int* dataCalib, int* scanMaxStamp, int* canClockUnit, bool removeNullLines)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return NULL;
-
- SVzNLXYZRGBDLaserLine* _scanLines = NULL;
-
- int lines = 0;
- int dataElements = 4;
- int firstIndex = -1;
-
- int dataFileVer = DATA_VER_OLD;
- std::getline(inputFile, linedata); //第一行
- int lineNum = 0;
- if (0 == strncmp("LineNum:", linedata.c_str(), 8))
- {
- sscanf_s(linedata.c_str(), "LineNum:%d", &lines);
- if (lines == 0)
- return NULL;
- lineNum = lines;
- _scanLines = (SVzNLXYZRGBDLaserLine*)malloc(sizeof(SVzNLXYZRGBDLaserLine) * (lineNum + 1));
- memset(_scanLines, 0, sizeof(SVzNLXYZRGBDLaserLine) * (lineNum + 1));
- }
- if (_scanLines == NULL)
- return NULL;
-
- int lineIdx = 0;
- int ptIdx = 0;
- int ptNum = 0;
- int pre_ptNum = -1;
- std::vector< SVzNLPointXYZRGBA> a_line;
- int vldLineIdx = 0;
- int vldPtNum = 0;
- unsigned int timeStamp = 0;
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("ScanSpeed:", linedata.c_str(), 10))
- {
- double lineV = 0;
- sscanf_s(linedata.c_str(), "ScanSpeed:%lf", &lineV);
- if (scanV)
- *scanV = (float)lineV;
- }
- else if (0 == strncmp("PointAdjust:", linedata.c_str(), 12))
- {
- int ptAdjusted = 0;
- sscanf_s(linedata.c_str(), "PointAdjust:%d", &ptAdjusted);
- if (dataCalib)
- *dataCalib = ptAdjusted;
- }
- else if (0 == strncmp("MaxTimeStamp:", linedata.c_str(), 13))
- {
- unsigned int maxTimeStamp = 0;
- unsigned int timePerStamp = 0;
- sscanf_s(linedata.c_str(), "MaxTimeStamp:%u_%u", &maxTimeStamp, &timePerStamp);
- if (scanMaxStamp)
- *scanMaxStamp = maxTimeStamp;
- if (canClockUnit)
- *canClockUnit = timePerStamp;
- }
- else if (0 == strncmp("Line_", linedata.c_str(), 5))
- {
- int lineIndex;
- unsigned int curr_timeStamp;
- sscanf_s(linedata.c_str(), "Line_%d_%u_%d", &lineIndex, &curr_timeStamp, &ptNum);
- if (firstIndex < 0)
- firstIndex = lineIndex;
-
- lineIndex = lineIndex - firstIndex;
- if ((lineIndex < 0) || (lineIndex >= lines))
- break;
-
- int recvPtNum = (int)a_line.size();
- if ((recvPtNum == pre_ptNum) && ((vldPtNum > 0) || (false == removeNullLines)))
- {
- SVzNLPointXYZRGBA* p3DPoint;
- if (pre_ptNum > 0)
- p3DPoint = (SVzNLPointXYZRGBA*)malloc(sizeof(SVzNLPointXYZRGBA) * pre_ptNum);
- else
- p3DPoint = NULL;
- _scanLines[vldLineIdx].nPointCnt = pre_ptNum;
- _scanLines[vldLineIdx].nTimeStamp = timeStamp;
- _scanLines[vldLineIdx].p3DPoint = p3DPoint;
- for (int m = 0; m < pre_ptNum; m++)
- p3DPoint[m] = a_line[m];
- vldLineIdx++;
- }
- //new Line
- timeStamp = curr_timeStamp;
- vldPtNum = 0;
- a_line.clear();
- pre_ptNum = ptNum;
- }
- else if (0 == strncmp("{", linedata.c_str(), 1))
- {
- float X, Y, Z;
- int imageY = 0;
- float leftX, leftY;
- float rightX, rightY;
- float r, g, b;
- sscanf_s(linedata.c_str(), "{%f,%f,%f,%f,%f,%f }-{%f,%f}-{%f,%f}", &X, &Y, &Z, &r, &g, &b, &leftX, &leftY, &rightX, &rightY);
- {
- if (lineIdx == 537)
- int kkk = 1;
-
- SVzNLPointXYZRGBA a_pt;
-
- a_pt.x = X;
- a_pt.y = Y;
- a_pt.z = Z;
- int nr = (int)(r * 255);
- int ng = (int)(g * 255);
- int nb = (int)(b * 255);
- nb <<= 8;
- nb += ng;
- nb <<= 8;
- nb += nr;
- a_pt.nRGB = nb;
- if (a_pt.z > 1e-4)
- vldPtNum++;
- a_line.push_back(a_pt);
- }
- }
- }
- //last line
- int recvPtNum = (int)a_line.size();
- if ((recvPtNum == pre_ptNum) && ((vldPtNum > 0) || (false == removeNullLines)))
- {
- SVzNLPointXYZRGBA* p3DPoint;
- if (pre_ptNum > 0)
- p3DPoint = (SVzNLPointXYZRGBA*)malloc(sizeof(SVzNLPointXYZRGBA) * pre_ptNum);
- else
- p3DPoint = NULL;
- _scanLines[vldLineIdx].nPointCnt = pre_ptNum;
- _scanLines[vldLineIdx].nTimeStamp = timeStamp;
- _scanLines[vldLineIdx].p3DPoint = p3DPoint;
- for (int m = 0; m < pre_ptNum; m++)
- p3DPoint[m] = a_line[m];
- vldLineIdx++;
- }
-
- if (scanLineNum)
- *scanLineNum = vldLineIdx;
- inputFile.close();
- return _scanLines;
-}
-
-void vzReadLaserScanPointFromFile_XYZRGB_vector(const char* fileName, std::vector>&scanData)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return;
-
- std::vector< SPointXYZRGB> a_line;
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("Line_", linedata.c_str(), 5)) //new line
- {
- if (a_line.size() > 0)
- {
- scanData.push_back(a_line);
- a_line.clear();
- }
- }
- else if (0 == strncmp("{", linedata.c_str(), 1))
- {
- float leftX, leftY;
- float rightX, rightY;
- SPointXYZRGB a_pt;
- sscanf_s(linedata.c_str(), "{ %lf, %lf, %lf, %f, %f, %f }-{ %f, %f }-{ %f, %f }", &a_pt.x, &a_pt.y, &a_pt.z, &a_pt.r, &a_pt.g, &a_pt.b, &leftX, &leftY, &rightX, &rightY);
- a_line.push_back(a_pt);
- }
- }
- if (a_line.size() > 0)
- scanData.push_back(a_line);
-
- inputFile.close();
- return;
-}
-
-void vzReadPlyTxtPointFromFile_XYZRGB_vector(const char* fileName, std::vector>& scanData)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return;
-
- const double lineYGap = 50;
- std::vector< SVzNLPointXYZRGBA> a_line;
-
- double pre_y = FLT_MIN;
- while (getline(inputFile, linedata))
- {
- SVzNLPointXYZRGBA a_pt;
- memset(&a_pt, 0, sizeof(SVzNLPointXYZRGBA));
- double _x, _y, _z;
- sscanf_s(linedata.c_str(), "%lf %lf %lf", &_x, &_y, &_z);
- a_pt.x = (float)_x;
- a_pt.y = (float)_y;
- a_pt.z = (float)_z;
- if(a_pt.y < pre_y - lineYGap) //新的扫描行
- {
- if (a_line.size() > 0)
- {
- scanData.push_back(a_line);
- a_line.clear();
- }
- }
- pre_y = a_pt.y;
- a_line.push_back(a_pt);
- }
- if (a_line.size() > 0)
- scanData.push_back(a_line);
-
- inputFile.close();
- return;
-}
-
-SVzNL3DLaserLine* vzReadLaserScanPointFromFile_XYZ(const char* fileName, int* scanLineNum, float* scanV,
- int* dataCalib, int* scanMaxStamp, int* canClockUnit)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return NULL;
-
- SVzNL3DLaserLine* _scanLines = NULL;
-
- int lines = 0;
- int dataElements = 4;
- int firstIndex = -1;
-
- int dataFileVer = DATA_VER_OLD;
- std::getline(inputFile, linedata); //第一行
- int lineNum = 0;
- if (0 == strncmp("LineNum:", linedata.c_str(), 8))
- {
- dataFileVer = DATA_VER_NEW;
- sscanf_s(linedata.c_str(), "LineNum:%d", &lines);
- if (lines == 0)
- return NULL;
- lineNum = lines;
- _scanLines = (SVzNL3DLaserLine*)malloc(sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- memset(_scanLines, 0, sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- if (scanLineNum)
- *scanLineNum = lines;
- }
- else if (0 == strncmp("LineNum_", linedata.c_str(), 8))
- {
- dataFileVer = DATA_VER_OLD;
- sscanf_s(linedata.c_str(), "LineNum_%d", &lines);
- if (lines == 0)
- return NULL;
- lineNum = lines;
- _scanLines = (SVzNL3DLaserLine*)malloc(sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- memset(_scanLines, 0, sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- if (scanLineNum)
- *scanLineNum = lines;
- }
- if (_scanLines == NULL)
- return NULL;
-
- int ptNum = 0;
- int lineIdx = -1;
- int ptIdx = 0;
- SVzNL3DPosition* p3DPoint = NULL;
- if (dataFileVer == DATA_VER_NEW)
- {
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("ScanSpeed:", linedata.c_str(), 10))
- {
- double lineV = 0;
- sscanf_s(linedata.c_str(), "ScanSpeed:%lf", &lineV);
- if (scanV)
- *scanV = (float)lineV;
- }
- else if (0 == strncmp("PointAdjust:", linedata.c_str(), 12))
- {
- int ptAdjusted = 0;
- sscanf_s(linedata.c_str(), "PointAdjust:%d", &ptAdjusted);
- if (dataCalib)
- *dataCalib = ptAdjusted;
- }
- else if (0 == strncmp("MaxTimeStamp:", linedata.c_str(), 13))
- {
- unsigned int maxTimeStamp = 0;
- unsigned int timePerStamp = 0;
- sscanf_s(linedata.c_str(), "MaxTimeStamp:%u_%u", &maxTimeStamp, &timePerStamp);
- if (scanMaxStamp)
- *scanMaxStamp = maxTimeStamp;
- if (canClockUnit)
- *canClockUnit = timePerStamp;
- }
- else if (0 == strncmp("Line_", linedata.c_str(), 5))
- {
- int lineIndex;
- unsigned int timeStamp;
- sscanf_s(linedata.c_str(), "Line_%d_%u_%d", &lineIndex, &timeStamp, &ptNum);
- if (firstIndex < 0)
- firstIndex = lineIndex;
-
- lineIndex = lineIndex - firstIndex;
- if ((lineIndex < 0) || (lineIndex >= lines))
- break;
-
- //new Line
- lineIdx++;
- if (ptNum > 0)
- {
- p3DPoint = (SVzNL3DPosition*)malloc(sizeof(SVzNL3DPosition) * ptNum);
- memset(p3DPoint, 0, sizeof(SVzNL3DPosition) * ptNum);
- }
- else
- p3DPoint = NULL;
- _scanLines[lineIdx].nPositionCnt = 0;
- _scanLines[lineIdx].nTimeStamp = timeStamp;
- _scanLines[lineIdx].p3DPosition = p3DPoint;
-
- }
- else if (0 == strncmp("{", linedata.c_str(), 1))
- {
- float X, Y, Z;
- int imageY = 0;
- float leftX, leftY;
- float rightX, rightY;
- sscanf_s(linedata.c_str(), "{%f,%f,%f}-{%f,%f}-{%f,%f}", &X, &Y, &Z, &leftX, &leftY, &rightX, &rightY);
- int id = _scanLines[lineIdx].nPositionCnt;
- if (id < ptNum)
- {
- p3DPoint[id].pt3D.x = X;
- p3DPoint[id].pt3D.y = Y;
- p3DPoint[id].pt3D.z = Z;
- _scanLines[lineIdx].nPositionCnt = id + 1;
- }
- }
- }
-
- }
- else if (dataFileVer == DATA_VER_OLD)
- {
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("DataElements_", linedata.c_str(), 13))
- {
- sscanf_s(linedata.c_str(), "DataElements_%d", &dataElements);
- if ((dataElements != 3) && (dataElements != 4))
- break;
- }
- if (0 == strncmp("LineV_", linedata.c_str(), 6))
- {
- double lineV = 0;
- sscanf_s(linedata.c_str(), "LineV_%lf", &lineV);
- }
- else if (0 == strncmp("Line_", linedata.c_str(), 5))
- {
- int lineIndex;
- unsigned int timeStamp;
- sscanf_s(linedata.c_str(), "Line_%d_%u", &lineIndex, &timeStamp);
-#if 0
- if (scanLineListTail == NULL)
- firstIndex = lineIndex;
-#endif
- lineIndex = lineIndex - firstIndex;
- if ((lineIndex < 0) || (lineIndex >= lines))
- break;
- //new Line
- //new Line
- lineIdx++;
- p3DPoint = (SVzNL3DPosition*)malloc(sizeof(SVzNL3DPosition) * VZ_LASER_LINE_PT_MAX_NUM);
- memset(p3DPoint, 0, sizeof(SVzNL3DPosition) * VZ_LASER_LINE_PT_MAX_NUM);
- _scanLines[lineIdx].nPositionCnt = 0;
- _scanLines[lineIdx].nTimeStamp = timeStamp;
- _scanLines[lineIdx].p3DPosition = p3DPoint;
- }
- else if (0 == strncmp("(", linedata.c_str(), 1))
- {
- float X, Y, Z;
- int imageY = 0;
- if (dataElements == 4)
- sscanf_s(linedata.c_str(), "(%f,%f,%f,%d)", &X, &Y, &Z, &imageY);
- else
- sscanf_s(linedata.c_str(), "(%f,%f,%f)", &X, &Y, &Z);
- int id = _scanLines[lineIdx].nPositionCnt;
- if (id < VZ_LASER_LINE_PT_MAX_NUM)
- {
- p3DPoint[id].pt3D.x = X;
- p3DPoint[id].pt3D.y = Y;
- p3DPoint[id].pt3D.z = Z;
- _scanLines[lineIdx].nPositionCnt = id + 1;
- }
- }
- }
- }
- inputFile.close();
- return _scanLines;
-}
-
-//从RGBD点云中读取XYZ信息
-SVzNL3DLaserLine* vzReadXYZPointFromFile_XYZRGB(const char* fileName, int* scanLineNum, float* scanV,
- int* dataCalib, int* scanMaxStamp, int* canClockUnit)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return NULL;
-
- SVzNL3DLaserLine* _scanLines = NULL;
-
- int lines = 0;
- int dataElements = 4;
- int firstIndex = -1;
-
- int dataFileVer = DATA_VER_OLD;
- std::getline(inputFile, linedata); //第一行
- int lineNum = 0;
- if (0 == strncmp("LineNum:", linedata.c_str(), 8))
- {
- dataFileVer = DATA_VER_NEW;
- sscanf_s(linedata.c_str(), "LineNum:%d", &lines);
- if (lines == 0)
- return NULL;
- lineNum = lines;
- _scanLines = (SVzNL3DLaserLine*)malloc(sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- memset(_scanLines, 0, sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- if (scanLineNum)
- *scanLineNum = lines;
- }
- else if (0 == strncmp("LineNum_", linedata.c_str(), 8))
- {
- dataFileVer = DATA_VER_OLD;
- sscanf_s(linedata.c_str(), "LineNum_%d", &lines);
- if (lines == 0)
- return NULL;
- lineNum = lines;
- _scanLines = (SVzNL3DLaserLine*)malloc(sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- memset(_scanLines, 0, sizeof(SVzNL3DLaserLine) * (lineNum + 1));
- if (scanLineNum)
- *scanLineNum = lines;
- }
- if (_scanLines == NULL)
- return NULL;
-
- int ptNum = 0;
- int lineIdx = -1;
- int ptIdx = 0;
- SVzNL3DPosition* p3DPoint = NULL;
- if (dataFileVer == DATA_VER_NEW)
- {
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("ScanSpeed:", linedata.c_str(), 10))
- {
- double lineV = 0;
- sscanf_s(linedata.c_str(), "ScanSpeed:%lf", &lineV);
- if (scanV)
- *scanV = (float)lineV;
- }
- else if (0 == strncmp("PointAdjust:", linedata.c_str(), 12))
- {
- int ptAdjusted = 0;
- sscanf_s(linedata.c_str(), "PointAdjust:%d", &ptAdjusted);
- if (dataCalib)
- *dataCalib = ptAdjusted;
- }
- else if (0 == strncmp("MaxTimeStamp:", linedata.c_str(), 13))
- {
- unsigned int maxTimeStamp = 0;
- unsigned int timePerStamp = 0;
- sscanf_s(linedata.c_str(), "MaxTimeStamp:%u_%u", &maxTimeStamp, &timePerStamp);
- if (scanMaxStamp)
- *scanMaxStamp = maxTimeStamp;
- if (canClockUnit)
- *canClockUnit = timePerStamp;
- }
- else if (0 == strncmp("Line_", linedata.c_str(), 5))
- {
- int lineIndex;
- unsigned int timeStamp;
- sscanf_s(linedata.c_str(), "Line_%d_%u_%d", &lineIndex, &timeStamp, &ptNum);
- if (firstIndex < 0)
- firstIndex = lineIndex;
-
- lineIndex = lineIndex - firstIndex;
- if ((lineIndex < 0) || (lineIndex >= lines))
- break;
-
- //new Line
- lineIdx++;
- if (ptNum > 0)
- {
- p3DPoint = (SVzNL3DPosition*)malloc(sizeof(SVzNL3DPosition) * ptNum);
- memset(p3DPoint, 0, sizeof(SVzNL3DPosition) * ptNum);
- }
- else
- p3DPoint = NULL;
- _scanLines[lineIdx].nPositionCnt = 0;
- _scanLines[lineIdx].nTimeStamp = timeStamp;
- _scanLines[lineIdx].p3DPosition = p3DPoint;
-
- }
- else if (0 == strncmp("{", linedata.c_str(), 1))
- {
- float X, Y, Z;
- float leftX, leftY;
- float rightX, rightY;
- float r, g, b;
- sscanf_s(linedata.c_str(), "{%f,%f,%f,%f,%f,%f }-{%f,%f}-{%f,%f}", &X, &Y, &Z, &r, &g, &b, &leftX, &leftY, &rightX, &rightY);
- int id = _scanLines[lineIdx].nPositionCnt;
- if (id < ptNum)
- {
- p3DPoint[id].pt3D.x = X;
- p3DPoint[id].pt3D.y = Y;
- p3DPoint[id].pt3D.z = Z;
- _scanLines[lineIdx].nPositionCnt = id + 1;
- }
- }
- }
-
- }
- inputFile.close();
- return _scanLines;
-}
-
-void vzReadLaserScanPointFromFile_XYZ_vector(const char* fileName, std::vector>& scanData)
-{
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return;
-
- std::vector< SVzNL3DPosition> a_line;
- int ptIdx = 0;
- while (getline(inputFile, linedata))
- {
- if (0 == strncmp("Line_", linedata.c_str(), 5))
- {
- int ptSize = (int)a_line.size();
- if (ptSize > 0)
- {
- scanData.push_back(a_line);
- }
- a_line.clear();
- ptIdx = 0;
- }
- else if (0 == strncmp("{", linedata.c_str(), 1))
- {
- float X, Y, Z;
- int imageY = 0;
- float leftX, leftY;
- float rightX, rightY;
- sscanf_s(linedata.c_str(), "{%f,%f,%f}-{%f,%f}-{%f,%f}", &X, &Y, &Z, &leftX, &leftY, &rightX, &rightY);
- SVzNL3DPosition a_pt;
- a_pt.pt3D.x = X;
- a_pt.pt3D.y = Y;
- a_pt.pt3D.z = Z;
- a_pt.nPointIdx = ptIdx;
- ptIdx++;
- a_line.push_back(a_pt);
- }
- }
- //last line
- int ptSize = (int)a_line.size();
- if (ptSize > 0)
- {
- scanData.push_back(a_line);
- a_line.clear();
- }
-
- inputFile.close();
- return;
-}
-
-void _convertToGridData_XYZRGB(std::vector>& scanData, double _F, std::vector>& gridData)
-{
- int lineNum = (int)scanData.size();
- int min_y = 100000000;
- int max_y = -10000000;
- int validStartLine = -1;
- int validEndLine = -1;
- for (int line = 0; line < lineNum; line++)
- {
- if (scanData[line].size() > 0)
- {
- if (validStartLine < 0)
- {
- validStartLine = line;
- validEndLine = line;
- }
- else
- validEndLine = line;
- }
-
- for (int i = 0; i < (int)scanData[line].size(); i++)
- {
- SVzNLPointXYZRGBA& a_pt = scanData[line][i];
- if (a_pt.z > 1e-4)
- {
- double v = _F * a_pt.y / a_pt.z + 2000;
- a_pt.nRGB = (int)(v + 0.5);
- max_y = max_y < (int)a_pt.nRGB ? (int)a_pt.nRGB : max_y;
- min_y = min_y > (int)a_pt.nRGB ? (int)a_pt.nRGB : min_y;
- }
- }
- }
- if (min_y == 100000000)
- return;
-
- int vldLineNum = validEndLine - validStartLine + 1;
- gridData.resize(vldLineNum);
- int pt_counter = max_y - min_y + 1;
- for (int i = 0; i < vldLineNum; i++)
- {
- gridData[i].resize(pt_counter);
- for (int j = 0; j < pt_counter; j++)
- {
- gridData[i][j].nPointIdx = j;
- gridData[i][j].pt3D.x = 0;
- gridData[i][j].pt3D.y = 0;
- gridData[i][j].pt3D.z = 0;
- }
- }
- for (int line = validStartLine; line <= validEndLine; line++)
- {
- int gridLine = line - validStartLine;
- for (int i = 0; i < (int)scanData[line].size(); i++)
- {
- SVzNLPointXYZRGBA& a_pt = scanData[line][i];
- if (a_pt.z > 1e-4)
- {
- int pt_id = a_pt.nRGB - min_y;
- gridData[gridLine][pt_id].pt3D.x = a_pt.x;
- gridData[gridLine][pt_id].pt3D.y = a_pt.y;
- gridData[gridLine][pt_id].pt3D.z = a_pt.z;
- }
- }
- }
- return;
-}
-
-void _convertToGridData_XYZRGB_vector(std::vector>&scanData, double _F, std::vector>&scanData_grid)
-{
- int min_y = 100000000;
- int max_y = -10000000;
- int lineNum = scanData.size();
- for (int line = 0; line < lineNum; line++)
- {
- std::vector< SPointXYZRGB>& a_line = scanData[line];
- int nPointCnt = a_line.size();
- for (int i = 0; i < nPointCnt; i++)
- {
- SPointXYZRGB* a_pt = &scanData[line][i];
- if (a_pt->z > 1e-4)
- {
- double v = _F * a_pt->y / a_pt->z + 2000;
- a_pt->nPointIdx = (int)(v + 0.5);
- max_y = max_y < (int)a_pt->nPointIdx ? (int)a_pt->nPointIdx : max_y;
- min_y = min_y > (int)a_pt->nPointIdx ? (int)a_pt->nPointIdx : min_y;
- }
- }
- }
- if (min_y == 100000000)
- return;
-
- int pt_counter = max_y - min_y + 1;
- for (int line = 0; line < lineNum; line++)
- {
- std::vector< SPointXYZRGB> gridData;
- gridData.resize(pt_counter);
- for (int i = 0; i < pt_counter; i++)
- gridData[i] = { 0, 0.0, 0.0, 0.0, 0.0f, 0.0f, 0.0f };
-
- std::vector< SPointXYZRGB>& a_line = scanData[line];
- int nPointCnt = a_line.size();
- for (int i = 0; i < nPointCnt; i++)
- {
- SPointXYZRGB a_pt = a_line[i];
- if (a_pt.z > 1e-4)
- {
- int pt_id = a_pt.nPointIdx - min_y;
- gridData[pt_id] = a_pt;
- }
- }
- scanData_grid.push_back(gridData);
- }
- return;
-}
-
-void _outputCalibPara(char* fileName, SSG_planeCalibPara calibPara)
-{
- std::ofstream sw(fileName);
- char dataStr[250];
- //调平矩阵
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[0], calibPara.planeCalib[1], calibPara.planeCalib[2]);
- sw << dataStr << std::endl;
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[3], calibPara.planeCalib[4], calibPara.planeCalib[5]);
- sw << dataStr << std::endl;
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.planeCalib[6], calibPara.planeCalib[7], calibPara.planeCalib[8]);
- sw << dataStr << std::endl;
- //地面高度
- sprintf_s(dataStr, 250, "%g", calibPara.planeHeight);
- sw << dataStr << std::endl;
- //反向旋转矩阵
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[0], calibPara.invRMatrix[1], calibPara.invRMatrix[2]);
- sw << dataStr << std::endl;
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[3], calibPara.invRMatrix[4], calibPara.invRMatrix[5]);
- sw << dataStr << std::endl;
- sprintf_s(dataStr, 250, "%g, %g, %g", calibPara.invRMatrix[6], calibPara.invRMatrix[7], calibPara.invRMatrix[8]);
- sw << dataStr << std::endl;
-
- sw.close();
-}
-
-SSG_planeCalibPara _readCalibPara(char* fileName)
-{
- //设置初始结果
- double initCalib[9] = {
- 1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0, 1.0 };
- SSG_planeCalibPara planePara;
- for (int i = 0; i < 9; i++)
- planePara.planeCalib[i] = initCalib[i];
- planePara.planeHeight = -1.0;
- for (int i = 0; i < 9; i++)
- planePara.invRMatrix[i] = initCalib[i];
-
- std::ifstream inputFile(fileName);
- std::string linedata;
-
- if (inputFile.is_open() == false)
- return planePara;
-
- //调平矩阵
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[0], &planePara.planeCalib[1], &planePara.planeCalib[2]);
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[3], &planePara.planeCalib[4], &planePara.planeCalib[5]);
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.planeCalib[6], &planePara.planeCalib[7], &planePara.planeCalib[8]);
- //地面高度
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf", &planePara.planeHeight);
- //反向旋转矩阵
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[0], &planePara.invRMatrix[1], &planePara.invRMatrix[2]);
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[3], &planePara.invRMatrix[4], &planePara.invRMatrix[5]);
- std::getline(inputFile, linedata);
- sscanf_s(linedata.c_str(), "%lf, %lf, %lf", &planePara.invRMatrix[6], &planePara.invRMatrix[7], &planePara.invRMatrix[8]);
-
- inputFile.close();
- return planePara;
-}
-
-void _outputObjResult(char* fileName, std::vector&objOps)
-{
- std::ofstream sw(fileName);
- char dataStr[250];
-
- int objSize = (int)objOps.size();
- for (int i = 0; i < objSize; i++)
- {
- sw << "obj_" << i << std::endl;
- sprintf_s(dataStr, 250, " %g, %g, %g, %g", objOps[i].centerPos.x, objOps[i].centerPos.y, objOps[i].centerPos.z, objOps[i].centerPos.z_yaw);
- sw << dataStr << std::endl;
- }
- sw.close();
-}
-
-void _outputScanDataFile_self(char* fileName, std::vector>& gridData,
- float lineV, int maxTimeStamp, int clockPerSecond)
-{
- int lineNum = (int)gridData.size();
- std::ofstream sw(fileName);
- sw << "LineNum:" << lineNum << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed:" << lineV << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << std::endl;
-
- for (int line = 0; line < lineNum; line++)
- {
- int nPositionCnt = (int)gridData[line].size();
- sw << "Line_" << line << "_0_" << nPositionCnt << std::endl;
- for (int i = 0; i < nPositionCnt; i++)
- {
- SVzNL3DPosition& pt3D = gridData[line][i];
- float x = (float)pt3D.pt3D.x;
- float y = (float)pt3D.pt3D.y;
- float z = (float)pt3D.pt3D.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}" << std::endl;
- }
- }
- sw.close();
-}
-
-void _outputScanDataFile_SPointXYZRGB_vector(char* fileName, std::vector>&scanData)
-{
- std::ofstream sw(fileName);
- int lineNum = scanData.size();
- sw << "LineNum:" << lineNum << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed: 0" << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp: 0_0" << std::endl;
-
- for (int line = 0; line < lineNum; line++)
- {
- int nPositionCnt = scanData[line].size();
- sw << "Line_" << line << "_0_" << nPositionCnt << std::endl;
- for (int i = 0; i < nPositionCnt; i++)
- {
- SVzNLPointXYZRGBA& pt3D = scanData[line][i];
- char str[250];
- sprintf_s(str, "{ %lf, %lf, %lf, 0, 0, 0 } - { 0, 0 } - { 0, 0 }",
- pt3D.x, pt3D.y, pt3D.z);
-
- sw << str << std::endl;
- }
- }
- sw.close();
-}
-
-typedef struct
-{
- int r;
- int g;
- int b;
-}SG_color;
-void _outputScanDataFile_RGBD_obj(char* fileName, std::vector>& scanData,
- float lineV, int maxTimeStamp, int clockPerSecond, WD_wheelArchInfo& wheelArcHeight)
-{
- int lineNum = (int)scanData.size();
- std::ofstream sw(fileName);
- int realLines = lineNum;
- realLines++;
- sw << "LineNum:" << realLines << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed:" << lineV << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << std::endl;
-
- int maxLineIndex = 0;
- int max_stamp = 0;
-
- SG_color rgb = { 0, 0, 0 };
-
- SG_color objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- int nTimeStamp = 0;
- double alpha = 0.8;
- for (int line = 0; line < lineNum; line++)
- {
- int nPositionCnt = (int)scanData[line].size();
- sw << "Line_" << line << "_0_" << nPositionCnt << std::endl;
- for (int i = 0; i < nPositionCnt; i++)
- {
- SVzNL3DPosition& pt3D = scanData[line][i];
- int type = pt3D.nPointIdx;
- if (1 == type)
- {
- rgb = { 0,255,0 };
- rgb.r = (int)((double)rgb.r * alpha);
- rgb.g = (int)((double)rgb.g * alpha);
- rgb.b = (int)((double)rgb.b * alpha);
- size = 2;
- }
- else if (2 == type)
- {
- rgb = { 0,0,255 };
- rgb.r = (int)((double)rgb.r * alpha);
- rgb.g = (int)((double)rgb.g * alpha);
- rgb.b = (int)((double)rgb.b * alpha);
- size = 2;
- }
- else if (3 == type) //轮眉
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (4 == type) //
- {
- rgb = { 255, 255, 0 };
- size = 3;
- }
- else if (5 == type) //
- {
- rgb = { 255, 255, 0 };
- size = 3;
- }
- else
- {
- rgb = { 100, 100, 100 };
- size = 1;
- }
-
- float x = (float)pt3D.pt3D.x;
- float y = (float)pt3D.pt3D.y;
- float z = (float)pt3D.pt3D.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- //if (objOps.size() > 0)
- {
- int ptNum = 3;
- sw << "Line_" << lineNum << "_" << (nTimeStamp + 1000) << "_" << ptNum << std::endl;
-
- rgb = { 255, 0, 0 };
-
- size = 10;
- float x = (float)wheelArcHeight.wheelArchPos.x;
- float y = (float)wheelArcHeight.wheelArchPos.y;
- float z = (float)wheelArcHeight.wheelArchPos.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
-
- x = (float)wheelArcHeight.wheelUpPos.x;
- y = (float)wheelArcHeight.wheelUpPos.y;
- z = (float)wheelArcHeight.wheelUpPos.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
-
- x = (float)wheelArcHeight.wheelDownPos.x;
- y = (float)wheelArcHeight.wheelDownPos.y;
- z = (float)wheelArcHeight.wheelDownPos.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
-
- x = (float)wheelArcHeight.wheelArchPos.x;
- y = (float)wheelArcHeight.wheelArchPos.y;
- z = (float)wheelArcHeight.wheelArchPos.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- //画出方向线
- rgb = { 255, 0, 0 };
- size = 3;
- int lineIdx = 0;
- sw << "Poly_" << lineIdx << "_2" << std::endl;
- sw << "{" << (float)wheelArcHeight.arcLine[0].x << "," << (float)wheelArcHeight.arcLine[0].y << "," << (float)wheelArcHeight.arcLine[0].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
- sw << "{" << (float)wheelArcHeight.arcLine[1].x << "," << (float)wheelArcHeight.arcLine[1].y << "," << (float)wheelArcHeight.arcLine[1].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
-
- lineIdx++;
- sw << "Poly_" << lineIdx << "_2" << std::endl;
- sw << "{" << (float)wheelArcHeight.upLine[0].x << "," << (float)wheelArcHeight.upLine[0].y << "," << (float)wheelArcHeight.upLine[0].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
- sw << "{" << (float)wheelArcHeight.upLine[1].x << "," << (float)wheelArcHeight.upLine[1].y << "," << (float)wheelArcHeight.upLine[1].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
-
- lineIdx++;
- sw << "Poly_" << lineIdx << "_2" << std::endl;
- sw << "{" << (float)wheelArcHeight.downLine[0].x << "," << (float)wheelArcHeight.downLine[0].y << "," << (float)wheelArcHeight.downLine[0].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
- sw << "{" << (float)wheelArcHeight.downLine[1].x << "," << (float)wheelArcHeight.downLine[1].y << "," << (float)wheelArcHeight.downLine[1].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
-
- lineIdx++;
- sw << "Poly_" << lineIdx << "_2" << std::endl;
- sw << "{" << (float)wheelArcHeight.centerLine[0].x << "," << (float)wheelArcHeight.centerLine[0].y << "," << (float)wheelArcHeight.centerLine[0].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
- sw << "{" << (float)wheelArcHeight.centerLine[1].x << "," << (float)wheelArcHeight.centerLine[1].y << "," << (float)wheelArcHeight.centerLine[1].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
-
- lineIdx++;
- sw << "Poly_" << lineIdx << "_2" << std::endl;
- sw << "{" << (float)wheelArcHeight.arcLine[0].x << "," << (float)wheelArcHeight.arcLine[0].y << "," << (float)wheelArcHeight.arcLine[0].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
- sw << "{" << (float)wheelArcHeight.arcLine[1].x << "," << (float)wheelArcHeight.arcLine[1].y << "," << (float)wheelArcHeight.arcLine[1].z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
-
- sw.close();
-}
-
-void _outputScanDataFile_obj_vector(char* fileName, std::vector>scanData,
- std::vector&objOps)
-{
- int lineNum = scanData.size();
- std::ofstream sw(fileName);
- int realLines = lineNum;
- if (objOps.size() > 0)
- realLines++;
- sw << "LineNum:" << realLines << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed: 0" << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp: 0_0" << std::endl;
-
- int maxLineIndex = 0;
- int max_stamp = 0;
-
- SG_color rgb = { 0, 0, 0 };
-
- SG_color objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- int nTimeStamp = 0;
- for (int line = 0; line < lineNum; line++)
- {
- int nPositionCnt = scanData[line].size();
- sw << "Line_" << line << "_0_" << nPositionCnt << std::endl;
- for (int i = 0; i < nPositionCnt; i++)
- {
- SVzNL3DPosition* pt3D = &scanData[line][i];
- int vType = pt3D->nPointIdx & 0xff;
- int hType = vType >> 4;
- int objId = (pt3D->nPointIdx >> 16) & 0xffff;
- vType = vType & 0x0f;
- if (LINE_FEATURE_L_JUMP_H2L == vType)
- {
- rgb = { 255, 97, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == vType)
- {
- rgb = { 255, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == vType)
- {
- rgb = { 255, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == vType)
- {
- rgb = { 160, 82, 45 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == vType)
- {
- rgb = { 233, 150, 122 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_H2L == hType)
- {
- rgb = { 0, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == hType)
- {
- rgb = { 0, 255, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == hType)
- {
- rgb = { 0, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == hType)
- {
- rgb = { 85, 107, 47 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == hType)
- {
- rgb = { 0, 255, 154 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (objId > 0) //目标
- {
- rgb = objColor[objId % 8];
- size = 5;
- }
- else
- {
- rgb = { 200, 200, 200 };
- size = 1;
- }
-
- float x = (float)pt3D->pt3D.x;
- float y = (float)pt3D->pt3D.y;
- float z = (float)pt3D->pt3D.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- if (objOps.size() > 0)
- {
- int ptNum = objOps.size();
- sw << "Line_" << lineNum << "_0_" << ptNum << std::endl;
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- rgb = { 255, 0, 0 };
- else
- rgb = { 255, 255, 0 };
- size = 25;
- float x = (float)objOps[i].centerPos.x;
- float y = (float)objOps[i].centerPos.y;
- float z = (float)objOps[i].centerPos.z;
-
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- if (i == 0)
- {
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- }
- //画出方向线
- sw.close();
-}
-
-void _outputRGBDScanDataFile_RGBD_obj(char* fileName, SVzNLXYZRGBDLaserLine * scanData, int lineNum,
- float lineV, int maxTimeStamp, int clockPerSecond, std::vector&objOps)
-{
- std::ofstream sw(fileName);
- int realLines = lineNum;
- if (objOps.size() > 0)
- realLines++;
- sw << "LineNum:" << realLines << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed:" << lineV << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << std::endl;
-
- int maxLineIndex = 0;
- int max_stamp = 0;
-
- SG_color rgb = { 0, 0, 0 };
-
- SG_color objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- int nTimeStamp = 0;
- for (int line = 0; line < lineNum; line++)
- {
- sw << "Line_" << line << "_" << scanData[line].nTimeStamp << "_" << scanData[line].nPointCnt << std::endl;
- nTimeStamp = scanData[line].nTimeStamp;
- for (int i = 0; i < scanData[line].nPointCnt; i++)
- {
- SVzNLPointXYZRGBA* pt3D = &scanData[line].p3DPoint[i];
-#if 0
- int vType = pt3D->nRGB & 0xff;
- int hType = vType >> 4;
- int objId = (pt3D->nRGB >> 16) & 0xffff;
- vType = vType & 0x0f;
- if (LINE_FEATURE_L_JUMP_H2L == vType)
- {
- rgb = { 255, 97, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == vType)
- {
- rgb = { 255, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == vType)
- {
- rgb = { 255, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == vType)
- {
- rgb = { 160, 82, 45 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == vType)
- {
- rgb = { 233, 150, 122 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_H2L == hType)
- {
- rgb = { 0, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == hType)
- {
- rgb = { 0, 255, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == hType)
- {
- rgb = { 0, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == hType)
- {
- rgb = { 85, 107, 47 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == hType)
- {
- rgb = { 0, 255, 154 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (objId > 0) //目标
- {
- rgb = objColor[objId % 8];
- size = 5;
- }
- else
-#endif
- {
- rgb = { 200, 200, 200 };
- size = 1;
- }
- float x = (float)pt3D->x;
- float y = (float)pt3D->y;
- float z = (float)pt3D->z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- if (objOps.size() > 0)
- {
- int ptNum = objOps.size();
- sw << "Line_" << lineNum << "_" << (nTimeStamp + 1000) << "_" << ptNum << std::endl;
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- rgb = { 255, 0, 0 };
- else
- rgb = { 255, 255, 0 };
- size = 25;
- float x = (float)objOps[i].centerPos.x;
- float y = (float)objOps[i].centerPos.y;
- float z = (float)objOps[i].centerPos.z;
-
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- if (i == 0)
- {
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- }
- sw.close();
-}
-
-void _outputScanDataFile_RGBD_sideBagObj(char* fileName, SVzNL3DLaserLine * scanData, int lineNum,
- float lineV, int maxTimeStamp, int clockPerSecond, std::vector&objOps)
-{
- std::ofstream sw(fileName);
- int realLines = lineNum;
- if (objOps.size() > 0)
- realLines++;
- sw << "LineNum:" << realLines << std::endl;
- sw << "DataType: 0" << std::endl;
- sw << "ScanSpeed:" << lineV << std::endl;
- sw << "PointAdjust: 1" << std::endl;
- sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << std::endl;
-
- int maxLineIndex = 0;
- int max_stamp = 0;
-
- SG_color rgb = { 0, 0, 0 };
-
- SG_color objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- int nTimeStamp = 0;
- for (int line = 0; line < lineNum; line++)
- {
- int nPntCount = 0;
- for (int i = 0; i < scanData[line].nPositionCnt; i++)
- {
- SVzNL3DPosition* pt3D = &scanData[line].p3DPosition[i];
- if (pt3D->pt3D.z > 1e-4)
- nPntCount++;
- }
- sw << "Line_" << line << "_" << scanData[line].nTimeStamp << "_" << nPntCount << std::endl;
- nTimeStamp = scanData[line].nTimeStamp;
- for (int i = 0; i < scanData[line].nPositionCnt; i++)
- {
- SVzNL3DPosition* pt3D = &scanData[line].p3DPosition[i];
- if (pt3D->pt3D.z < 1e-4)
- continue;
-
- int vType = pt3D->nPointIdx & 0xff;
- int hType = vType >> 4;
- int objId = (pt3D->nPointIdx >> 16) & 0xffff;
- vType = vType & 0x0f;
- if (LINE_FEATURE_L_JUMP_H2L == vType)
- {
- rgb = { 255, 97, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == vType)
- {
- rgb = { 255, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == vType)
- {
- rgb = { 255, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == vType)
- {
- rgb = { 160, 82, 45 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == vType)
- {
- rgb = { 233, 150, 122 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_H2L == hType)
- {
- rgb = { 0, 0, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == hType)
- {
- rgb = { 0, 255, 255 };
- size = 3;
- }
- else if (LINE_FEATURE_V_SLOPE == hType)
- {
- rgb = { 0, 255, 0 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == hType)
- {
- rgb = { 85, 107, 47 };
- size = 3;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == hType)
- {
- rgb = { 0, 255, 154 };
- size = 3;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType))
- {
- rgb = { 255, 0, 0 };
- size = 3;
- }
- else if (objId > 0) //目标
- {
- rgb = objColor[objId % 8];
- size = 5;
- }
- else
- {
- rgb = { 200, 200, 200 };
- size = 1;
- }
-
- float x = (float)pt3D->pt3D.x;
- float y = (float)pt3D->pt3D.y;
- float z = (float)pt3D->pt3D.z;
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- if (objOps.size() > 0)
- {
- int ptNum = objOps.size();
- sw << "Line_" << lineNum << "_" << (nTimeStamp + 1000) << "_" << ptNum << std::endl;
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- rgb = { 255, 0, 0 };
- else
- rgb = { 255, 255, 0 };
- size = 25;
- float x = (float)objOps[i].graspPos.x;
- float y = (float)objOps[i].graspPos.y;
- float z = (float)objOps[i].graspPos.z;
-
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- if (i == 0)
- {
- sw << "{" << x << "," << y << "," << z << "}-";
- sw << "{0,0}-{0,0}-";
- sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
- }
- }
- }
- sw.close();
-}
-
-void EulerRpyToRotation1(double rpy[3], double matrix3d[9]) {
- double cos0 = cos(rpy[0] * PI / 180);
- double sin0 = sin(rpy[0] * PI / 180);
- double cos1 = cos(rpy[1] * PI / 180);
- double sin1 = sin(rpy[1] * PI / 180);
- double cos2 = cos(rpy[2] * PI / 180);
- double sin2 = sin(rpy[2] * PI / 180);
- matrix3d[0] = cos2 * cos1;
- matrix3d[1] = cos2 * sin1 * sin0 - sin2 * cos0;
- matrix3d[2] = cos2 * sin1 * cos0 + sin2 * sin0;
- matrix3d[3] = sin2 * cos1;
- matrix3d[4] = sin2 * sin1 * sin0 + cos2 * cos0;
- matrix3d[5] = sin2 * sin1 * cos0 - cos2 * sin0;
- matrix3d[6] = -sin1;
- matrix3d[7] = cos1 * sin0;
- matrix3d[8] = cos1 * cos0;
- return;
-}
-
-void _rotateCloudPts(SVzNL3DLaserLine * scanData, int lineNum, double matrix3d[9], std::vector>&rotateLines, SVzNLRangeD * rx_range, SVzNLRangeD * ry_range)
-{
- rx_range->min = 0;
- rx_range->max = -1;
- ry_range->min = 0;
- ry_range->max = -1;
- for (int line = 0; line < lineNum; line++)
- {
- std::vector< SVzNL3DPosition> linePts;
- for (int i = 0; i < scanData[line].nPositionCnt; i++)
- {
- SVzNL3DPosition* pt3D = &scanData[line].p3DPosition[i];
- if (pt3D->pt3D.z < 1e-4)
- continue;
-
- SVzNL3DPosition r_pt;
- r_pt.pt3D = _ptRotate(pt3D->pt3D, matrix3d);
- r_pt.nPointIdx = pt3D->nPointIdx;
- if (rx_range->max < rx_range->min)
- {
- rx_range->min = r_pt.pt3D.x;
- rx_range->max = r_pt.pt3D.x;
- }
- else
- {
- if (rx_range->min > r_pt.pt3D.x)
- rx_range->min = r_pt.pt3D.x;
- if (rx_range->max < r_pt.pt3D.x)
- rx_range->max = r_pt.pt3D.x;
- }
- if (ry_range->max < ry_range->min)
- {
- ry_range->min = r_pt.pt3D.y;
- ry_range->max = r_pt.pt3D.y;
- }
- else
- {
- if (ry_range->min > r_pt.pt3D.y)
- ry_range->min = r_pt.pt3D.y;
- if (ry_range->max < r_pt.pt3D.y)
- ry_range->max = r_pt.pt3D.y;
- }
- linePts.push_back(r_pt);
-
- }
- rotateLines.push_back(linePts);
- }
-}
-
-void _rotateCloudPts_RGBD(SVzNLXYZRGBDLaserLine * scanData, int lineNum, double matrix3d[9], std::vector>&rotateLines, SVzNLRangeD * rx_range, SVzNLRangeD * ry_range)
-{
- rx_range->min = 0;
- rx_range->max = -1;
- ry_range->min = 0;
- ry_range->max = -1;
- for (int line = 0; line < lineNum; line++)
- {
- std::vector< SVzNLPointXYZRGBA> linePts;
- for (int i = 0; i < scanData[line].nPointCnt; i++)
- {
- SVzNLPointXYZRGBA* pt3D = &scanData[line].p3DPoint[i];
- if (pt3D->z < 1e-4)
- continue;
-
- SVzNLPointXYZRGBA r_pt;
- r_pt = _ptRotate_RGBD(*pt3D, matrix3d);
- if (rx_range->max < rx_range->min)
- {
- rx_range->min = r_pt.x;
- rx_range->max = r_pt.x;
- }
- else
- {
- if (rx_range->min > r_pt.x)
- rx_range->min = r_pt.x;
- if (rx_range->max < r_pt.x)
- rx_range->max = r_pt.x;
- }
- if (ry_range->max < ry_range->min)
- {
- ry_range->min = r_pt.y;
- ry_range->max = r_pt.y;
- }
- else
- {
- if (ry_range->min > r_pt.y)
- ry_range->min = r_pt.y;
- if (ry_range->max < r_pt.y)
- ry_range->max = r_pt.y;
- }
- linePts.push_back(r_pt);
- }
- rotateLines.push_back(linePts);
- }
-}
-
-void _XOYprojection(
- cv::Mat & img,
- std::vector>&dataLines,
- std::vector&objOps,
- const double x_scale,
- const double y_scale,
- const SVzNLRangeD x_range,
- const SVzNLRangeD y_range,
- bool drawDirAngle,
- int dirAngleLen)
-{
- int x_skip = 16;
- int y_skip = 16;
-
- cv::Vec3b rgb = cv::Vec3b(0, 0, 0);
- cv::Vec3b objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- for (int line = 0; line < dataLines.size(); line++)
- {
- std::vector< SVzNL3DPosition>& a_line = dataLines[line];
- for (int i = 0; i < a_line.size(); i++)
- {
- SVzNL3DPosition* pt3D = &a_line[i];
- if (pt3D->pt3D.z < 1e-4)
- continue;
-
- int vType = pt3D->nPointIdx & 0xff;
- int hType = vType >> 4;
- int objId = (pt3D->nPointIdx >> 16) & 0xff;
- vType = vType & 0x0f;
- if (LINE_FEATURE_L_JUMP_H2L == vType)
- {
- rgb = { 255, 97, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == vType)
- {
- rgb = { 255, 255, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_V_SLOPE == vType)
- {
- rgb = { 255, 0, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == vType)
- {
- rgb = { 160, 82, 45 };
- size = 2;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType))
- {
- rgb = { 255, 0, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == vType)
- {
- rgb = { 233, 150, 122 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_H2L == hType)
- {
- rgb = { 0, 0, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == hType)
- {
- rgb = { 0, 255, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_V_SLOPE == hType)
- {
- rgb = { 0, 255, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == hType)
- {
- rgb = { 85, 107, 47 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == hType)
- {
- rgb = { 0, 255, 154 };
- size = 2;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType))
- {
- rgb = { 255, 0, 0 };
- size = 2;
- }
- else if (objId > 0) //目标
- {
- rgb = objColor[objId % 8];
- size = 1;
- }
- else
- {
- rgb = { 150, 150, 150 };
- size = 1;
- }
-
-
- double x = pt3D->pt3D.x;
- double y = pt3D->pt3D.y;
-
- int px = (int)((x - x_range.min) / x_scale + x_skip);
- int py = (int)((y - y_range.min) / y_scale + y_skip);
- if (size == 1)
- img.at(py, px) = cv::Vec3b(rgb[2], rgb[1], rgb[0]);
- else
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
- }
- }
- if (objOps.size() > 0)
- {
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- {
- rgb = { 255, 0, 0 };
- size = 20;
- }
- else
- {
- rgb = { 255, 255, 0 };
- size = 10;
- }
- int px = (int)((objOps[i].centerPos.x - x_range.min) / x_scale + x_skip);
- int py = (int)((objOps[i].centerPos.y - y_range.min) / y_scale + y_skip);
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
- if (true == drawDirAngle)
- {
- //画线
- double R = (double)dirAngleLen / 2.0;
- const double deg2rad = PI / 180.0;
- const double yaw = objOps[i].centerPos.z_yaw * deg2rad;
- double cy = cos(yaw); double sy = sin(yaw);
- double x1 = objOps[i].centerPos.x + R * cy; double y1 = objOps[i].centerPos.y - R * sy;
- double x2 = objOps[i].centerPos.x - R * cy; double y2 = objOps[i].centerPos.y + R * sy;
- int px1 = (int)((x1 - x_range.min) / x_scale + x_skip);
- int py1 = (int)((y1 - y_range.min) / y_scale + y_skip);
- int px2 = (int)((x2 - x_range.min) / x_scale + x_skip);
- int py2 = (int)((y2 - y_range.min) / y_scale + y_skip);
- cv::line(img, cv::Point(px1, py1), cv::Point(px2, py2), cv::Scalar(rgb[2], rgb[1], rgb[0]), 2);
- }
- }
- }
-
-}
-
-void _XOYprojection_RGBD(
- cv::Mat & img,
- std::vector>&dataLines,
- std::vector&objOps,
- const double x_scale,
- const double y_scale,
- const SVzNLRangeD x_range,
- const SVzNLRangeD y_range,
- bool drawDirAngle,
- int dirAngleLen)
-{
- int x_skip = 16;
- int y_skip = 16;
-
- cv::Vec3b rgb = cv::Vec3b(0, 0, 0);
- cv::Vec3b objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- for (int line = 0; line < dataLines.size(); line++)
- {
- std::vector< SVzNLPointXYZRGBA>& a_line = dataLines[line];
- for (int i = 0; i < a_line.size(); i++)
- {
- SVzNLPointXYZRGBA* pt3D = &a_line[i];
- if (pt3D->z < 1e-4)
- continue;
-
- int nRGB = pt3D->nRGB;
- int r = nRGB & 0xff;
- nRGB >>= 8;
- int g = nRGB & 0xff;
- nRGB >>= 8;
- int b = nRGB & 0xff;
-
- rgb[0] = r;
- rgb[1] = g;
- rgb[2] = b;
- size = 1;
- double x = pt3D->x;
- double y = pt3D->y;
- int px = (int)((x - x_range.min) / x_scale + x_skip);
- int py = (int)((y - y_range.min) / y_scale + y_skip);
- if ((px == 666) && (py == 828))
- int kkk = 1;
- if (size == 1)
- img.at(py, px) = cv::Vec3b(rgb[2], rgb[1], rgb[0]);
- else
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
- }
- }
- if (objOps.size() > 0)
- {
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- {
- rgb = { 255, 0, 0 };
- size = 20;
- }
- else
- {
- rgb = { 255, 255, 0 };
- size = 10;
- }
- int px = (int)((objOps[i].centerPos.x - x_range.min) / x_scale + x_skip);
- int py = (int)((objOps[i].centerPos.y - y_range.min) / y_scale + y_skip);
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
- if (true == drawDirAngle)
- {
- //画线
- double R = (double)dirAngleLen / 2.0;
- const double deg2rad = PI / 180.0;
- const double yaw = objOps[i].centerPos.z_yaw * deg2rad;
- double cy = cos(yaw); double sy = sin(yaw);
- double arrowLen = R / 3;
- double arrowAngle = 30;
- double ca = cos(arrowAngle * deg2rad);
- double sa = sin(arrowAngle * deg2rad);
- SVzNL2DPointD endingPt[4];
- endingPt[0] = { R, 0 };
- endingPt[1] = { -R, 0 };
- endingPt[2] = { R - arrowLen * ca, -arrowLen * sa };
- endingPt[3] = { R - arrowLen * ca, arrowLen * sa };
- for (int m = 0; m < 4; m++)
- {
- double tmp_x = endingPt[m].x * cy - endingPt[m].y * sy;
- double tmp_y = -endingPt[m].x * sy - endingPt[m].y * cy;
- endingPt[m].x = tmp_x + objOps[i].centerPos.x;
- endingPt[m].y = tmp_y + objOps[i].centerPos.y;
- }
- int px1 = (int)((endingPt[0].x - x_range.min) / x_scale + x_skip);
- int py1 = (int)((endingPt[0].y - y_range.min) / y_scale + y_skip);
- int px2 = (int)((endingPt[1].x - x_range.min) / x_scale + x_skip);
- int py2 = (int)((endingPt[1].y - y_range.min) / y_scale + y_skip);
- cv::line(img, cv::Point(px1, py1), cv::Point(px2, py2), cv::Scalar(rgb[2], rgb[1], rgb[0]), 2);
- int px3 = (int)((endingPt[2].x - x_range.min) / x_scale + x_skip);
- int py3 = (int)((endingPt[2].y - y_range.min) / y_scale + y_skip);
- int px4 = (int)((endingPt[3].x - x_range.min) / x_scale + x_skip);
- int py4 = (int)((endingPt[3].y - y_range.min) / y_scale + y_skip);
- if (objOps[i].orienFlag == 1)
- {
- cv::line(img, cv::Point(px1, py1), cv::Point(px3, py3), cv::Scalar(0, 255, 0), 2);
- cv::line(img, cv::Point(px1, py1), cv::Point(px4, py4), cv::Scalar(0, 255, 0), 2);
- //cv::circle(img, cv::Point(px1, py1), 5, cv::Scalar(0, 255, 0), -1);
- }
- else if (objOps[i].orienFlag == 2)
- {
- cv::line(img, cv::Point(px1, py1), cv::Point(px3, py3), cv::Scalar(0, 0, 255), 2);
- cv::line(img, cv::Point(px1, py1), cv::Point(px4, py4), cv::Scalar(0, 0, 255), 2);
- //cv::circle(img, cv::Point(px1, py1), 5, cv::Scalar(0, 0, 255), -1);
- }
- }
- }
- }
-
-}
-
-void _XOYprojection_sideBagInfo(cv::Mat & img, std::vector>&dataLines, std::vector&objOps,
- const double x_scale, const double y_scale, const SVzNLRangeD x_range, const SVzNLRangeD y_range)
-{
- int x_skip = 16;
- int y_skip = 16;
-
- cv::Vec3b rgb = cv::Vec3b(0, 0, 0);
- cv::Vec3b objColor[8] = {
- {245,222,179},//淡黄色
- {210,105, 30},//巧克力色
- {240,230,140},//黄褐色
- {135,206,235},//天蓝色
- {250,235,215},//古董白
- {189,252,201},//薄荷色
- {221,160,221},//梅红色
- {188,143,143},//玫瑰红色
- };
- int size = 1;
- for (int line = 0; line < dataLines.size(); line++)
- {
- std::vector< SVzNL3DPosition>& a_line = dataLines[line];
- for (int i = 0; i < a_line.size(); i++)
- {
- SVzNL3DPosition* pt3D = &a_line[i];
- if (pt3D->pt3D.z < 1e-4)
- continue;
-
- int vType = pt3D->nPointIdx & 0xff;
- int hType = vType >> 4;
- int objId = (pt3D->nPointIdx >> 16) & 0xffff;
- vType = vType & 0x0f;
- if (LINE_FEATURE_L_JUMP_H2L == vType)
- {
- rgb = { 255, 97, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == vType)
- {
- rgb = { 255, 255, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_V_SLOPE == vType)
- {
- rgb = { 255, 0, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == vType)
- {
- rgb = { 160, 82, 45 };
- size = 2;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType))
- {
- rgb = { 255, 0, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == vType)
- {
- rgb = { 233, 150, 122 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_H2L == hType)
- {
- rgb = { 0, 0, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_L_JUMP_L2H == hType)
- {
- rgb = { 0, 255, 255 };
- size = 2;
- }
- else if (LINE_FEATURE_V_SLOPE == hType)
- {
- rgb = { 0, 255, 0 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_H2L == hType)
- {
- rgb = { 85, 107, 47 };
- size = 2;
- }
- else if (LINE_FEATURE_L_SLOPE_L2H == hType)
- {
- rgb = { 0, 255, 154 };
- size = 2;
- }
- else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType))
- {
- rgb = { 255, 0, 0 };
- size = 2;
- }
- else if ((objId > 0) && (objId < 1000)) //目标
- {
- rgb = objColor[objId % 8];
- size = 3;
- }
- else
- {
- rgb = { 150, 150, 150 };
- size = 1;
- }
-
-
- double x = pt3D->pt3D.x;
- double y = pt3D->pt3D.y;
-
- int px = (int)((x - x_range.min) / x_scale + x_skip);
- int py = (int)((y - y_range.min) / y_scale + y_skip);
- if (size == 1)
- img.at(py, px) = cv::Vec3b(rgb[2], rgb[1], rgb[0]);
- else
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
- }
- }
- if (objOps.size() > 0)
- {
- for (int i = 0; i < objOps.size(); i++)
- {
- if (i == 0)
- {
- rgb = { 255, 0, 0 };
- size = 20;
- }
- else
- {
- rgb = { 255, 255, 0 };
- size = 10;
- }
- int px = (int)((objOps[i].graspPos.x - x_range.min) / x_scale + x_skip);
- int py = (int)((objOps[i].graspPos.y - y_range.min) / y_scale + y_skip);
- cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
-
- //画ROI
- size = 3;
- cv::Point2d vec2d[4];
- vec2d[0].x = objOps[i].objROI.left; vec2d[0].y = objOps[i].objROI.top;
- vec2d[1].x = objOps[i].objROI.right; vec2d[1].y = objOps[i].objROI.top;
- vec2d[2].x = objOps[i].objROI.right; vec2d[2].y = objOps[i].objROI.bottom;
- vec2d[3].x = objOps[i].objROI.left; vec2d[3].y = objOps[i].objROI.bottom;
- cv::Point vec[4];
- for (int j = 0; j < 4; j++)
- {
- vec[j].x = (int)((vec2d[j].x - x_range.min) / x_scale + x_skip);
- vec[j].y = (int)((vec2d[j].y - y_range.min) / y_scale + y_skip);
- }
- for (int j = 0; j < 4; j++)
- {
- int nxtIdx = (j + 1) % 4;
- cv::line(img, vec[j], vec[nxtIdx], cv::Scalar(rgb[2], rgb[1], rgb[0]), size);
- }
-
- //画倾角
- double r = 50;
- double angle = objOps[i].graspPos.z_yaw;
- angle = -angle * PI / 180;
- cv::Point2d line_pt[2];
- line_pt[0].x = (int)(r * cos(angle) + px);
- line_pt[0].y = (int)(-r * sin(angle) + py);
- line_pt[1].x = (int)(-r * cos(angle) + px);
- line_pt[1].y = (int)(r * sin(angle) + py);
- cv::line(img, line_pt[0], line_pt[1], cv::Scalar(rgb[2], rgb[1], rgb[0]), size);
- }
-
-
- }
-
-}
-
-void _genXOYProjectionImage(cv::String & fileName, SVzNL3DLaserLine * scanData, int lineNum, std::vector&objOps, double rpy[3], double dirLen)
-{
- //统计X和Y的范围
- std::vector> scan_lines;
- SVzNLRangeD x_range = { 0, -1 };
- SVzNLRangeD y_range = { 0, -1 };
- for (int line = 0; line < lineNum; line++)
- {
- std::vector< SVzNL3DPosition> a_line;
- for (int i = 0; i < scanData[line].nPositionCnt; i++)
- {
- SVzNL3DPosition* pt3D = &scanData[line].p3DPosition[i];
- if (pt3D->pt3D.z < 1e-4)
- continue;
-
- a_line.push_back(*pt3D);
- if (x_range.max < x_range.min)
- {
- x_range.min = pt3D->pt3D.x;
- x_range.max = pt3D->pt3D.x;
- }
- else
- {
- if (x_range.min > pt3D->pt3D.x)
- x_range.min = pt3D->pt3D.x;
- if (x_range.max < pt3D->pt3D.x)
- x_range.max = pt3D->pt3D.x;
- }
- if (y_range.max < y_range.min)
- {
- y_range.min = pt3D->pt3D.y;
- y_range.max = pt3D->pt3D.y;
- }
- else
- {
- if (y_range.min > pt3D->pt3D.y)
- y_range.min = pt3D->pt3D.y;
- if (y_range.max < pt3D->pt3D.y)
- y_range.max = pt3D->pt3D.y;
- }
- }
- scan_lines.push_back(a_line);
- }
-
- int imgRows = 992;
- int imgCols = 1056;
- double y_rows = 960.0;
- double x_cols = 1024.0;
- cv::Mat img = cv::Mat::zeros(imgRows, imgCols, CV_8UC3);
- //计算投影比例
- double x_scale = (x_range.max - x_range.min) / x_cols;
- double y_scale = (y_range.max - y_range.min) / y_rows;
- if (x_scale < y_scale)
- x_scale = y_scale;
- else
- y_scale = x_scale;
-
- int angleDrawLen = dirLen;// / x_scale;
- _XOYprojection(img, scan_lines, objOps, x_scale, y_scale, x_range, y_range, true, angleDrawLen);
-
- //旋转视角显示
- double matrix3d[9];
- EulerRpyToRotation1(rpy, matrix3d);
- std::vector