工件孔的检测算法更新,公共绘图接口的更新

This commit is contained in:
杰仔 2026-04-12 00:32:30 +08:00
parent 5f4be9b154
commit 7046696afb
22 changed files with 122 additions and 334 deletions

View File

@ -28,18 +28,6 @@ HECEulerOrder ToHandEyeEulerOrder(int eulerOrder)
} }
} }
HECCalibResult ToHandEyeCalibResult(const double clibMatrix[16])
{
HECCalibResult calibResult;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
calibResult.R.at(i, j) = clibMatrix[i * 4 + j];
}
calibResult.T.at(i) = clibMatrix[i * 4 + 3];
}
return calibResult;
}
} // namespace } // namespace
DetectPresenter::DetectPresenter(/* args */) DetectPresenter::DetectPresenter(/* args */)
@ -145,7 +133,7 @@ int DetectPresenter::DetectRod(
return ERR_CODE(DEV_NOT_FIND); return ERR_CODE(DEV_NOT_FIND);
} }
const HECCalibResult calibResult = ToHandEyeCalibResult(clibMatrix); const HECCalibResult calibResult = HECCalibResult::fromHomogeneousArray(clibMatrix);
const HECEulerOrder hecEulerOrder = ToHandEyeEulerOrder(eulerOrder); const HECEulerOrder hecEulerOrder = ToHandEyeEulerOrder(eulerOrder);
// 构建检测结果:生成点云图像 // 构建检测结果:生成点云图像

View File

@ -13,7 +13,6 @@
#include "IYWorkpieceHoleStatus.h" #include "IYWorkpieceHoleStatus.h"
#include "PointCloudImageUtils.h" #include "PointCloudImageUtils.h"
#include "VrDateUtils.h" #include "VrDateUtils.h"
#include "CoordinateTransform.h"
class DetectPresenter class DetectPresenter
{ {

View File

@ -68,40 +68,6 @@ public:
// 手眼标定矩阵管理 // 手眼标定矩阵管理
CalibMatrix GetClibMatrix(int index) const; CalibMatrix GetClibMatrix(int index) const;
// ============ 坐标转换接口 ============
/**
* @brief
*
* @param workpieceInfo
* @param robotPose 姿
* @param handEye
* @param targetPose 姿
*
* 使
* - Eye-in-Hand
* - x_dir, y_dir, z_dir
* - targetPose 姿
*/
void ConvertWorkpieceToRobotPose(const WD_workpieceInfo& workpieceInfo,
const CTRobotPose& robotPose,
const CTSixAxisCalibResult& handEye,
CTRobotPose& targetPose);
/**
* @brief Eye-to-Hand模式
*
* @param workpieceInfo
* @param cameraToBase
* @param targetPose 姿
*
* 使
* - Eye-to-Hand
*/
void ConvertWorkpieceToRobotPoseEyeToHand(const WD_workpieceInfo& workpieceInfo,
const CTSixAxisCalibResult& cameraToBase,
CTRobotPose& targetPose);
// 实现IVrConfigChangeNotify接口 // 实现IVrConfigChangeNotify接口
virtual void OnConfigChanged(const ConfigResult& configResult) override; virtual void OnConfigChanged(const ConfigResult& configResult) override;

View File

@ -2,13 +2,9 @@
#include "workpieceHolePositioning_Export.h" #include "workpieceHolePositioning_Export.h"
#include "SG_baseAlgo_Export.h" #include "SG_baseAlgo_Export.h"
#include "AlgoParamConverter.h" #include "AlgoParamConverter.h"
#include "IHandEyeCalib.h"
#include <fstream> #include <fstream>
#include <QPainter> #include <memory>
#include <QPen>
#include <QColor>
#include <opencv2/opencv.hpp>
#include "CoordinateTransform.h"
#include "VrConvert.h"
DetectPresenter::DetectPresenter(/* args */) DetectPresenter::DetectPresenter(/* args */)
{ {
@ -91,15 +87,15 @@ int DetectPresenter::DetectWorkpieceHole(
AlgoParamConverter::LogAlgoParams("[Algo Thread]", AlgoParamConverter::LogAlgoParams("[Algo Thread]",
workpiecePara, lineSegPara, filterParam, growParam, groundCalibPara, clibMatrix); workpiecePara, lineSegPara, filterParam, growParam, groundCalibPara, clibMatrix);
} }
#if 0
// 数据预处理:调平和去除地面(使用当前相机的调平参数) // 数据预处理:调平和去除地面(使用当前相机的调平参数)
if(cameraCalibParam){ if(cameraCalibParam){
LOG_DEBUG("Processing data with plane calibration\n"); LOG_DEBUG("Processing data with plane calibration\n");
double groundH = -1;
for(size_t i = 0; i < xyzData.size(); i++){ for(size_t i = 0; i < xyzData.size(); i++){
wd_lineDataR(xyzData[i], cameraCalibParam->planeCalib, groundH); wd_lineDataR(xyzData[i], cameraCalibParam->planeCalib, -1);
} }
} }
#endif
int errCode = 0; int errCode = 0;
CVrTimeUtils oTimeUtils; CVrTimeUtils oTimeUtils;
@ -124,19 +120,16 @@ int DetectPresenter::DetectWorkpieceHole(
LOG_INFO("wd_workpieceHolePositioning: found %zu workpieces, err=%d runtime=%.3fms\n", workpiecePositioning.size(), errCode, oTimeUtils.GetElapsedTimeInMilliSec()); LOG_INFO("wd_workpieceHolePositioning: found %zu workpieces, err=%d runtime=%.3fms\n", workpiecePositioning.size(), errCode, oTimeUtils.GetElapsedTimeInMilliSec());
ERR_CODE_RETURN(errCode); ERR_CODE_RETURN(errCode);
// 从4x4齐次变换矩阵中提取旋转矩阵R(3x3)和平移向量T(3x1) // 创建手眼标定实例
// clibMatrix 是行优先存储的4x4矩阵 std::unique_ptr<IHandEyeCalib, decltype(&DestroyHandEyeCalibInstance)> handEyeCalib(
cv::Mat R = cv::Mat::zeros(3, 3, CV_64F); CreateHandEyeCalibInstance(),
cv::Mat T = cv::Mat::zeros(3, 1, CV_64F); DestroyHandEyeCalibInstance);
for (int i = 0; i < 3; i++) { if (!handEyeCalib) {
for (int j = 0; j < 3; j++) { LOG_ERROR("Failed to create HandEyeCalib instance\n");
R.at<double>(i, j) = clibMatrix[i * 4 + j]; return ERR_CODE(DEV_NOT_FIND);
}
T.at<double>(i, 0) = clibMatrix[i * 4 + 3];
} }
// 构建用于可视化的点数组 const HECCalibResult calibResult = HECCalibResult::fromHomogeneousArray(clibMatrix);
std::vector<std::vector<SVzNL3DPoint>> objOps;
// 处理每个工件的检测结果 // 处理每个工件的检测结果
for (size_t i = 0; i < workpiecePositioning.size(); i++) { for (size_t i = 0; i < workpiecePositioning.size(); i++) {
@ -148,52 +141,44 @@ int DetectPresenter::DetectWorkpieceHole(
} }
// 六轴转换:位置+姿态(转换到机械臂坐标系) // 六轴转换:位置+姿态(转换到机械臂坐标系)
SVzNL3DPoint centerEye = workpiece.center; HECPoint3D eyeCenter(workpiece.center.x, workpiece.center.y, workpiece.center.z);
// 1. 位置转换:使用 pointRT_2 进行坐标变换 // 构建方向向量(眼坐标系)
cv::Point3d ptEye(centerEye.x, centerEye.y, centerEye.z); std::vector<HECPoint3D> dirVectors_eye(3);
cv::Point3d ptRobot; dirVectors_eye[0] = HECPoint3D(workpiece.x_dir.x, workpiece.x_dir.y, workpiece.x_dir.z);
pointRT_2(R, T, ptEye, ptRobot); dirVectors_eye[1] = HECPoint3D(workpiece.y_dir.x, workpiece.y_dir.y, workpiece.y_dir.z);
dirVectors_eye[2] = HECPoint3D(workpiece.z_dir.x, workpiece.z_dir.y, workpiece.z_dir.z);
// 2. 姿态转换:按照测试代码的方式处理方向向量
// 从算法输出获取方向向量
std::vector<cv::Point3d> dirVectors_eye(3);
dirVectors_eye[0] = cv::Point3d(workpiece.x_dir.x, workpiece.x_dir.y, workpiece.x_dir.z);
dirVectors_eye[1] = cv::Point3d(workpiece.y_dir.x, workpiece.y_dir.y, workpiece.y_dir.z);
dirVectors_eye[2] = cv::Point3d(workpiece.z_dir.x, workpiece.z_dir.y, workpiece.z_dir.z);
// 根据配置决定方向向量反向 // 根据配置决定方向向量反向
switch (dirVectorInvert) { switch (dirVectorInvert) {
case DIR_INVERT_NONE: case DIR_INVERT_NONE:
// 不反向
break; break;
case DIR_INVERT_XY: case DIR_INVERT_XY:
// X和Y方向反向 dirVectors_eye[0] = dirVectors_eye[0] * (-1.0);
dirVectors_eye[0] = cv::Point3d(-dirVectors_eye[0].x, -dirVectors_eye[0].y, -dirVectors_eye[0].z); dirVectors_eye[1] = dirVectors_eye[1] * (-1.0);
dirVectors_eye[1] = cv::Point3d(-dirVectors_eye[1].x, -dirVectors_eye[1].y, -dirVectors_eye[1].z);
break; break;
case DIR_INVERT_XZ: case DIR_INVERT_XZ:
// X和Z方向反向 dirVectors_eye[0] = dirVectors_eye[0] * (-1.0);
dirVectors_eye[0] = cv::Point3d(-dirVectors_eye[0].x, -dirVectors_eye[0].y, -dirVectors_eye[0].z); dirVectors_eye[2] = dirVectors_eye[2] * (-1.0);
dirVectors_eye[2] = cv::Point3d(-dirVectors_eye[2].x, -dirVectors_eye[2].y, -dirVectors_eye[2].z);
break; break;
case DIR_INVERT_YZ: case DIR_INVERT_YZ:
default: default:
// Y和Z方向反向默认兼容原有行为 dirVectors_eye[1] = dirVectors_eye[1] * (-1.0);
dirVectors_eye[1] = cv::Point3d(-dirVectors_eye[1].x, -dirVectors_eye[1].y, -dirVectors_eye[1].z); dirVectors_eye[2] = dirVectors_eye[2] * (-1.0);
dirVectors_eye[2] = cv::Point3d(-dirVectors_eye[2].x, -dirVectors_eye[2].y, -dirVectors_eye[2].z);
break; break;
} }
// 使用 pointRotate 对方向向量进行旋转变换 // 1. 位置转换R * P_eye + T
std::vector<cv::Point3d> dirVectors_robot; HECPoint3D ptRobot;
handEyeCalib->TransformPoint(calibResult.R, calibResult.T, eyeCenter, ptRobot);
// 2. 方向向量旋转变换(仅旋转,不平移)
std::vector<HECPoint3D> dirVectors_robot(3);
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
cv::Point3d rt_pt; handEyeCalib->RotatePoint(calibResult.R, dirVectors_eye[j], dirVectors_robot[j]);
pointRotate(R, dirVectors_eye[j], rt_pt);
dirVectors_robot.push_back(rt_pt);
} }
// 3. 构建旋转矩阵(按照测试代码的方式) // 3. 构建旋转矩阵(列向量形式)
double R_pose[3][3]; double R_pose[3][3];
R_pose[0][0] = dirVectors_robot[0].x; R_pose[0][0] = dirVectors_robot[0].x;
R_pose[0][1] = dirVectors_robot[1].x; R_pose[0][1] = dirVectors_robot[1].x;
@ -205,7 +190,7 @@ int DetectPresenter::DetectWorkpieceHole(
R_pose[2][1] = dirVectors_robot[1].z; R_pose[2][1] = dirVectors_robot[1].z;
R_pose[2][2] = dirVectors_robot[2].z; R_pose[2][2] = dirVectors_robot[2].z;
// 4. 使用 rotationMatrixToEulerZYX 转换为欧拉角外旋ZYX即RZ-RY-RX // 4. 使用算法库的 rotationMatrixToEulerZYX 转换为欧拉角(返回角度
SSG_EulerAngles robotRpy = rotationMatrixToEulerZYX(R_pose); SSG_EulerAngles robotRpy = rotationMatrixToEulerZYX(R_pose);
// 将机器人坐标系下的位姿添加到positions列表 // 将机器人坐标系下的位姿添加到positions列表
@ -213,21 +198,12 @@ int DetectPresenter::DetectWorkpieceHole(
centerRobotPos.x = ptRobot.x; centerRobotPos.x = ptRobot.x;
centerRobotPos.y = ptRobot.y; centerRobotPos.y = ptRobot.y;
centerRobotPos.z = ptRobot.z; centerRobotPos.z = ptRobot.z;
centerRobotPos.roll = robotRpy.roll; // 已经是角度 centerRobotPos.roll = robotRpy.roll;
centerRobotPos.pitch = robotRpy.pitch; // 已经是角度 centerRobotPos.pitch = robotRpy.pitch;
centerRobotPos.yaw = robotRpy.yaw; // 已经是角度 centerRobotPos.yaw = robotRpy.yaw;
detectionResult.positions.push_back(centerRobotPos); detectionResult.positions.push_back(centerRobotPos);
// 添加中心点到可视化列表
std::vector<SVzNL3DPoint> holePoints;
for(size_t j = 0; j < workpiece.holes.size(); j++){
SVzNL3DPoint holeEye = workpiece.holes[j];
holePoints.push_back(holeEye);
}
holePoints.push_back(centerEye);
objOps.push_back(holePoints);
if(debugParam.enableDebug && debugParam.printDetailLog){ if(debugParam.enableDebug && debugParam.printDetailLog){
LOG_INFO("[Algo Thread] Direction vectors (eye): X=(%.3f,%.3f,%.3f), Y=(%.3f,%.3f,%.3f), Z=(%.3f,%.3f,%.3f)\n", LOG_INFO("[Algo Thread] Direction vectors (eye): X=(%.3f,%.3f,%.3f), Y=(%.3f,%.3f,%.3f), Z=(%.3f,%.3f,%.3f)\n",
workpiece.x_dir.x, workpiece.x_dir.y, workpiece.x_dir.z, workpiece.x_dir.x, workpiece.x_dir.y, workpiece.x_dir.z,
@ -237,111 +213,29 @@ int DetectPresenter::DetectWorkpieceHole(
dirVectors_robot[0].x, dirVectors_robot[0].y, dirVectors_robot[0].z, dirVectors_robot[0].x, dirVectors_robot[0].y, dirVectors_robot[0].z,
dirVectors_robot[1].x, dirVectors_robot[1].y, dirVectors_robot[1].z, dirVectors_robot[1].x, dirVectors_robot[1].y, dirVectors_robot[1].z,
dirVectors_robot[2].x, dirVectors_robot[2].y, dirVectors_robot[2].z); dirVectors_robot[2].x, dirVectors_robot[2].y, dirVectors_robot[2].z);
LOG_INFO("[Algo Thread] Center Eye Coords: X=%.2f, Y=%.2f, Z=%.2f\n", LOG_INFO("[Algo Thread] Center Eye Coords: X=%.3f, Y=%.3f, Z=%.3f\n",
centerEye.x, centerEye.y, centerEye.z); workpiece.center.x, workpiece.center.y, workpiece.center.z);
LOG_INFO("[Algo Thread] Center Robot Coords: X=%.2f, Y=%.2f, Z=%.2f, R=%.4f, P=%.4f, Y=%.4f\n", LOG_INFO("[Algo Thread] Center Robot Coords: X=%.3f, Y=%.3f, Z=%.3f, R=%.4f, P=%.4f, Y=%.4f\n",
ptRobot.x, ptRobot.y, ptRobot.z, ptRobot.x, ptRobot.y, ptRobot.z,
centerRobotPos.roll, centerRobotPos.pitch, centerRobotPos.yaw); centerRobotPos.roll, centerRobotPos.pitch, centerRobotPos.yaw);
} }
} }
// 从点云数据生成投影图像(单色灰色点云 + 红色孔位标记 // 使用 PointCloudCanvas 生成点云图像(灰色底图 + 红色孔位标记 + 中心点编号
{ {
// 固定图像尺寸 PointCloudCanvas canvas = PointCloudCanvas::Create(xyzData);
int imgRows = 992; for (size_t i = 0; i < workpiecePositioning.size(); i++) {
int imgCols = 1056; const WD_workpieceInfo& workpiece = workpiecePositioning[i];
int x_skip = 50; // 红色小圆点标记每个孔
int y_skip = 50; for (size_t j = 0; j < workpiece.holes.size(); j++) {
canvas.drawPoint(workpiece.holes[j].x, workpiece.holes[j].y, QColor(255, 0, 0), 4);
// 计算点云范围
double xMin = 1e10, xMax = -1e10, yMin = 1e10, yMax = -1e10;
for (const auto& line : xyzData) {
for (const auto& pt : line) {
if (pt.pt3D.z < 1e-4) continue;
xMin = std::min(xMin, (double)pt.pt3D.x);
xMax = std::max(xMax, (double)pt.pt3D.x);
yMin = std::min(yMin, (double)pt.pt3D.y);
yMax = std::max(yMax, (double)pt.pt3D.y);
} }
// 中心点标记 + 白色编号
canvas.drawPoint(workpiece.center.x, workpiece.center.y, QColor(255, 0, 0), 4);
canvas.drawText(workpiece.center.x, workpiece.center.y,
QString("%1").arg(i + 1), Qt::white, 14);
} }
detectionResult.image = canvas.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;
// 创建图像
QImage image(imgCols, imgRows, QImage::Format_RGB888);
image.fill(Qt::black);
QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing);
// 绘制点云数据 - 使用单色灰色
QColor grayColor(150, 150, 150);
for (const auto& scanLine : xyzData) {
for (const auto& point : scanLine) {
if (point.pt3D.z < 1e-4) continue;
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(grayColor, 1));
painter.drawPoint(px, py);
}
}
}
// 绘制孔位标记 - 使用红色
if (!objOps.empty()) {
QColor holeColor(255, 0, 0); // 红色
painter.setPen(QPen(holeColor, 1));
painter.setBrush(QBrush(holeColor));
for (size_t i = 0; i < objOps.size(); i++) {
const auto& holeGroup = objOps[i];
size_t groupSize = holeGroup.size();
for (size_t j = 0; j < groupSize; j++) {
const SVzNL3DPoint& hole = holeGroup[j];
// 跳过全0的点
if (fabs(hole.x) < 0.0001 && fabs(hole.y) < 0.0001 && fabs(hole.z) < 0.0001) {
continue;
}
int px = (int)((hole.x - xMin) / x_scale + x_skip);
int py = (int)((hole.y - yMin) / y_scale + y_skip);
if (px >= 0 && px < imgCols && py >= 0 && py < imgRows) {
// 绘制圆点标记
int circleSize = 2;
painter.drawEllipse(px - circleSize/2, py - circleSize/2, circleSize, circleSize);
// 只有中心点(最后一个点)才绘制编号
if (j == groupSize - 1) {
painter.setPen(QPen(Qt::white, 1));
QFont font("Arial", 14, QFont::Bold);
painter.setFont(font);
painter.drawText(px + 8, py + 6, QString("%1").arg(i + 1));
// 恢复画笔
painter.setPen(QPen(holeColor, 1));
painter.setBrush(QBrush(holeColor));
}
}
}
}
}
detectionResult.image = image;
} }
if(debugParam.enableDebug && debugParam.saveDebugImage){ if(debugParam.enableDebug && debugParam.saveDebugImage){

View File

@ -255,88 +255,6 @@ CalibMatrix WorkpieceHolePresenter::GetClibMatrix(int index) const
return clibMatrix; return clibMatrix;
} }
// ============ 坐标转换实现 ============
void WorkpieceHolePresenter::ConvertWorkpieceToRobotPose(const WD_workpieceInfo& workpieceInfo,
const CTRobotPose& robotPose,
const CTSixAxisCalibResult& handEye,
CTRobotPose& targetPose)
{
// 1. 从方向向量构建旋转矩阵
CTRotationMatrix rotMatrix;
rotMatrix.at(0, 0) = workpieceInfo.x_dir.x;
rotMatrix.at(1, 0) = workpieceInfo.x_dir.y;
rotMatrix.at(2, 0) = workpieceInfo.x_dir.z;
rotMatrix.at(0, 1) = workpieceInfo.y_dir.x;
rotMatrix.at(1, 1) = workpieceInfo.y_dir.y;
rotMatrix.at(2, 1) = workpieceInfo.y_dir.z;
rotMatrix.at(0, 2) = workpieceInfo.z_dir.x;
rotMatrix.at(1, 2) = workpieceInfo.z_dir.y;
rotMatrix.at(2, 2) = workpieceInfo.z_dir.z;
// 2. 将旋转矩阵转换为欧拉角
CTEulerAngles eulerAngles = CCoordinateTransform::rotationMatrixToEuler(rotMatrix, CTEulerOrder::sZYX);
// 3. 构造相机坐标系下的目标位姿
CTCameraPose cameraPose(
workpieceInfo.center.x,
workpieceInfo.center.y,
workpieceInfo.center.z,
eulerAngles.roll,
eulerAngles.pitch,
eulerAngles.yaw
);
// 4. 使用六轴手眼转换Eye-in-Hand模式计算机器人目标位姿
CCoordinateTransform::sixAxisEyeInHandCalcGraspPose(cameraPose, robotPose, handEye, targetPose);
LOG_DEBUG("ConvertWorkpieceToRobotPose: Camera(%f, %f, %f, %f, %f, %f) -> Robot(%f, %f, %f, %f, %f, %f)\n",
cameraPose.x, cameraPose.y, cameraPose.z,
cameraPose.rx, cameraPose.ry, cameraPose.rz,
targetPose.x, targetPose.y, targetPose.z,
targetPose.rx, targetPose.ry, targetPose.rz);
}
void WorkpieceHolePresenter::ConvertWorkpieceToRobotPoseEyeToHand(const WD_workpieceInfo& workpieceInfo,
const CTSixAxisCalibResult& cameraToBase,
CTRobotPose& targetPose)
{
// 1. 从方向向量构建旋转矩阵
CTRotationMatrix rotMatrix;
rotMatrix.at(0, 0) = workpieceInfo.x_dir.x;
rotMatrix.at(1, 0) = workpieceInfo.x_dir.y;
rotMatrix.at(2, 0) = workpieceInfo.x_dir.z;
rotMatrix.at(0, 1) = workpieceInfo.y_dir.x;
rotMatrix.at(1, 1) = workpieceInfo.y_dir.y;
rotMatrix.at(2, 1) = workpieceInfo.y_dir.z;
rotMatrix.at(0, 2) = workpieceInfo.z_dir.x;
rotMatrix.at(1, 2) = workpieceInfo.z_dir.y;
rotMatrix.at(2, 2) = workpieceInfo.z_dir.z;
// 2. 将旋转矩阵转换为欧拉角
CTEulerAngles eulerAngles = CCoordinateTransform::rotationMatrixToEuler(rotMatrix, CTEulerOrder::sZYX);
// 3. 构造相机坐标系下的目标位姿
CTCameraPose cameraPose(
workpieceInfo.center.x,
workpieceInfo.center.y,
workpieceInfo.center.z,
eulerAngles.roll,
eulerAngles.pitch,
eulerAngles.yaw
);
// 4. 使用六轴手眼转换Eye-to-Hand模式计算机器人目标位姿
CCoordinateTransform::sixAxisEyeToHandCalcGraspPose(cameraPose, cameraToBase, targetPose);
LOG_DEBUG("ConvertWorkpieceToRobotPoseEyeToHand: Camera(%f, %f, %f, %f, %f, %f) -> Robot(%f, %f, %f, %f, %f, %f)\n",
cameraPose.x, cameraPose.y, cameraPose.z,
cameraPose.rx, cameraPose.ry, cameraPose.rz,
targetPose.x, targetPose.y, targetPose.z,
targetPose.rx, targetPose.ry, targetPose.rz);
}
void WorkpieceHolePresenter::CheckAndUpdateWorkStatus() void WorkpieceHolePresenter::CheckAndUpdateWorkStatus()
{ {
if (m_bCameraConnected) { if (m_bCameraConnected) {

View File

@ -1,6 +1,7 @@
# 1.1.0 # 1.1.0
## build_0 2026-04-28 ## build_0 2026-04-28
1. 更新内存泄露问题 1. 更新算法
2. 更新内存泄露问题
# 1.0.3 # 1.0.3
## build_0 2026-03-24 ## build_0 2026-03-24

View File

@ -42,6 +42,8 @@ INCLUDEPATH += $$PWD/../../../Module/AuthModule/Inc
# 坐标变换库 # 坐标变换库
INCLUDEPATH += $$PWD/../../../Utils/DataUtils/CoordinateTransform/Inc INCLUDEPATH += $$PWD/../../../Utils/DataUtils/CoordinateTransform/Inc
# 手眼标定模块
INCLUDEPATH += $$PWD/../../../Module/HandEyeCalib/Inc
# eigen 依赖 # eigen 依赖
INCLUDEPATH += $$PWD/../../../SDK/eigen-3.3.9 INCLUDEPATH += $$PWD/../../../SDK/eigen-3.3.9
@ -110,6 +112,7 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../../../VrNets/debug -lVrModbus LIBS += -L../../../VrNets/debug -lVrModbus
LIBS += -L../../../VrNets/debug -lVrTcpServer LIBS += -L../../../VrNets/debug -lVrTcpServer
LIBS += -L../../../Utils/DataUtils/CoordinateTransform/debug -lCoordinateTransformd LIBS += -L../../../Utils/DataUtils/CoordinateTransform/debug -lCoordinateTransformd
LIBS += -L../../../Module/HandEyeCalib/debug -lHandEyeCalib
}else:win32:CONFIG(release, debug|release){ }else:win32:CONFIG(release, debug|release){
LIBS += -L../../../Utils/VrUtils/release -lVrUtils LIBS += -L../../../Utils/VrUtils/release -lVrUtils
@ -126,6 +129,7 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../../../VrNets/release -lVrModbus LIBS += -L../../../VrNets/release -lVrModbus
LIBS += -L../../../VrNets/release -lVrTcpServer LIBS += -L../../../VrNets/release -lVrTcpServer
LIBS += -L../../../Utils/DataUtils/CoordinateTransform/release -lCoordinateTransform LIBS += -L../../../Utils/DataUtils/CoordinateTransform/release -lCoordinateTransform
LIBS += -L../../../Module/HandEyeCalib/release -lHandEyeCalib
}else:unix:!macx { }else:unix:!macx {
# Unix/Linux平台库链接(包括交叉编译) # Unix/Linux平台库链接(包括交叉编译)
# 注意链接顺序:依赖关系从高到低(被依赖的库放在后面) # 注意链接顺序:依赖关系从高到低(被依赖的库放在后面)
@ -143,6 +147,7 @@ win32:CONFIG(debug, debug|release) {
LIBS += -L../../../VrNets -lVrTcpServer LIBS += -L../../../VrNets -lVrTcpServer
LIBS += -L../../../Utils/VrUtils -lVrUtils LIBS += -L../../../Utils/VrUtils -lVrUtils
LIBS += -L../../../Utils/DataUtils/CoordinateTransform -lCoordinateTransform LIBS += -L../../../Utils/DataUtils/CoordinateTransform -lCoordinateTransform
LIBS += -L../../../Module/HandEyeCalib -lHandEyeCalib
# 添加系统库依赖 # 添加系统库依赖
LIBS += -lpthread LIBS += -lpthread

View File

@ -953,6 +953,19 @@ QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="QPushButton" name="btn_camer_cancel"> <widget class="QPushButton" name="btn_camer_cancel">
<property name="minimumSize"> <property name="minimumSize">

View File

@ -39,6 +39,13 @@ typedef struct
SWD3DPoint point; SWD3DPoint point;
}SWDIndexing3DPoint; }SWDIndexing3DPoint;
typedef struct
{
int lineIdx;
int ptIdx;
SVzNL3DPoint point;
}SWDIndexingVzPoint;
typedef struct typedef struct
{ {
int start; int start;
@ -604,6 +611,7 @@ typedef struct
double backwardDiffZ; double backwardDiffZ;
double pre_stepDist; double pre_stepDist;
double post_stepDist; double post_stepDist;
double curr_z;
double forward_z; double forward_z;
double backward_z; double backward_z;
}SSG_pntDirAngle; }SSG_pntDirAngle;

View File

@ -32,6 +32,10 @@
//汽车轮眉高度测量 //汽车轮眉高度测量
#define SX_ERR_INVALID_ARC -2301 #define SX_ERR_INVALID_ARC -2301
#define SX_ERR_INVALID_WHEEL_EDGE -2302
#define SX_ERR_NO_WHEEL_COMMON_EDGE -2303
#define SX_ERR_NO_WHEEL_ARC -2304
//糖袋子拆线 //糖袋子拆线
#define SX_ERR_NO_MARK -2401 #define SX_ERR_NO_MARK -2401

View File

@ -29,6 +29,9 @@
<string notr="true">background-color: rgb(25, 26, 28);</string> <string notr="true">background-color: rgb(25, 26, 28);</string>
</property> </property>
<layout class="QVBoxLayout" name="mainLayout"> <layout class="QVBoxLayout" name="mainLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>40</number> <number>40</number>
</property> </property>
@ -41,15 +44,11 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>25</number> <number>25</number>
</property> </property>
<property name="spacing">
<number>6</number>
</property>
<item> <item>
<widget class="QLabel" name="labelAppName"> <widget class="QLabel" name="labelAppName">
<property name="font"> <property name="font">
<font> <font>
<pointsize>22</pointsize> <pointsize>22</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
@ -82,22 +81,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="spacerAfterVersion">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="Line" name="line"> <widget class="Line" name="line">
<property name="styleSheet"> <property name="styleSheet">
@ -109,32 +92,13 @@
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="spacerAfterLine"> <layout class="QGridLayout" name="infoGrid" columnstretch="0,0">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="infoGrid">
<property name="horizontalSpacing"> <property name="horizontalSpacing">
<number>16</number> <number>16</number>
</property> </property>
<property name="verticalSpacing"> <property name="verticalSpacing">
<number>12</number> <number>12</number>
</property> </property>
<property name="columnStretch" stdset="0">
<string>1,4</string>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="labelMachineCodeTitle"> <widget class="QLabel" name="labelMachineCodeTitle">
<property name="font"> <property name="font">
@ -149,7 +113,7 @@
<string>机器码</string> <string>机器码</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -185,7 +149,7 @@
<string>CPU序列号</string> <string>CPU序列号</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -221,7 +185,7 @@
<string>硬盘序列号</string> <string>硬盘序列号</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -257,7 +221,7 @@
<string>算法版本</string> <string>算法版本</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -301,6 +265,12 @@
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer> </spacer>
</item> </item>
<item> <item>
@ -331,6 +301,12 @@ border-radius: 4px;</string>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer> </spacer>
</item> </item>
</layout> </layout>

View File

@ -392,6 +392,22 @@ struct HECCalibResult
HECCalibResult() = default; HECCalibResult() = default;
/**
* @brief 4x4齐次变换矩阵double[16]
* R(3x3)T(3x1)
*/
static HECCalibResult fromHomogeneousArray(const double matrix[16])
{
HECCalibResult result;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
result.R.at(i, j) = matrix[i * 4 + j];
}
result.T.at(i) = matrix[i * 4 + 3];
}
return result;
}
// 转换为齐次变换矩阵 // 转换为齐次变换矩阵
HECHomogeneousMatrix toHomogeneousMatrix() const HECHomogeneousMatrix toHomogeneousMatrix() const
{ {