diff --git a/App/Workpiece/WorkpieceApp/IYWorkpieceStatus.h b/App/Workpiece/WorkpieceApp/IYWorkpieceStatus.h index 1d28190..2aede1a 100644 --- a/App/Workpiece/WorkpieceApp/IYWorkpieceStatus.h +++ b/App/Workpiece/WorkpieceApp/IYWorkpieceStatus.h @@ -52,6 +52,7 @@ struct DetectionResult { QImage image; std::vector positions; int cameraIndex = 1; // 相机索引,默认为1(第一个相机) + int workpieceType = 0; // 工件类型:1/2/3/4等 }; // 状态回调接口 diff --git a/App/Workpiece/WorkpieceApp/Presenter/Inc/TCPServerProtocol.h b/App/Workpiece/WorkpieceApp/Presenter/Inc/TCPServerProtocol.h index 5d2c856..a776615 100644 --- a/App/Workpiece/WorkpieceApp/Presenter/Inc/TCPServerProtocol.h +++ b/App/Workpiece/WorkpieceApp/Presenter/Inc/TCPServerProtocol.h @@ -70,7 +70,7 @@ public: * @param pClient 目标客户端,如果为nullptr则发送给所有客户端 * @return 0-成功,其他-错误码 */ - int SendDetectionResult(const DetectionResultData& result, const TCPClient* pClient = nullptr); + int SendDetectionResult(const QJsonObject& result, const TCPClient* pClient = nullptr); /** * @brief 获取当前连接状态 diff --git a/App/Workpiece/WorkpieceApp/Presenter/Src/DetectPresenter.cpp b/App/Workpiece/WorkpieceApp/Presenter/Src/DetectPresenter.cpp index a102492..0713547 100644 --- a/App/Workpiece/WorkpieceApp/Presenter/Src/DetectPresenter.cpp +++ b/App/Workpiece/WorkpieceApp/Presenter/Src/DetectPresenter.cpp @@ -11,56 +11,6 @@ DetectPresenter::~DetectPresenter() } -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; -} - int DetectPresenter::DetectWorkpiece( int cameraIndex, std::vector>& laserLines, @@ -94,20 +44,15 @@ int DetectPresenter::DetectWorkpiece( dataLoader.SaveLaserScanData(fileName, laserLines, laserLines.size(), 0.0, 0, 0); } - int nRet = SUCCESS; // 转换为算法需要的XYZ格式 std::vector> xyzData; -#if 0 int convertResult = dataLoader.ConvertToSVzNL3DPosition(laserLines, xyzData); if (convertResult != SUCCESS || xyzData.empty()) { LOG_WARNING("Failed to convert data to XYZ format or no XYZ data available\n"); return ERR_CODE(DEV_DATA_INVALID); } - #else - vzReadLaserScanPointFromFile_XYZ_vector("C:\\project\\QT\\GrabBag\\TestData\\workpiece\\scanData_1_grid.txt", xyzData); - #endif // 工件角点提取参数 SSX_BQworkpiecePara bqWorkpieceParam; @@ -162,8 +107,8 @@ int DetectPresenter::DetectWorkpiece( SSG_planeCalibPara groundCalibPara; if(cameraCalibParam){ memcpy(groundCalibPara.planeCalib, cameraCalibParam->planeCalib, sizeof(double) * 9); - groundCalibPara.planeHeight = cameraCalibParam->planeHeight; memcpy(groundCalibPara.invRMatrix, cameraCalibParam->invRMatrix, sizeof(double) * 9); + groundCalibPara.planeHeight = cameraCalibParam->planeHeight; } else { // 使用默认单位矩阵 double identity[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; @@ -174,20 +119,16 @@ int DetectPresenter::DetectWorkpiece( if(debugParam.enableDebug && debugParam.printDetailLog) { - if(cameraCalibParam){ - LOG_INFO("Plane height: %.3f\n", cameraCalibParam->planeHeight); - LOG_INFO(" Plane calibration matrix: [%f, %f, %f; %f, %f, %f; %f, %f, %f]\n", - cameraCalibParam->planeCalib[0], cameraCalibParam->planeCalib[1], cameraCalibParam->planeCalib[2], - cameraCalibParam->planeCalib[3], cameraCalibParam->planeCalib[4], cameraCalibParam->planeCalib[5], - cameraCalibParam->planeCalib[6], cameraCalibParam->planeCalib[7], cameraCalibParam->planeCalib[8]); + LOG_INFO("Plane height: %.3f\n", groundCalibPara.planeHeight); + LOG_INFO(" Plane calibration matrix: [%f, %f, %f; %f, %f, %f; %f, %f, %f]\n", + groundCalibPara.planeCalib[0], groundCalibPara.planeCalib[1], groundCalibPara.planeCalib[2], + groundCalibPara.planeCalib[3], groundCalibPara.planeCalib[4], groundCalibPara.planeCalib[5], + groundCalibPara.planeCalib[6], groundCalibPara.planeCalib[7], groundCalibPara.planeCalib[8]); - LOG_INFO(" Plane invRMatrix matrix: [%f, %f, %f; %f, %f, %f; %f, %f, %f]\n", - cameraCalibParam->invRMatrix[0], cameraCalibParam->invRMatrix[1], cameraCalibParam->invRMatrix[2], - cameraCalibParam->invRMatrix[3], cameraCalibParam->invRMatrix[4], cameraCalibParam->invRMatrix[5], - cameraCalibParam->invRMatrix[6], cameraCalibParam->invRMatrix[7], cameraCalibParam->invRMatrix[8]); - } else { - LOG_WARNING("[Algo Thread] Camera calibration parameters not found for camera %d\n", cameraIndex); - } + LOG_INFO(" Plane invRMatrix matrix: [%f, %f, %f; %f, %f, %f; %f, %f, %f]\n", + groundCalibPara.invRMatrix[0], groundCalibPara.invRMatrix[1], groundCalibPara.invRMatrix[2], + groundCalibPara.invRMatrix[3], groundCalibPara.invRMatrix[4], groundCalibPara.invRMatrix[5], + groundCalibPara.invRMatrix[6], groundCalibPara.invRMatrix[7], groundCalibPara.invRMatrix[8]); } // 数据预处理:调平和去除地面(使用当前相机的调平参数) @@ -221,11 +162,15 @@ int DetectPresenter::DetectWorkpiece( LOG_INFO("sx_BQ_getWorkpieceCorners: workpieceType=%d err=%d runtime=%.3fms\n", bqResult.workpieceType, errCode, oTimeUtils.GetElapsedTimeInMilliSec()); ERR_CODE_RETURN(errCode); + // 保存工件类型到检测结果 + detectionResult.workpieceType = bqResult.workpieceType; + // 构建用于可视化的角点数组 + // 按照逆时针顺序排列:左侧(从下到上) -> 顶部(从左到右) -> 右侧(从上到下) -> 底部(从右到左) std::vector> objOps; std::vector allCorners; - // 添加左侧角点 + // 1. 添加左侧角点(从下到上,逆时针) for (int i = 0; i < 3; i++) { SVzNL3DPoint pt; pt.x = bqResult.corner_L[i].x; @@ -234,16 +179,7 @@ int DetectPresenter::DetectWorkpiece( allCorners.push_back(pt); } - // 添加右侧角点 - for (int i = 0; i < 3; i++) { - SVzNL3DPoint pt; - pt.x = bqResult.corner_R[i].x; - pt.y = bqResult.corner_R[i].y; - pt.z = bqResult.corner_R[i].z; - allCorners.push_back(pt); - } - - // 添加顶部角点 + // 2. 添加顶部角点(从左到右,逆时针) for (int i = 0; i < 3; i++) { SVzNL3DPoint pt; pt.x = bqResult.corner_T[i].x; @@ -252,7 +188,16 @@ int DetectPresenter::DetectWorkpiece( allCorners.push_back(pt); } - // 添加底部角点 + // 3. 添加右侧角点(从上到下,逆时针) + for (int i = 0; i < 3; i++) { + SVzNL3DPoint pt; + pt.x = bqResult.corner_R[i].x; + pt.y = bqResult.corner_R[i].y; + pt.z = bqResult.corner_R[i].z; + allCorners.push_back(pt); + } + + // 4. 添加底部角点(从右到左,逆时针) for (int i = 0; i < 3; i++) { SVzNL3DPoint pt; pt.x = bqResult.corner_B[i].x; @@ -264,7 +209,7 @@ int DetectPresenter::DetectWorkpiece( objOps.push_back(allCorners); // 从点云数据生成投影图像 - detectionResult.image = PointCloudImageUtils::GeneratePointCloudImage(xyzData, objOps); + detectionResult.image = PointCloudImageUtils::GeneratePointCloudRetPointImage(xyzData, objOps); // 转换检测结果为UI显示格式(使用机械臂坐标系数据) for (size_t i = 0; i < objOps.size(); i++) { diff --git a/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerMethods.cpp b/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerMethods.cpp index 4dc225b..61a2bf8 100644 --- a/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerMethods.cpp +++ b/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerMethods.cpp @@ -17,7 +17,7 @@ int WorkpiecePresenter::InitTCPServer() m_pTCPServer = new TCPServerProtocol(); // 从配置获取端口,默认5020 - int port = 5020; + int port = 7800; if (m_vrConfig) { // TODO: 从配置文件获取端口配置 // port = m_vrConfig->GetTCPPort(); @@ -60,6 +60,9 @@ void WorkpiecePresenter::OnTCPConnectionChanged(bool connected) } else { m_pStatus->OnStatusUpdate("TCP客户端已断开"); } + + // 更新机械臂连接状态 + m_pStatus->OnRobotConnectionChanged(connected); } // 更新工作状态 @@ -112,37 +115,71 @@ void WorkpiecePresenter::_SendDetectionResultToTCP(const DetectionResult& detect LOG_DEBUG("Sending detection result to TCP clients, camera index: %d\n", cameraIndex); - // 构造TCP协议的检测结果数据 - TCPServerProtocol::DetectionResultData tcpResult; - tcpResult.code = 0; - tcpResult.success = true; - tcpResult.message = "检测成功"; - tcpResult.timestamp = QDateTime::currentMSecsSinceEpoch(); - - // 转换检测结果为JSON格式的3D坐标点数组 - // 工件角点检测:将12个角点(左3、右3、上3、下3)作为一组发送 + // 创建主结果对象 + QJsonObject resultObject; + // 添加工件类型 + resultObject["type"] = detectionResult.workpieceType; + // 构造新的JSON格式:type + L/T/R/B分组 try { - std::vector cornerPoints; - - // 遍历所有检测到的角点位置 - for (const auto& position : detectionResult.positions) { - QJsonObject point; - point["x"] = position.x; - point["y"] = position.y; - point["z"] = position.z; - point["roll"] = position.roll; - point["pitch"] = position.pitch; - point["yaw"] = position.yaw; - cornerPoints.push_back(point); + // 检查角点数量是否为12个(左3、顶3、右3、底3) + if (detectionResult.positions.size() != 12) { + LOG_WARNING("Expected 12 corner points, but got %zu points\n", detectionResult.positions.size()); + // 如果点数不对,仍然发送,但可能数据不完整 } - if (!cornerPoints.empty()) { - tcpResult.result.push_back(cornerPoints); - LOG_INFO("Prepared %zu corner points for TCP transmission\n", cornerPoints.size()); + resultObject["success"] = true; + // 角点索引说明(根据DetectPresenter.cpp中的顺序): + // 索引 0-2: 左侧 (L) - 从下到上 + // 索引 3-5: 顶部 (T) - 从左到右 + // 索引 6-8: 右侧 (R) - 从上到下 + // 索引 9-11: 底部 (B) - 从右到左 + + // 构造左侧角点 (L) + QJsonObject L; + for (int i = 0; i < 3 && i < (int)detectionResult.positions.size(); i++) { + QJsonArray point; + point.append(detectionResult.positions[i].x); + point.append(detectionResult.positions[i].y); + point.append(detectionResult.positions[i].z); + L[QString("P%1").arg(i + 1)] = point; } + resultObject["L"] = L; + + // 构造顶部角点 (T) + QJsonObject T; + for (int i = 0; i < 3 && (i + 3) < (int)detectionResult.positions.size(); i++) { + QJsonArray point; + point.append(detectionResult.positions[i + 3].x); + point.append(detectionResult.positions[i + 3].y); + point.append(detectionResult.positions[i + 3].z); + T[QString("P%1").arg(i + 1)] = point; + } + resultObject["T"] = T; + + // 构造右侧角点 (R) + QJsonObject R; + for (int i = 0; i < 3 && (i + 6) < (int)detectionResult.positions.size(); i++) { + QJsonArray point; + point.append(detectionResult.positions[i + 6].x); + point.append(detectionResult.positions[i + 6].y); + point.append(detectionResult.positions[i + 6].z); + R[QString("P%1").arg(i + 1)] = point; + } + resultObject["R"] = R; + + // 构造底部角点 (B) + QJsonObject B; + for (int i = 0; i < 3 && (i + 9) < (int)detectionResult.positions.size(); i++) { + QJsonArray point; + point.append(detectionResult.positions[i + 9].x); + point.append(detectionResult.positions[i + 9].y); + point.append(detectionResult.positions[i + 9].z); + B[QString("P%1").arg(i + 1)] = point; + } + resultObject["B"] = B; // 发送结果 - int sendResult = m_pTCPServer->SendDetectionResult(tcpResult); + int sendResult = m_pTCPServer->SendDetectionResult(resultObject); if (sendResult == 0) { LOG_INFO("Detection result sent to TCP clients successfully\n"); } else { @@ -150,12 +187,6 @@ void WorkpiecePresenter::_SendDetectionResultToTCP(const DetectionResult& detect } } catch (const std::exception& e) { LOG_ERROR("Exception while preparing TCP detection result: %s\n", e.what()); - - // 发送错误响应 - tcpResult.code = -1; - tcpResult.success = false; - tcpResult.message = "检测结果处理异常"; - tcpResult.result.clear(); - m_pTCPServer->SendDetectionResult(tcpResult); + m_pTCPServer->SendDetectionResult(resultObject); } -} \ No newline at end of file +} diff --git a/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerProtocol.cpp b/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerProtocol.cpp index ac87883..8c4842b 100644 --- a/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerProtocol.cpp +++ b/App/Workpiece/WorkpieceApp/Presenter/Src/TCPServerProtocol.cpp @@ -78,33 +78,15 @@ void TCPServerProtocol::Deinitialize() } } -int TCPServerProtocol::SendDetectionResult(const DetectionResultData& result, const TCPClient* pClient) +int TCPServerProtocol::SendDetectionResult(const QJsonObject& result, const TCPClient* pClient) { if (!m_pTCPServer || !m_bServerRunning) { LOG_ERROR("TCP server is not running\n"); return -1; } - // 构造JSON响应 - QJsonObject response; - response["code"] = result.code; - response["success"] = result.success; - response["message"] = result.message; - response["timestamp"] = result.timestamp; - - // 构造结果数组 - QJsonArray resultArray; - for (const auto& weldLine : result.result) { - QJsonArray lineArray; - for (const auto& point : weldLine) { - lineArray.append(point); - } - resultArray.append(lineArray); - } - response["result"] = resultArray; - // 转换为JSON字符串 - QJsonDocument doc(response); + QJsonDocument doc(result); QByteArray jsonData = doc.toJson(QJsonDocument::Compact); // 发送数据 @@ -248,12 +230,8 @@ void TCPServerProtocol::HandleStartDetectionCommand(const TCPClient* pClient, qi void TCPServerProtocol::SendErrorResponse(const TCPClient* pClient, int code, const QString& message, qint64 timestamp) { - DetectionResultData errorResult; - errorResult.code = code; - errorResult.success = false; - errorResult.message = message; - errorResult.timestamp = timestamp; - errorResult.result.clear(); // 错误时返回空结果 + QJsonObject resultObject; + resultObject["success"] = true; - SendDetectionResult(errorResult, pClient); + SendDetectionResult(resultObject, pClient); } diff --git a/App/Workpiece/WorkpieceApp/Presenter/Src/WorkpiecePresenter.cpp b/App/Workpiece/WorkpieceApp/Presenter/Src/WorkpiecePresenter.cpp index 791636e..b37b590 100644 --- a/App/Workpiece/WorkpieceApp/Presenter/Src/WorkpiecePresenter.cpp +++ b/App/Workpiece/WorkpieceApp/Presenter/Src/WorkpiecePresenter.cpp @@ -824,9 +824,9 @@ void WorkpiecePresenter::_AlgoDetectThread() } int WorkpiecePresenter::_DetectTask() -{ +{ LOG_INFO("[Algo Thread] Start real detection task using algorithm\n"); - + std::lock_guard lock(m_detectionDataMutex); // 1. 获取缓存的点云数据 if (m_detectionDataCache.empty()) { @@ -836,7 +836,16 @@ int WorkpiecePresenter::_DetectTask() } return ERR_CODE(DEV_DATA_INVALID); } - + + // 检查检测处理器是否已初始化 + if (!m_pDetectPresenter) { + LOG_ERROR("DetectPresenter is null, cannot proceed with detection\n"); + if (m_pStatus) { + m_pStatus->OnStatusUpdate("检测处理器未初始化"); + } + return ERR_CODE(DEV_NOT_FIND); + } + // 2. 准备算法输入数据 unsigned int lineNum = 0; lineNum = m_detectionDataCache.size(); diff --git a/App/Workpiece/WorkpieceApp/WorkpieceApp.pro b/App/Workpiece/WorkpieceApp/WorkpieceApp.pro index 317a5d0..6cd6cb0 100644 --- a/App/Workpiece/WorkpieceApp/WorkpieceApp.pro +++ b/App/Workpiece/WorkpieceApp/WorkpieceApp.pro @@ -36,6 +36,7 @@ INCLUDEPATH += $$PWD/../../../VrEyeDevice/Inc INCLUDEPATH += $$PWD/../../../VrNets/TCPServer/Inc INCLUDEPATH += $$PWD/../../../CloudUtils/Inc +INCLUDEPATH += $$PWD/../../../QtUtils/Inc # 源文件 SOURCES += \ @@ -91,15 +92,18 @@ win32 { win32:CONFIG(debug, debug|release) { LIBS += -L../../../VrUtils/debug -lVrUtils LIBS += -L../../../CloudUtils/debug -lCloudUtils + LIBS += -L../../../QtUtils/debug -lQtUtils LIBS += -L../WorkpieceConfig/debug -lWorkpieceConfig LIBS += -L../../../VrEyeDevice/debug -lVrEyeDevice LIBS += -L../../../Module/ModbusTCPServer/debug -lModbusTCPServer LIBS += -L../../../Module/ShareMem/debug -lShareMem LIBS += -L../../../VrNets/debug -lVrModbus LIBS += -L../../../VrNets/debug -lVrTcpServer + }else:win32:CONFIG(release, debug|release){ LIBS += -L../../../VrUtils/release -lVrUtils LIBS += -L../../../CloudUtils/release -lCloudUtils + LIBS += -L../../../QtUtils/release -lQtUtils LIBS += -L../WorkpieceConfig/release -lWorkpieceConfig LIBS += -L../../../VrEyeDevice/release -lVrEyeDevice LIBS += -L../../../Module/ModbusTCPServer/release -lModbusTCPServer @@ -116,6 +120,7 @@ win32:CONFIG(debug, debug|release) { LIBS += -L../../../Module/ShareMem -lShareMem LIBS += -L../../../VrNets -lVrTcpServer LIBS += -L../../../CloudUtils -lCloudUtils + LIBS += -L../../../QtUtils -lQtUtils LIBS += -L../../../VrUtils -lVrUtils # 添加系统库依赖 diff --git a/App/Workpiece/WorkpieceApp/dialogalgoarg.cpp b/App/Workpiece/WorkpieceApp/dialogalgoarg.cpp index 9ffa8dd..30789d9 100644 --- a/App/Workpiece/WorkpieceApp/dialogalgoarg.cpp +++ b/App/Workpiece/WorkpieceApp/dialogalgoarg.cpp @@ -9,6 +9,7 @@ #include #include #include "PathManager.h" +#include "StyledMessageBox.h" #include "VrLog.h" @@ -28,7 +29,7 @@ DialogAlgoarg::DialogAlgoarg(IVrConfig* vrConfig, QWidget *parent) // 检查配置文件路径是否有效 if (m_configFilePath.isEmpty()) { - QMessageBox::critical(this, "错误", "无法获取配置文件路径!"); + StyledMessageBox::critical(this, "错误", "无法获取配置文件路径!"); return; } @@ -36,9 +37,9 @@ DialogAlgoarg::DialogAlgoarg(IVrConfig* vrConfig, QWidget *parent) LoadConfigToUI(); } catch (const std::exception& e) { - QMessageBox::critical(this, "初始化错误", QString("对话框初始化失败: %1").arg(e.what())); + StyledMessageBox::critical(this, "初始化错误", QString("对话框初始化失败: %1").arg(e.what())); } catch (...) { - QMessageBox::critical(this, "初始化错误", "对话框初始化失败!(未知错误)"); + StyledMessageBox::critical(this, "初始化错误", "对话框初始化失败!(未知错误)"); } } @@ -50,7 +51,7 @@ DialogAlgoarg::~DialogAlgoarg() void DialogAlgoarg::LoadConfigToUI() { if (!m_vrConfig) { - QMessageBox::critical(this, "错误", "配置对象未初始化!"); + StyledMessageBox::critical(this, "错误", "配置对象未初始化!"); return; } @@ -60,7 +61,7 @@ void DialogAlgoarg::LoadConfigToUI() if (ret != LOAD_CONFIG_SUCCESS) { // 配置文件加载失败,使用默认参数 LOG_WARNING("Failed to load config file (error code: %d), using default parameters\n", ret); - QMessageBox::information(this, "提示", + StyledMessageBox::information(this, "提示", QString("配置文件加载失败(错误代码: %1),将使用默认参数显示").arg(ret)); // 使用 IVrConfig.h 中定义的默认值初始化 ConfigResult @@ -83,7 +84,7 @@ void DialogAlgoarg::LoadConfigToUI() } catch (const std::exception& e) { LOG_ERROR("Exception in LoadConfigToUI: %s\n", e.what()); - QMessageBox::warning(this, "警告", + StyledMessageBox::warning(this, "警告", QString("加载配置时发生异常: %1\n将使用默认参数显示").arg(e.what())); // 发生异常时也使用默认参数 @@ -95,7 +96,7 @@ void DialogAlgoarg::LoadConfigToUI() LoadGrowParamToUI(algoParams.growParam); } catch (...) { LOG_ERROR("Unknown exception in LoadConfigToUI\n"); - QMessageBox::warning(this, "警告", "加载配置文件失败(未知错误),将使用默认参数显示"); + StyledMessageBox::warning(this, "警告", "加载配置文件失败(未知错误),将使用默认参数显示"); // 发生未知异常时也使用默认参数 m_configData = ConfigResult(); @@ -157,22 +158,22 @@ bool DialogAlgoarg::SaveConfigFromUI() // 保存各个参数组 if (!SaveWorkpieceParamFromUI(algoParams.workpieceParam)) { - QMessageBox::warning(this, "错误", "工件参数输入有误,请检查!"); + StyledMessageBox::warning(this, "错误", "工件参数输入有误,请检查!"); return false; } if (!SaveFilterParamFromUI(algoParams.filterParam)) { - QMessageBox::warning(this, "错误", "滤波参数输入有误,请检查!"); + StyledMessageBox::warning(this, "错误", "滤波参数输入有误,请检查!"); return false; } if (!SaveCornerParamFromUI(algoParams.cornerParam)) { - QMessageBox::warning(this, "错误", "拐角参数输入有误,请检查!"); + StyledMessageBox::warning(this, "错误", "拐角参数输入有误,请检查!"); return false; } if (!SaveGrowParamFromUI(algoParams.growParam)) { - QMessageBox::warning(this, "错误", "生长参数输入有误,请检查!"); + StyledMessageBox::warning(this, "错误", "生长参数输入有误,请检查!"); return false; } @@ -260,10 +261,10 @@ bool DialogAlgoarg::SaveGrowParamFromUI(VrTreeGrowParam& param) void DialogAlgoarg::on_btn_camer_ok_clicked() { if (SaveConfigFromUI()) { - QMessageBox::information(this, "成功", "配置保存成功!"); + StyledMessageBox::information(this, "成功", "配置保存成功!"); accept(); } else { - QMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限或参数输入!"); + StyledMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限或参数输入!"); } } diff --git a/App/Workpiece/WorkpieceApp/dialogcameralevel.ui b/App/Workpiece/WorkpieceApp/dialogcameralevel.ui index f5d74d1..4d0ce3d 100644 --- a/App/Workpiece/WorkpieceApp/dialogcameralevel.ui +++ b/App/Workpiece/WorkpieceApp/dialogcameralevel.ui @@ -7,7 +7,7 @@ 0 0 659 - 400 + 448 @@ -58,14 +58,14 @@ 相机调平 - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 180 - 350 + 390 101 38 @@ -86,7 +86,7 @@ 390 - 350 + 390 111 38 @@ -128,7 +128,7 @@ background-color: rgb(47, 48, 52); 140 100 401 - 241 + 281 @@ -146,7 +146,7 @@ padding: 5px; - Qt::AlignmentFlag::AlignCenter + Qt::AlignCenter diff --git a/App/Workpiece/WorkpieceApp/mainwindow.cpp b/App/Workpiece/WorkpieceApp/mainwindow.cpp index f8dd041..3817c06 100644 --- a/App/Workpiece/WorkpieceApp/mainwindow.cpp +++ b/App/Workpiece/WorkpieceApp/mainwindow.cpp @@ -30,6 +30,10 @@ #include #include #include "WorkpiecePresenter.h" +#include +#include +#include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -51,10 +55,13 @@ MainWindow::MainWindow(QWidget *parent) QFont statusFont = statusBar()->font(); statusFont.setPointSize(12); statusBar()->setFont(statusFont); - + // 设置状态栏颜色和padding statusBar()->setStyleSheet("QStatusBar { color: rgb(239, 241, 245); padding: 20px; }"); - + + // 设置CPU序列号显示(左下角) + setupCPUSerialDisplay(); + // 在状态栏右侧添加版本信息(包含编译时间) // 使用VrSimpleLog.h中的宏定义构建编译时间 QString versionWithBuildTime = QString("%1_%2%3%4%5%6%7") @@ -65,7 +72,7 @@ MainWindow::MainWindow(QWidget *parent) .arg(HOUR, 2, 10, QChar('0')) .arg(MINUTE, 2, 10, QChar('0')) .arg(SECOND, 2, 10, QChar('0')); - + QLabel* buildLabel = new QLabel(versionWithBuildTime); buildLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 20px; margin-right: 16px;"); statusBar()->addPermanentWidget(buildLabel); @@ -817,7 +824,7 @@ int MainWindow::getAvailableHeight() if (screen) { QRect availableGeometry = screen->availableGeometry(); // 额外预留20px底部边距 - return availableGeometry.height() - 28; + return availableGeometry.height() - 30; } // 如果无法获取屏幕信息,返回默认值 @@ -852,14 +859,13 @@ void MainWindow::setupSingleCameraLayout() ui->detect_result_list->setWrapping(true); // 允许换行 // 单相机模式:设置gridSize,gridHeight = 207 - int gridWidth = 275; - int gridHeight = 206; + int gridWidth = 183; + int gridHeight = 154; ui->detect_result_list->setGridSize(QSize(gridWidth, gridHeight)); // 恢复设备状态widget的原始布局 m_deviceStatusWidget->setCameraCount(1); - // 日志: 位于右下方,动态计算高度 int detectLogTop = 850; int detectLogHeight = availableHeight - detectLogTop; @@ -1013,7 +1019,7 @@ bool MainWindow::saveDetectionDataToFile(const QString& filePath, int cameraInde try { // 直接调用Presenter的保存方法 int result = m_presenter->SaveDetectionDataToFile(filePath.toStdString()); - + if (result == 0) { updateStatusLog(tr("检测数据保存成功")); return true; @@ -1021,12 +1027,85 @@ bool MainWindow::saveDetectionDataToFile(const QString& filePath, int cameraInde updateStatusLog(tr("保存数据失败,错误码:%1").arg(result)); return false; } - + } catch (const std::exception& e) { updateStatusLog(tr("保存数据时发生异常:%1").arg(e.what())); return false; } } +// 获取CPU序列号(跨平台实现) +QString MainWindow::getCPUSerialNumber() +{ + QString serialNumber = "UNKNOWN"; + +#ifdef _WIN32 + // Windows平台:使用WMI获取CPU序列号 + QProcess process; + process.start("wmic", QStringList() << "cpu" << "get" << "ProcessorId"); + process.waitForFinished(); + + QString output = QString::fromLocal8Bit(process.readAllStandardOutput()); + QStringList lines = output.split('\n', Qt::SkipEmptyParts); + + // 第一行是标题"ProcessorId",第二行是实际的序列号 + if (lines.size() >= 2) { + serialNumber = lines[1].trimmed(); + } + + // 如果WMIC失败,尝试读取注册表(备用方案) + if (serialNumber.isEmpty() || serialNumber == "UNKNOWN") { + QSettings settings("HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", QSettings::NativeFormat); + serialNumber = settings.value("ProcessorNameString", "UNKNOWN").toString(); + + // 从处理器名称中提取唯一标识 + if (serialNumber != "UNKNOWN") { + // 使用处理器名称的哈希作为替代 + serialNumber = QString("WIN_%1").arg(QString::number(qHash(serialNumber), 16).toUpper()); + } + } +#else + // Linux/ARM Ubuntu平台:从/proc/cpuinfo读取 + QFile file("/proc/cpuinfo"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + QString line; + + // 首先尝试查找Serial字段 + while (!in.atEnd()) { + line = in.readLine(); + if (line.contains("Serial", Qt::CaseInsensitive)) { + QStringList parts = line.split(':'); + if (parts.size() >= 2) { + serialNumber = parts[1].trimmed(); + break; + } + } + } + file.close(); + } + +#endif + + // 转换为大写 + return serialNumber.toUpper(); +} + +// 设置CPU序列号显示 +void MainWindow::setupCPUSerialDisplay() +{ + return; + + QString cpuSerial = getCPUSerialNumber(); + + // 创建CPU序列号标签 + m_cpuSerialLabel = new QLabel(QString("编号: %1").arg(cpuSerial)); + m_cpuSerialLabel->setStyleSheet("color: rgb(239, 241, 245); font-size: 16px; margin-left: 16px;"); + + // 添加到状态栏左侧 + statusBar()->addWidget(m_cpuSerialLabel); + + LOG_INFO("CPU Serial Number: %s\n", cpuSerial.toStdString().c_str()); +} diff --git a/App/Workpiece/WorkpieceApp/mainwindow.h b/App/Workpiece/WorkpieceApp/mainwindow.h index 39b2dfb..a01424c 100644 --- a/App/Workpiece/WorkpieceApp/mainwindow.h +++ b/App/Workpiece/WorkpieceApp/mainwindow.h @@ -141,5 +141,12 @@ private: void setupContextMenu(); void showContextMenu(const QPoint& pos, QGraphicsView* view); bool saveDetectionDataToFile(const QString& filePath, int cameraIndex); + + // CPU序列号相关函数 + QString getCPUSerialNumber(); + void setupCPUSerialDisplay(); + +private: + QLabel* m_cpuSerialLabel = nullptr; // CPU序列号标签 }; #endif // MAINWINDOW_H diff --git a/App/Workpiece/WorkpieceApp/mainwindow.ui b/App/Workpiece/WorkpieceApp/mainwindow.ui index 3931193..d9d161f 100644 --- a/App/Workpiece/WorkpieceApp/mainwindow.ui +++ b/App/Workpiece/WorkpieceApp/mainwindow.ui @@ -60,13 +60,14 @@ color: rgb(239, 241, 245); 40 14 - 341 + 431 91 - 40 + 36 + true @@ -74,7 +75,7 @@ color: rgb(239, 241, 245); background-color: rgba(255, 255, 255, 0); - 工件定位 + 3D视觉定位系统 @@ -353,7 +354,7 @@ background-color: rgba(255, 255, 255, 0); 0 0 1920 - 20 + 21 diff --git a/App/Workpiece/WorkpieceApp/resultitem.cpp b/App/Workpiece/WorkpieceApp/resultitem.cpp index 5b56777..981d3d7 100644 --- a/App/Workpiece/WorkpieceApp/resultitem.cpp +++ b/App/Workpiece/WorkpieceApp/resultitem.cpp @@ -28,7 +28,6 @@ void ResultItem::setResultData(int targetIndex, const WorkpiecePosition& positio ui->result_x->setText(QString("%1").arg(position.x, 0, 'f', 2)); ui->result_y->setText(QString("%1").arg(position.y, 0, 'f', 2)); ui->result_z->setText(QString("%1").arg(position.z, 0, 'f', 2)); - ui->result_rz->setText(QString("%1").arg(position.yaw, 0, 'f', 2)); } @@ -37,7 +36,7 @@ void ResultItem::setItemStyle() // 只设置右侧和下侧边框作为格子间分隔线,不修改背景和QLabel样式 this->setStyleSheet( "ResultItem { " - " border: 6px solid #191A1C; " // 右侧边框 + " border: 1px solid #191A1C; " // 右侧边框 " border-radius: 0px; " // 去掉圆角,让分隔线更清晰 "} " ); diff --git a/App/Workpiece/WorkpieceApp/resultitem.ui b/App/Workpiece/WorkpieceApp/resultitem.ui index 71521ff..ff59b7b 100644 --- a/App/Workpiece/WorkpieceApp/resultitem.ui +++ b/App/Workpiece/WorkpieceApp/resultitem.ui @@ -6,8 +6,8 @@ 0 0 - 272 - 200 + 180 + 152 @@ -20,10 +20,10 @@ - 48 - 13 - 161 - 29 + 50 + 15 + 121 + 24 @@ -32,7 +32,7 @@ - Qt::LayoutDirection::LeftToRight + Qt::LeftToRight color: rgb(239, 241, 245); @@ -42,14 +42,14 @@ background-color: rgb(37, 38, 42); 目标 - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - 16 - 16 + 10 + 15 24 24 @@ -59,225 +59,158 @@ background-color: rgb(37, 38, 42); background-color: rgba(255, 255, 255, 0); - + - 59 - 43 - 58 - 30 + 20 + 50 + 61 + 91 - - - 12 - - - - Qt::LayoutDirection::RightToLeft - - - color: rgb(239, 241, 245); + + + + + + 12 + + + + Qt::RightToLeft + + + color: rgb(239, 241, 245); background-color: rgb(37, 38, 42); - - - 坐标X: - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - - - - - 59 - 78 - 58 - 30 - - - - - 12 - - - - Qt::LayoutDirection::RightToLeft - - - color: rgb(239, 241, 245); + + + 坐标X: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + Qt::RightToLeft + + + color: rgb(239, 241, 245); background-color: rgb(37, 38, 42); - - - 坐标Y: - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - - - - - 33 - 148 - 84 - 30 - - - - - 12 - - - - Qt::LayoutDirection::RightToLeft - - - color: rgb(239, 241, 245); + + + 坐标Y: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 12 + + + + Qt::RightToLeft + + + color: rgb(239, 241, 245); background-color: rgb(37, 38, 42); - - - 旋转角RZ: - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - + + + 坐标Z: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + - + - 59 - 113 - 58 - 30 + 80 + 50 + 91 + 92 - - - 12 - - - - Qt::LayoutDirection::RightToLeft - - - color: rgb(239, 241, 245); -background-color: rgb(37, 38, 42); - - - 坐标Z: - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - - - - - 128 - 80 - 85 - 30 - - - - - 12 - - - - background-color: rgb(59, 61, 71); + + + + + + 12 + + + + background-color: rgb(59, 61, 71); color: rgb(239, 241, 245); border: 1px solid #3B3D47; -padding: 5px; - - - - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - - - - - - 128 - 150 - 85 - 30 - - - - - 12 - - - - background-color: rgb(59, 61, 71); +padding: 2px; + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 12 + + + + background-color: rgb(59, 61, 71); color: rgb(239, 241, 245); border: 1px solid #3B3D47; -padding: 5px; - - - - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - - - - - - 128 - 45 - 85 - 30 - - - - - 12 - - - - background-color: rgb(59, 61, 71); +padding: 2px; + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 12 + + + + background-color: rgb(59, 61, 71); color: rgb(239, 241, 245); border: 1px solid #3B3D47; -padding: 5px; - - - - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - - - - - - 128 - 115 - 85 - 30 - - - - - 12 - - - - background-color: rgb(59, 61, 71); -color: rgb(239, 241, 245); -border: 1px solid #3B3D47; -padding: 5px; - - - - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - +padding: 2px; + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + diff --git a/CloudUtils/Inc/LaserDataLoader.h b/CloudUtils/Inc/LaserDataLoader.h index 7982cf6..7c74ef4 100644 --- a/CloudUtils/Inc/LaserDataLoader.h +++ b/CloudUtils/Inc/LaserDataLoader.h @@ -29,6 +29,8 @@ public: int maxTimeStamp, int clockPerSecond); + int DebugSaveLaser(std::string fileName, std::vector> xyzData); + // 释放统一格式数据内存 void FreeLaserScanData(std::vector>& laserLines); @@ -67,4 +69,4 @@ private: static const int VZ_LASER_LINE_PT_MAX_NUM = 4096; }; -#endif // LASER_DATA_LOADER_H \ No newline at end of file +#endif // LASER_DATA_LOADER_H diff --git a/CloudUtils/Inc/PointCloudImageUtils.h b/CloudUtils/Inc/PointCloudImageUtils.h index 9e9bf68..e8a897a 100644 --- a/CloudUtils/Inc/PointCloudImageUtils.h +++ b/CloudUtils/Inc/PointCloudImageUtils.h @@ -29,6 +29,10 @@ public: const std::vector>& weldResults, int imageWidth = 800, int imageHeight = 600); + // Workpiece点云和角点检测结果转图像 - 将角点画成圆点 + static QImage GeneratePointCloudRetPointImage(const std::vector>& scanLines, + const std::vector>& cornerPoints); + private: // 定义线特征颜色和大小获取函数 static void GetLineFeatureStyle(int vType, int hType, int objId, diff --git a/CloudUtils/Src/LaserDataLoader.cpp b/CloudUtils/Src/LaserDataLoader.cpp index bc29043..76802e3 100644 --- a/CloudUtils/Src/LaserDataLoader.cpp +++ b/CloudUtils/Src/LaserDataLoader.cpp @@ -110,6 +110,7 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName, SVzNL3DPosition* p3DPoints = static_cast(sLaserData.p3DPoint); SVzNL2DPosition* p2DPoints = static_cast(sLaserData.p2DPoint); _ParseLaserScanPoint(line, p3DPoints[nLaserPointIdx], p2DPoints[nLaserPointIdx]); + p3DPoints[nLaserPointIdx].nPointIdx = nLaserPointIdx; nLaserPointIdx++; } } @@ -173,7 +174,7 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName, float x = static_cast(points[i].pt3D.x); float y = static_cast(points[i].pt3D.y); float z = static_cast(points[i].pt3D.z); - sw << "{ " << x << "," << y << "," << z << " }-"; + sw << "{ " << std::fixed << std::setprecision(6) << x << "," << y << "," << z << " }-"; sw << "{ " << points2D[i].ptLeft2D.x << "," << points2D[i].ptLeft2D.y << " }-"; sw << "{ " << points2D[i].ptRight2D.x << "," << points2D[i].ptRight2D.y << " }" << std::endl; } @@ -211,6 +212,60 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName, } } +int LaserDataLoader::DebugSaveLaser(std::string fileName, std::vector > xyzData) +{ + LOG_INFO("Saving unified laser scan data to file: %s\n", fileName.c_str()); + + if (xyzData.empty()) { + m_lastError = "Invalid input parameters for saving unified data"; + LOG_ERROR("Invalid parameters for saving unified laser data\n"); + return ERR_CODE(DEV_ARG_INVAILD); + } + + try { + std::ofstream sw(fileName); + if (!sw.is_open()) { + m_lastError = "Cannot open file for writing: " + fileName; + LOG_ERROR("Cannot open file for writing: %s\n", fileName.c_str()); + return ERR_CODE(FILE_ERR_WRITE); + } + + // 写入文件头 + sw << "LineNum:" << xyzData.size() << std::endl; + sw << "DataType: 0" << std::endl; + sw << "ScanSpeed:" << 0 << std::endl; + sw << "PointAdjust: 1" << std::endl; + sw << "MaxTimeStamp:" << 0 << "_" << 0 << std::endl; + + int index = 0; + // 写入每条扫描线数据 + for (const auto& linePair : xyzData) { + sw << "Line_" << index++ << "_" << 0 << "_" << linePair.size() << std::endl; + // 根据数据类型写入点云数据 + for(const auto& point : linePair){ + + // 写入XYZ格式数据 + float x = static_cast(point.pt3D.x); + float y = static_cast(point.pt3D.y); + float z = static_cast(point.pt3D.z); + sw << "{ " + << std::fixed << std::setprecision(6) << x << ", " + << std::fixed << std::setprecision(6) << y << ", " + << std::fixed << std::setprecision(6) << z << " } - "; + sw << "{ 0, 0 } - { 0, 0 }" << std::endl; + } + } + + sw.close(); + return SUCCESS; + + } catch (const std::exception& e) { + m_lastError = "Error saving unified file: " + std::string(e.what()); + LOG_ERROR("Error saving unified laser data to file: %s\n", e.what()); + return ERR_CODE(FILE_ERR_WRITE); + } +} + void LaserDataLoader::FreeLaserScanData(std::vector>& laserLines) { LOG_DEBUG("Freeing unified laser scan data, line count: %zu\n", laserLines.size()); diff --git a/CloudUtils/Src/PointCloudImageUtils.cpp b/CloudUtils/Src/PointCloudImageUtils.cpp index a7914ce..822b0b9 100644 --- a/CloudUtils/Src/PointCloudImageUtils.cpp +++ b/CloudUtils/Src/PointCloudImageUtils.cpp @@ -669,3 +669,123 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter, } } } + +// Workpiece点云和角点检测结果转图像 - 将角点画成圆点 +QImage PointCloudImageUtils::GeneratePointCloudRetPointImage(const std::vector>& scanLines, + const std::vector>& cornerPoints) +{ + if (scanLines.empty()) { + return QImage(); + } + + // 固定图像尺寸,与其他函数保持一致 + int imgRows = 992; + int imgCols = 1056; + int x_skip = 16; + int y_skip = 16; + + // 计算点云范围 + double xMin, xMax, yMin, yMax; + CalculateScanLinesRange(scanLines, xMin, xMax, yMin, yMax); + + // 检查范围是否有效 + if (xMax <= xMin || yMax <= yMin) { + return QImage(); + } + + // 创建图像 + QImage image(imgCols, imgRows, QImage::Format_RGB888); + image.fill(Qt::black); + + QPainter painter(&image); + + // 计算投影比例 + double y_rows = (double)(imgRows - y_skip * 2); + double x_cols = (double)(imgCols - x_skip * 2); + double x_scale = (xMax - xMin) / x_cols; + double y_scale = (yMax - yMin) / y_rows; + + // 使用统一的比例尺 + if (x_scale < y_scale) + x_scale = y_scale; + else + y_scale = x_scale; + + // 绘制点云数据 + for (const auto& scanLine : scanLines) { + for (const auto& point : scanLine) { + if (point.pt3D.z < 1e-4) continue; + + // 解析点索引信息 + int vType = point.nPointIdx & 0xff; + int hType = vType >> 4; + int objId = (point.nPointIdx >> 16) & 0xff; + vType = vType & 0x0f; + + // 根据线特征类型确定颜色和大小 + QColor pointColor; + int pointSize = 1; + GetLineFeatureStyle(vType, hType, objId, pointColor, pointSize); + + // 计算图像坐标 + int px = (int)((point.pt3D.x - xMin) / x_scale + x_skip); + int py = (int)((point.pt3D.y - yMin) / y_scale + y_skip); + + if (px >= 0 && px < imgCols && py >= 0 && py < imgRows) { + painter.setPen(QPen(pointColor, pointSize)); + painter.drawPoint(px, py); + } + } + } + + // 绘制角点作为圆点 + if (!cornerPoints.empty()) { + // 定义不同组角点的颜色 + QColor cornerColors[] = { + QColor(255, 0, 0), // 红色 + QColor(0, 255, 0), // 绿色 + QColor(0, 0, 255), // 蓝色 + QColor(255, 255, 0), // 黄色 + QColor(255, 0, 255), // 紫色 + QColor(0, 255, 255), // 青色 + QColor(255, 128, 0), // 橙色 + QColor(128, 255, 0) // 浅绿色 + }; + int numColors = sizeof(cornerColors) / sizeof(cornerColors[0]); + + for (size_t i = 0; i < cornerPoints.size(); i++) { + const auto& cornerGroup = cornerPoints[i]; + if (cornerGroup.empty()) continue; + + QColor cornerColor = cornerColors[i % numColors]; + + // 绘制每个角点 + for (size_t j = 0; j < cornerGroup.size(); j++) { + const SVzNL3DPoint& corner = cornerGroup[j]; + + // 计算图像坐标 + int px = (int)((corner.x - xMin) / x_scale + x_skip); + int py = (int)((corner.y - yMin) / y_scale + y_skip); + + if (px >= 0 && px < imgCols && py >= 0 && py < imgRows) { + // 绘制圆点标记 + int circleSize = 10; // 圆点直径 + painter.setPen(QPen(cornerColor, 2)); + painter.setBrush(QBrush(cornerColor)); + painter.drawEllipse(px - circleSize/2, py - circleSize/2, circleSize, circleSize); + + // 绘制角点编号,确保不超出图像边界 + painter.setPen(QPen(Qt::white, 1)); + QFont font("Arial", 16, QFont::Bold); + painter.setFont(font); + + QString numberText = QString("%1").arg(j + 1); + painter.drawText(px + 8, py + 8, numberText); + } + } + } + } + + return image; +} + diff --git a/SDK/workpieceCornerExtraction/Inc/SG_errCode.h b/SDK/workpieceCornerExtraction/Inc/SG_errCode.h index e0fd99d..6fc72fb 100644 --- a/SDK/workpieceCornerExtraction/Inc/SG_errCode.h +++ b/SDK/workpieceCornerExtraction/Inc/SG_errCode.h @@ -9,4 +9,6 @@ //BQ_workpiece #define SX_ERR_INVLD_VTREE_NUM -2001 -#define SX_ERR_INVLD_HTREE_NUM -2002 \ No newline at end of file +#define SX_ERR_INVLD_HTREE_NUM -2002 +#define SX_ERR_INVLD_EDGE_LINK_NUM -2003 +#define SX_ERR_INVLD_CLOSES_PT -2004 \ No newline at end of file diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.dll b/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.dll index dd6f166..a0d9e07 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.dll and b/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.dll differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.pdb b/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.pdb index 664462e..51d25fd 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.pdb and b/SDK/workpieceCornerExtraction/Windows/x64/Debug/BQ_workpieceCornerExtraction.pdb differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.dll b/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.dll index cfd1d7e..f6d6c1b 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.dll and b/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.dll differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.pdb b/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.pdb index 8470255..8ed2cf9 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.pdb and b/SDK/workpieceCornerExtraction/Windows/x64/Debug/baseAlgorithm.pdb differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.dll b/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.dll index 0dc6bf4..365b0d5 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.dll and b/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.dll differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.pdb b/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.pdb index 7f8b0d0..854ffbe 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.pdb and b/SDK/workpieceCornerExtraction/Windows/x64/Release/BQ_workpieceCornerExtraction.pdb differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.dll b/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.dll index f6ba263..d321ce8 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.dll and b/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.dll differ diff --git a/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.pdb b/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.pdb index 8f15add..07bd576 100644 Binary files a/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.pdb and b/SDK/workpieceCornerExtraction/Windows/x64/Release/baseAlgorithm.pdb differ