工件定位开发完成
This commit is contained in:
parent
12585d2d2b
commit
81aefc448c
@ -52,6 +52,7 @@ struct DetectionResult {
|
||||
QImage image;
|
||||
std::vector<WorkpiecePosition> positions;
|
||||
int cameraIndex = 1; // 相机索引,默认为1(第一个相机)
|
||||
int workpieceType = 0; // 工件类型:1/2/3/4等
|
||||
};
|
||||
|
||||
// 状态回调接口
|
||||
|
||||
@ -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 获取当前连接状态
|
||||
|
||||
@ -11,56 +11,6 @@ DetectPresenter::~DetectPresenter()
|
||||
}
|
||||
|
||||
|
||||
void vzReadLaserScanPointFromFile_XYZ_vector(const char* fileName, std::vector<std::vector< SVzNL3DPosition>>& 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<std::pair<EVzResultDataType, SVzLaserLineData>>& laserLines,
|
||||
@ -94,20 +44,15 @@ int DetectPresenter::DetectWorkpiece(
|
||||
dataLoader.SaveLaserScanData(fileName, laserLines, laserLines.size(), 0.0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
int nRet = SUCCESS;
|
||||
|
||||
// 转换为算法需要的XYZ格式
|
||||
std::vector<std::vector<SVzNL3DPosition>> 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 height: %.3f\n", groundCalibPara.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]);
|
||||
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);
|
||||
}
|
||||
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<std::vector<SVzNL3DPoint>> objOps;
|
||||
std::vector<SVzNL3DPoint> 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++) {
|
||||
|
||||
@ -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<QJsonObject> 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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -837,6 +837,15 @@ 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();
|
||||
|
||||
@ -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
|
||||
|
||||
# 添加系统库依赖
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <QtCore/QFile>
|
||||
#include <cstring>
|
||||
#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, "失败", "配置保存失败,请检查文件权限或参数输入!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>659</width>
|
||||
<height>400</height>
|
||||
<height>448</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -58,14 +58,14 @@
|
||||
<string>相机调平</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btn_apply">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>180</x>
|
||||
<y>350</y>
|
||||
<y>390</y>
|
||||
<width>101</width>
|
||||
<height>38</height>
|
||||
</rect>
|
||||
@ -86,7 +86,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>390</x>
|
||||
<y>350</y>
|
||||
<y>390</y>
|
||||
<width>111</width>
|
||||
<height>38</height>
|
||||
</rect>
|
||||
@ -128,7 +128,7 @@ background-color: rgb(47, 48, 52);</string>
|
||||
<x>140</x>
|
||||
<y>100</y>
|
||||
<width>401</width>
|
||||
<height>241</height>
|
||||
<height>281</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -146,7 +146,7 @@ padding: 5px;</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
@ -30,6 +30,10 @@
|
||||
#include <QDir>
|
||||
#include <QGraphicsView>
|
||||
#include "WorkpiecePresenter.h"
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
@ -55,6 +59,9 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// 设置状态栏颜色和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")
|
||||
@ -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;
|
||||
@ -1028,5 +1034,78 @@ bool MainWindow::saveDetectionDataToFile(const QString& filePath, int cameraInde
|
||||
}
|
||||
}
|
||||
|
||||
// 获取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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -60,13 +60,14 @@ color: rgb(239, 241, 245);</string>
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>14</y>
|
||||
<width>341</width>
|
||||
<width>431</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>40</pointsize>
|
||||
<pointsize>36</pointsize>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
@ -74,7 +75,7 @@ color: rgb(239, 241, 245);</string>
|
||||
background-color: rgba(255, 255, 255, 0);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>工件定位</string>
|
||||
<string>3D视觉定位系统</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListWidget" name="detect_result_list">
|
||||
@ -353,7 +354,7 @@ background-color: rgba(255, 255, 255, 0);</string>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1920</width>
|
||||
<height>20</height>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
|
||||
@ -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; " // 去掉圆角,让分隔线更清晰
|
||||
"} "
|
||||
);
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>272</width>
|
||||
<height>200</height>
|
||||
<width>180</width>
|
||||
<height>152</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -20,10 +20,10 @@
|
||||
<widget class="QLabel" name="result_id">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>48</x>
|
||||
<y>13</y>
|
||||
<width>161</width>
|
||||
<height>29</height>
|
||||
<x>50</x>
|
||||
<y>15</y>
|
||||
<width>121</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -32,7 +32,7 @@
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(239, 241, 245);
|
||||
@ -42,14 +42,14 @@ background-color: rgb(37, 38, 42);</string>
|
||||
<string>目标</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>16</x>
|
||||
<y>16</y>
|
||||
<x>10</x>
|
||||
<y>15</y>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
@ -59,22 +59,25 @@ background-color: rgb(37, 38, 42);</string>
|
||||
background-color: rgba(255, 255, 255, 0);</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>59</x>
|
||||
<y>43</y>
|
||||
<width>58</width>
|
||||
<height>30</height>
|
||||
<x>20</x>
|
||||
<y>50</y>
|
||||
<width>61</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(239, 241, 245);
|
||||
@ -84,25 +87,19 @@ background-color: rgb(37, 38, 42);</string>
|
||||
<string>坐标X:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>59</x>
|
||||
<y>78</y>
|
||||
<width>58</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(239, 241, 245);
|
||||
@ -112,53 +109,19 @@ background-color: rgb(37, 38, 42);</string>
|
||||
<string>坐标Y:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>33</x>
|
||||
<y>148</y>
|
||||
<width>84</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(239, 241, 245);
|
||||
background-color: rgb(37, 38, 42);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>旋转角RZ:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>59</x>
|
||||
<y>113</y>
|
||||
<width>58</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(239, 241, 245);
|
||||
@ -168,72 +131,24 @@ background-color: rgb(37, 38, 42);</string>
|
||||
<string>坐标Z:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="result_y">
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>128</x>
|
||||
<y>80</y>
|
||||
<width>85</width>
|
||||
<height>30</height>
|
||||
<x>80</x>
|
||||
<y>50</y>
|
||||
<width>91</width>
|
||||
<height>92</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(59, 61, 71);
|
||||
color: rgb(239, 241, 245);
|
||||
border: 1px solid #3B3D47;
|
||||
padding: 5px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="result_rz">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>128</x>
|
||||
<y>150</y>
|
||||
<width>85</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(59, 61, 71);
|
||||
color: rgb(239, 241, 245);
|
||||
border: 1px solid #3B3D47;
|
||||
padding: 5px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="result_x">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>128</x>
|
||||
<y>45</y>
|
||||
<width>85</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
@ -243,24 +158,18 @@ padding: 5px;</string>
|
||||
<string notr="true">background-color: rgb(59, 61, 71);
|
||||
color: rgb(239, 241, 245);
|
||||
border: 1px solid #3B3D47;
|
||||
padding: 5px;</string>
|
||||
padding: 2px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="result_z">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>128</x>
|
||||
<y>115</y>
|
||||
<width>85</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="result_y">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
@ -270,15 +179,39 @@ padding: 5px;</string>
|
||||
<string notr="true">background-color: rgb(59, 61, 71);
|
||||
color: rgb(239, 241, 245);
|
||||
border: 1px solid #3B3D47;
|
||||
padding: 5px;</string>
|
||||
padding: 2px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="result_z">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(59, 61, 71);
|
||||
color: rgb(239, 241, 245);
|
||||
border: 1px solid #3B3D47;
|
||||
padding: 2px;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@ -29,6 +29,8 @@ public:
|
||||
int maxTimeStamp,
|
||||
int clockPerSecond);
|
||||
|
||||
int DebugSaveLaser(std::string fileName, std::vector<std::vector<SVzNL3DPosition>> xyzData);
|
||||
|
||||
// 释放统一格式数据内存
|
||||
void FreeLaserScanData(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& laserLines);
|
||||
|
||||
|
||||
@ -29,6 +29,10 @@ public:
|
||||
const std::vector<std::vector<SVzNL3DPoint>>& weldResults,
|
||||
int imageWidth = 800, int imageHeight = 600);
|
||||
|
||||
// Workpiece点云和角点检测结果转图像 - 将角点画成圆点
|
||||
static QImage GeneratePointCloudRetPointImage(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
const std::vector<std::vector<SVzNL3DPoint>>& cornerPoints);
|
||||
|
||||
private:
|
||||
// 定义线特征颜色和大小获取函数
|
||||
static void GetLineFeatureStyle(int vType, int hType, int objId,
|
||||
|
||||
@ -110,6 +110,7 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName,
|
||||
SVzNL3DPosition* p3DPoints = static_cast<SVzNL3DPosition*>(sLaserData.p3DPoint);
|
||||
SVzNL2DPosition* p2DPoints = static_cast<SVzNL2DPosition*>(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<float>(points[i].pt3D.x);
|
||||
float y = static_cast<float>(points[i].pt3D.y);
|
||||
float z = static_cast<float>(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<std::vector<SVzNL3DPosition> > 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<float>(point.pt3D.x);
|
||||
float y = static_cast<float>(point.pt3D.y);
|
||||
float z = static_cast<float>(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<std::pair<EVzResultDataType, SVzLaserLineData>>& laserLines)
|
||||
{
|
||||
LOG_DEBUG("Freeing unified laser scan data, line count: %zu\n", laserLines.size());
|
||||
|
||||
@ -669,3 +669,123 @@ void PointCloudImageUtils::DrawLapWeldResults(QPainter& painter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workpiece点云和角点检测结果转图像 - 将角点画成圆点
|
||||
QImage PointCloudImageUtils::GeneratePointCloudRetPointImage(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
const std::vector<std::vector<SVzNL3DPoint>>& 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;
|
||||
}
|
||||
|
||||
|
||||
@ -10,3 +10,5 @@
|
||||
//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
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user