GrabBag/AppUtils/UICommon/Inc/HandEyeCalibWidget.h

219 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef HANDEYECALIBWIDGET_H
#define HANDEYECALIBWIDGET_H
#include <QWidget>
#include <QVector>
#include <QString>
#include <QComboBox>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
/**
* @brief 手眼标定相机信息
*/
struct HandEyeCalibCameraInfo
{
int cameraIndex; // 相机索引1-based
QString displayName; // 显示名称
};
/**
* @brief 单个相机的标定数据缓存
*
* eulerOrder 既用作机器人法兰姿态的输入分解约定,
* 也用作工具姿态输出时的欧拉角合成约定;
* rotX/Y/Z 以度为单位,按 Rx*Ry*Rz 顺序对 Eye 坐标系下的工具轴做补偿旋转。
*/
struct HandEyeCalibData
{
int cameraIndex = 0;
double matrix[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
bool isCalibrated = false;
int eulerOrder = 11; // 默认外旋 ZYX
double rotX = 0.0;
double rotY = 0.0;
double rotZ = 0.0;
double approachOffset = 0.0; // 接近点偏移mm沿目标姿态反方向远离目标点
double offsetX = 0.0; // 目标点补偿偏移 XmmRobot 坐标系
double offsetY = 0.0; // 目标点补偿偏移 Ymm
double offsetZ = 0.0; // 目标点补偿偏移 Zmm
};
/**
* @brief 手眼标定共享控件
*
* 纯 QWidget代码构建 UI无 .ui 文件),可嵌入任意 tab/layout。
* 配置无关:不依赖任何 App 的 IVrConfig只操作原始数据。
* 自带 INI 解析:用 QSettings 读取 [CalibMatrixInfo_0] section。
*
* UI 布局:选择相机 ComboBox → 标定状态 Label → 4x4 矩阵 GridLayout → [可选外参区] → 加载/保存按钮
* 外参区setExtrinsicControlsVisible(true) 时出现):欧拉角顺序 + 绕 X/Y/Z 旋转角度。
*/
class HandEyeCalibWidget : public QWidget
{
Q_OBJECT
public:
explicit HandEyeCalibWidget(QWidget *parent = nullptr);
~HandEyeCalibWidget();
/**
* @brief 设置相机列表
*/
void setCameraList(const QVector<HandEyeCalibCameraInfo>& cameras);
/**
* @brief 设置指定相机的标定数据
*/
void setCalibData(int cameraIndex, const double matrix[16], bool isCalibrated);
/**
* @brief 设置指定相机的欧拉角顺序与补偿旋转
*/
void setExtrinsicData(int cameraIndex, int eulerOrder, double rotX, double rotY, double rotZ);
/**
* @brief 设置指定相机的欧拉角顺序、补偿旋转以及接近点偏移
*/
void setExtrinsicData(int cameraIndex, int eulerOrder,
double rotX, double rotY, double rotZ,
double approachOffset);
/**
* @brief 设置指定相机的完整外参(含接近点偏移 + 目标点补偿偏移)
*/
void setExtrinsicData(int cameraIndex, int eulerOrder,
double rotX, double rotY, double rotZ,
double approachOffset,
double offsetX, double offsetY, double offsetZ);
/**
* @brief 获取指定相机的标定数据
* @return 是否存在该相机的数据
*/
bool getCalibData(int cameraIndex, double outMatrix[16], bool& outIsCalibrated) const;
/**
* @brief 获取指定相机的外参(欧拉角顺序 + 轴旋转角度)
* @return 是否存在该相机的数据
*/
bool getExtrinsicData(int cameraIndex, int& outEulerOrder,
double& outRotX, double& outRotY, double& outRotZ) const;
/**
* @brief 获取指定相机的外参(含接近点偏移)
* @return 是否存在该相机的数据
*/
bool getExtrinsicData(int cameraIndex, int& outEulerOrder,
double& outRotX, double& outRotY, double& outRotZ,
double& outApproachOffset) const;
/**
* @brief 获取指定相机的完整外参(含接近点偏移 + 目标点补偿偏移)
*/
bool getExtrinsicData(int cameraIndex, int& outEulerOrder,
double& outRotX, double& outRotY, double& outRotZ,
double& outApproachOffset,
double& outOffsetX, double& outOffsetY, double& outOffsetZ) const;
/**
* @brief 获取当前选中的相机索引
* @return 相机索引,未选择返回 -1
*/
int currentCameraIndex() const;
/**
* @brief 设置默认文件打开路径
*/
void setDefaultFilePath(const QString& path);
/**
* @brief 设置矩阵是否可编辑
*/
void setMatrixEditable(bool editable);
/**
* @brief 显示/隐藏欧拉角顺序与绕 XYZ 旋转补偿的控件
*/
void setExtrinsicControlsVisible(bool visible);
/**
* @brief 显示/隐藏目标点补偿偏移控件(默认隐藏)
*/
void setTargetOffsetVisible(bool visible);
void setApproachOffsetVisible(bool visible);
signals:
/**
* @brief 标定矩阵已从文件加载
* @param cameraIndex 相机索引
* @param matrix 16 个 double 的矩阵
*/
void calibMatrixLoaded(int cameraIndex, const double* matrix);
/**
* @brief 请求保存标定数据
* @param cameraIndex 相机索引
* @param matrix 16 个 double 的矩阵
*/
void saveCalibRequested(int cameraIndex, const double* matrix);
private slots:
void onCameraSelectionChanged(int index);
void onLoadCalibMatrixClicked();
void onSaveCalibMatrixClicked();
private:
void setupUI();
void setupExtrinsicGroup();
void initEulerOrderComboBox();
void displayMatrix(const double* matrix);
void clearMatrix();
void displayIdentityMatrix();
void updateCalibStatus(bool isCalibrated);
void displayExtrinsic(const HandEyeCalibData& data);
void displayDefaultExtrinsic();
// 从矩阵编辑框读取当前矩阵值
bool readMatrixFromUI(double outMatrix[16]) const;
// 从外参编辑框读取当前值并写回缓存
void commitExtrinsicToCache(int cameraIndex);
// 查找缓存中指定相机的数据
HandEyeCalibData* findCalibData(int cameraIndex);
const HandEyeCalibData* findCalibData(int cameraIndex) const;
HandEyeCalibData& ensureCalibData(int cameraIndex);
private:
QComboBox* m_comboCamera;
QLabel* m_labelStatus;
QLineEdit* m_matrixEdits[4][4]; // 4x4 矩阵编辑框
QPushButton* m_btnLoad;
QPushButton* m_btnSave;
QGroupBox* m_groupExtrinsic;
QComboBox* m_comboEulerOrder;
QLineEdit* m_editRotX;
QLineEdit* m_editRotY;
QLineEdit* m_editRotZ;
QLabel* m_labelApproachOffset;
QLineEdit* m_editApproachOffset;
QLabel* m_labelTargetOffset;
QLineEdit* m_editOffsetX;
QLineEdit* m_editOffsetY;
QLineEdit* m_editOffsetZ;
QVector<HandEyeCalibData> m_calibDataCache; // 按相机索引缓存
QString m_defaultFilePath;
bool m_matrixEditable;
};
#endif // HANDEYECALIBWIDGET_H