219 lines
7.0 KiB
C++
219 lines
7.0 KiB
C++
#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; // 目标点补偿偏移 X(mm),Robot 坐标系
|
||
double offsetY = 0.0; // 目标点补偿偏移 Y(mm)
|
||
double offsetZ = 0.0; // 目标点补偿偏移 Z(mm)
|
||
};
|
||
|
||
/**
|
||
* @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
|