工件孔更新算法,斜着角度不对的问题

This commit is contained in:
YangSn 2026-07-17 00:36:59 +08:00
parent 9926c9907e
commit b15533e36e
19 changed files with 205 additions and 59 deletions

View File

@ -5,8 +5,8 @@
#define WORKPIECEHOLE_APP_NAME "工件孔定位" #define WORKPIECEHOLE_APP_NAME "工件孔定位"
// 版本字符串 // 版本字符串
#define WORKPIECEHOLE_VERSION_STRING "1.2.2" #define WORKPIECEHOLE_VERSION_STRING "1.2.3"
#define WORKPIECEHOLE_BUILD_STRING "2" #define WORKPIECEHOLE_BUILD_STRING "1"
#define WORKPIECEHOLE_FULL_VERSION_STRING "V" WORKPIECEHOLE_VERSION_STRING "_" WORKPIECEHOLE_BUILD_STRING #define WORKPIECEHOLE_FULL_VERSION_STRING "V" WORKPIECEHOLE_VERSION_STRING "_" WORKPIECEHOLE_BUILD_STRING
// 构建日期 // 构建日期

View File

@ -1,5 +1,13 @@
# 1.2.3
## build_1 2026-07-16
1. 更新算法 工件45歇着的情况
# 1.2.2 # 1.2.2
## build_1 2026-07-14 ## build_2 2026-07-16
1. 重新调整了工件序号
2. 增加正反工件的识别
## build_1 2026-07-16
1. 工件3和工件5 反了。 1. 工件3和工件5 反了。
2. 每个工件有独立的工具参数调整 2. 每个工件有独立的工具参数调整

View File

@ -114,14 +114,6 @@ typedef struct
int idx; int idx;
}SSG_intPair; }SSG_intPair;
typedef struct
{
int data_0;
int data_1;
double value1;
double value2;
}SSG_intPairRelationD;
typedef struct typedef struct
{ {
int flag; int flag;

View File

@ -978,12 +978,17 @@ void _XOYprojection(
int px1 = (int)((x1 - x_range.min) / scale + sideWidth); int px1 = (int)((x1 - x_range.min) / scale + sideWidth);
int py1 = (int)((y1 - y_range.min) / scale + sideWidth); int py1 = (int)((y1 - y_range.min) / scale + sideWidth);
//x轴 //x轴
double mx2 = a_hole.center.x - dirAngleLen * a_hole.x_dir.x;
double my2 = a_hole.center.y - dirAngleLen * a_hole.x_dir.y;
int mpx2 = (int)((mx2 - x_range.min) / scale + sideWidth);
int mpy2 = (int)((my2 - y_range.min) / scale + sideWidth);
double x2 = a_hole.center.x + dirAngleLen * a_hole.x_dir.x; double x2 = a_hole.center.x + dirAngleLen * a_hole.x_dir.x;
double y2 = a_hole.center.y + dirAngleLen * a_hole.x_dir.y; double y2 = a_hole.center.y + dirAngleLen * a_hole.x_dir.y;
int px2 = (int)((x2 - x_range.min) / scale + sideWidth); int px2 = (int)((x2 - x_range.min) / scale + sideWidth);
int py2 = (int)((y2 - y_range.min) / scale + sideWidth); int py2 = (int)((y2 - y_range.min) / scale + sideWidth);
rgb = { 255, 0, 0 }; //x轴用红色 rgb = { 255, 0, 0 }; //x轴用红色
cv::line(img, cv::Point(px1, py1), cv::Point(px2, py2), cv::Scalar(rgb[2], rgb[1], rgb[0]), 1); cv::line(img, cv::Point(mpx2, mpy2), cv::Point(px2, py2), cv::Scalar(rgb[2], rgb[1], rgb[0]), 1);
//y轴 //y轴
x2 = a_hole.center.x + dirAngleLen * a_hole.y_dir.x; x2 = a_hole.center.x + dirAngleLen * a_hole.y_dir.x;
y2 = a_hole.center.y + dirAngleLen * a_hole.y_dir.y; y2 = a_hole.center.y + dirAngleLen * a_hole.y_dir.y;
@ -1557,24 +1562,25 @@ void TuoPuFa_holePosition_test2(void)
#endif #endif
} }
#define TPF3_TEST_GROUP 7 #define TPF3_TEST_GROUP 8
//拓普发工件孔定位(工件定位) //拓普发工件孔定位(工件定位)
void TuoPuFa_holePosition_test3(void) void TuoPuFa_holePosition_test4(void)
{ {
const char* dataPath[TPF3_TEST_GROUP] = { const char* dataPath[TPF3_TEST_GROUP] = {
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/1层/", //0 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/1层/", //0
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/2层/", //1 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/2层/", //1
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/3层/", //2 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/3层/", //2
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/4层/", //3 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/4层/", //3
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/5层/", //4 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/5层/", //4
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/6层/", //5 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/6层/", //5
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/7层/", //6 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/7层/", //6
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/B10歪/", //7
}; };
SVzNLRange fileIdx[TPF3_TEST_GROUP] = { SVzNLRange fileIdx[TPF3_TEST_GROUP] = {
{1,11}, {1, 10}, {1,10}, {1,10}, {1, 10}, {1,11}, {1, 10}, {1,10}, {1,10}, {1, 10},
{1,10}, {1, 10}, {1,10}, {1, 10}, {1, 10},
}; };
const char* ver = wd_workpieceHolePositioningVersion(); const char* ver = wd_workpieceHolePositioningVersion();
@ -1617,7 +1623,7 @@ void TuoPuFa_holePosition_test3(void)
#endif #endif
#if TEST_COMPUTE_HOLE #if TEST_COMPUTE_HOLE
for (int grp = 0; grp < TPF3_TEST_GROUP; grp++) for (int grp = 7; grp < TPF3_TEST_GROUP; grp++)
{ {
SSG_planeCalibPara groundCalibPara; SSG_planeCalibPara groundCalibPara;
//初始化成单位阵 //初始化成单位阵
@ -1701,7 +1707,7 @@ void TuoPuFa_holePosition_test3(void)
sprintf_s(calibFile, "%sresult/LaserLine%d_holes_projection.png", dataPath[grp], fidx); sprintf_s(calibFile, "%sresult/LaserLine%d_holes_projection.png", dataPath[grp], fidx);
double rpy[3] = { -30, 15, 0 }; //{ 0,-45, 0 }; // double rpy[3] = { -30, 15, 0 }; //{ 0,-45, 0 }; //
double angleDrawLen = 15; double angleDrawLen = 30;
double displayScale = 0.3; double displayScale = 0.3;
cv::String imgName(calibFile); cv::String imgName(calibFile);
_genXOYProjectionImage(imgName, scanLines, displayScale, workpiecePositioning, rpy, angleDrawLen); _genXOYProjectionImage(imgName, scanLines, displayScale, workpiecePositioning, rpy, angleDrawLen);
@ -1710,25 +1716,26 @@ void TuoPuFa_holePosition_test3(void)
} }
#endif #endif
} }
#define TPF4_TEST_GROUP 7 #define TPF4_TEST_GROUP 8
//拓普发工件孔定位(工件定位) //拓普发工件孔定位(工件定位)
void TuoPuFa_holePosition_test4(void) void TuoPuFa_holePosition_test5(void)
{ {
const char* dataPath[TPF4_TEST_GROUP] = { const char* dataPath[TPF4_TEST_GROUP] = {
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/1层/", //0 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/1层/", //0
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/2层/", //1 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/2层/", //1
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/3层/", //2 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/3层/", //2
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/4层/", //3 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/4层/", //3
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/5层/", //4 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/5层/", //4
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/6层/", //5 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/6层/", //5
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件4/7层/", //6 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/7层/", //6
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/B20歪/", //7
}; };
SVzNLRange fileIdx[TPF4_TEST_GROUP] = { SVzNLRange fileIdx[TPF4_TEST_GROUP] = {
{1,11}, {1, 11}, {1,11}, {1,10}, {1, 10}, {1,11}, {1, 11}, {1,11}, {1,10}, {1, 10},
{1,10}, {1, 10}, {1,10}, {1, 10}, {1, 10},
}; };
const char* ver = wd_workpieceHolePositioningVersion(); const char* ver = wd_workpieceHolePositioningVersion();
@ -1771,7 +1778,7 @@ void TuoPuFa_holePosition_test4(void)
#endif #endif
#if TEST_COMPUTE_HOLE #if TEST_COMPUTE_HOLE
for (int grp = 0; grp < TPF4_TEST_GROUP; grp++) for (int grp = 7; grp < TPF4_TEST_GROUP; grp++)
{ {
SSG_planeCalibPara groundCalibPara; SSG_planeCalibPara groundCalibPara;
//初始化成单位阵 //初始化成单位阵
@ -1855,7 +1862,7 @@ void TuoPuFa_holePosition_test4(void)
sprintf_s(calibFile, "%sresult/LaserLine%d_holes_projection.png", dataPath[grp], fidx); sprintf_s(calibFile, "%sresult/LaserLine%d_holes_projection.png", dataPath[grp], fidx);
double rpy[3] = { -30, 15, 0 }; //{ 0,-45, 0 }; // double rpy[3] = { -30, 15, 0 }; //{ 0,-45, 0 }; //
double angleDrawLen = 15; double angleDrawLen = 30;
double displayScale = 0.3; double displayScale = 0.3;
cv::String imgName(calibFile); cv::String imgName(calibFile);
_genXOYProjectionImage(imgName, scanLines, displayScale, workpiecePositioning, rpy, angleDrawLen); _genXOYProjectionImage(imgName, scanLines, displayScale, workpiecePositioning, rpy, angleDrawLen);
@ -1867,28 +1874,28 @@ void TuoPuFa_holePosition_test4(void)
#define TPF5_TEST_GROUP 14 #define TPF5_TEST_GROUP 14
//拓普发工件孔定位(工件定位) //拓普发工件孔定位(工件定位)
void TuoPuFa_holePosition_test5(void) void TuoPuFa_holePosition_test3(void)
{ {
const char* dataPath[TPF5_TEST_GROUP] = { const char* dataPath[TPF5_TEST_GROUP] = {
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/1层/", //0 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/1层/", //0
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/2层/", //1 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/2层/", //1
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/3层/", //2 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/3层/", //2
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/4层/", //3 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/4层/", //3
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/5层/", //4 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/5层/", //4
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/6层/", //5 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/6层/", //5
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/7层/", //6 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/7层/", //6
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/8层/", //7 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/8层/", //7
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/9层/", //8 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/9层/", //8
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/10层/", //9 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/10层/", //9
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/11层/", //10 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/11层/", //10
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/12层/", //11 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/12层/", //11
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/13层/", //12 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/13层/", //12
"F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件5/14层/", //13 "F:/ShangGu/项目/冠钦项目/拓普发工件孔定位/工件3/14层/", //13
}; };
SVzNLRange fileIdx[TPF5_TEST_GROUP] = { SVzNLRange fileIdx[TPF5_TEST_GROUP] = {
{1,10}, {1, 10}, {1,10}, {1,10}, {1, 10}, {1,12}, {1, 10}, {1,10}, {1,10}, {1, 10},
{1,11}, {1, 10}, {1,11}, {1,10}, {1,10}, {1,11}, {1, 10}, {1,11}, {1,10}, {1,10},
{1, 10}, {1,10}, {1,11}, {1,10} {1, 10}, {1,10}, {1,11}, {1,10}
}; };
@ -2742,9 +2749,9 @@ int main()
{ {
//TuoPuFa_holePosition_test(); //TuoPuFa_holePosition_test();
//TuoPuFa_holePosition_test2(); //TuoPuFa_holePosition_test2();
TuoPuFa_holePosition_test3(); //TuoPuFa_holePosition_test3();
TuoPuFa_holePosition_test4(); TuoPuFa_holePosition_test4();
//TuoPuFa_holePosition_test5(); TuoPuFa_holePosition_test5();
} }
else if (keSG_华航孔定位 == testMode) else if (keSG_华航孔定位 == testMode)
HuaHang_holePosition_test(); HuaHang_holePosition_test();

View File

@ -29,10 +29,12 @@ namespace ConfigXmlUtils
* @param root XML * @param root XML
* @param list * @param list
* @param defaultEulerOrder XML eulerOrder 使 * @param defaultEulerOrder XML eulerOrder 使
* @param defaultCalibType XML calibType 使0=1=
*/ */
void LoadHandEyeCalibMatrixs(tinyxml2::XMLElement* root, void LoadHandEyeCalibMatrixs(tinyxml2::XMLElement* root,
std::vector<VrHandEyeCalibMatrix>& list, std::vector<VrHandEyeCalibMatrix>& list,
int defaultEulerOrder = 11); int defaultEulerOrder = 11,
int defaultCalibType = 0);
/** /**
* @brief XML <HandEyeCalibMatrixs> * @brief XML <HandEyeCalibMatrixs>

View File

@ -16,6 +16,7 @@
struct VrHandEyeCalibMatrix struct VrHandEyeCalibMatrix
{ {
int cameraIndex; int cameraIndex;
int calibType; // 0=眼在手外1=眼在手上
double matrix[16]; double matrix[16];
int eulerOrder; int eulerOrder;
double rotX; double rotX;
@ -35,6 +36,7 @@ struct VrHandEyeCalibMatrix
VrHandEyeCalibMatrix() VrHandEyeCalibMatrix()
: cameraIndex(1) : cameraIndex(1)
, calibType(0)
, eulerOrder(11) , eulerOrder(11)
, rotX(0.0) , rotX(0.0)
, rotY(0.0) , rotY(0.0)

View File

@ -12,11 +12,22 @@ namespace ConfigXmlUtils
static void LoadSingleHandEyeCalibMatrix(XMLElement* handEyeElement, static void LoadSingleHandEyeCalibMatrix(XMLElement* handEyeElement,
VrHandEyeCalibMatrix& calibMatrix, VrHandEyeCalibMatrix& calibMatrix,
int defaultEulerOrder) int defaultEulerOrder,
int defaultCalibType)
{ {
if (handEyeElement->Attribute("cameraIndex")) if (handEyeElement->Attribute("cameraIndex"))
calibMatrix.cameraIndex = handEyeElement->IntAttribute("cameraIndex"); calibMatrix.cameraIndex = handEyeElement->IntAttribute("cameraIndex");
const int fallbackCalibType = defaultCalibType == 1 ? 1 : 0;
if (handEyeElement->Attribute("calibType")) {
const int calibType = handEyeElement->IntAttribute("calibType");
calibMatrix.calibType = (calibType == 0 || calibType == 1)
? calibType
: fallbackCalibType;
} else {
calibMatrix.calibType = fallbackCalibType;
}
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
char attrName[32]; char attrName[32];
@ -60,7 +71,8 @@ static void LoadSingleHandEyeCalibMatrix(XMLElement* handEyeElement,
void LoadHandEyeCalibMatrixs(XMLElement* root, void LoadHandEyeCalibMatrixs(XMLElement* root,
std::vector<VrHandEyeCalibMatrix>& list, std::vector<VrHandEyeCalibMatrix>& list,
int defaultEulerOrder) int defaultEulerOrder,
int defaultCalibType)
{ {
// 优先找 <HandEyeCalibMatrixs> // 优先找 <HandEyeCalibMatrixs>
XMLElement* containerElement = root->FirstChildElement("HandEyeCalibMatrixs"); XMLElement* containerElement = root->FirstChildElement("HandEyeCalibMatrixs");
@ -76,7 +88,8 @@ void LoadHandEyeCalibMatrixs(XMLElement* root,
{ {
VrHandEyeCalibMatrix calibMatrix; VrHandEyeCalibMatrix calibMatrix;
calibMatrix.cameraIndex = static_cast<int>(list.size()) + 1; // 默认递增 calibMatrix.cameraIndex = static_cast<int>(list.size()) + 1; // 默认递增
LoadSingleHandEyeCalibMatrix(handEyeElement, calibMatrix, defaultEulerOrder); LoadSingleHandEyeCalibMatrix(handEyeElement, calibMatrix,
defaultEulerOrder, defaultCalibType);
list.push_back(calibMatrix); list.push_back(calibMatrix);
handEyeElement = handEyeElement->NextSiblingElement("HandEyeCalibMatrix"); handEyeElement = handEyeElement->NextSiblingElement("HandEyeCalibMatrix");
} }
@ -89,7 +102,8 @@ void LoadHandEyeCalibMatrixs(XMLElement* root,
{ {
VrHandEyeCalibMatrix calibMatrix; VrHandEyeCalibMatrix calibMatrix;
calibMatrix.cameraIndex = 1; calibMatrix.cameraIndex = 1;
LoadSingleHandEyeCalibMatrix(handEyeElement, calibMatrix, defaultEulerOrder); LoadSingleHandEyeCalibMatrix(handEyeElement, calibMatrix,
defaultEulerOrder, defaultCalibType);
list.push_back(calibMatrix); list.push_back(calibMatrix);
} }
} }
@ -104,6 +118,7 @@ void SaveHandEyeCalibMatrixs(XMLDocument& doc,
{ {
XMLElement* handEyeElement = doc.NewElement("HandEyeCalibMatrix"); XMLElement* handEyeElement = doc.NewElement("HandEyeCalibMatrix");
handEyeElement->SetAttribute("cameraIndex", calibMatrix.cameraIndex); handEyeElement->SetAttribute("cameraIndex", calibMatrix.cameraIndex);
handEyeElement->SetAttribute("calibType", calibMatrix.calibType);
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
char attrName[32]; char attrName[32];

View File

@ -57,6 +57,26 @@ padding: 2px;</string>
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutCalibType">
<item>
<widget class="QLabel" name="labelCalibType">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>标定方式:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboCalibType"/>
</item>
</layout>
</item>
<item> <item>
<widget class="QLabel" name="labelStatus"> <widget class="QLabel" name="labelStatus">
<property name="text"> <property name="text">

View File

@ -30,6 +30,7 @@ struct HandEyeCalibCameraInfo
struct HandEyeCalibData struct HandEyeCalibData
{ {
int cameraIndex = 0; int cameraIndex = 0;
int calibType = 0; // 0=眼在手外1=眼在手上
double matrix[16] = { double matrix[16] = {
1.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, 1.0, 0.0, 0.0,
@ -72,6 +73,23 @@ public:
*/ */
void setCalibData(int cameraIndex, const double matrix[16], bool isCalibrated); void setCalibData(int cameraIndex, const double matrix[16], bool isCalibrated);
/**
* @brief 使
* @param calibType 0=1=
*/
void setDefaultCalibType(int calibType);
/**
* @brief
*/
void setCalibType(int cameraIndex, int calibType);
/**
* @brief
* @return
*/
bool getCalibType(int cameraIndex, int& outCalibType) const;
/** /**
* @brief * @brief
*/ */
@ -165,6 +183,7 @@ signals:
private slots: private slots:
void onCameraSelectionChanged(int index); void onCameraSelectionChanged(int index);
void onCalibTypeChanged(int index);
void onLoadCalibMatrixClicked(); void onLoadCalibMatrixClicked();
void onSaveCalibMatrixClicked(); void onSaveCalibMatrixClicked();
@ -174,6 +193,7 @@ private:
void clearMatrix(); void clearMatrix();
void displayIdentityMatrix(); void displayIdentityMatrix();
void updateCalibStatus(bool isCalibrated); void updateCalibStatus(bool isCalibrated);
void updateCalibType(int calibType);
// 从矩阵编辑框读取当前矩阵值 // 从矩阵编辑框读取当前矩阵值
bool readMatrixFromUI(double outMatrix[16]) const; bool readMatrixFromUI(double outMatrix[16]) const;
@ -187,6 +207,7 @@ private:
Ui::HandEyeCalibWidget* ui = nullptr; Ui::HandEyeCalibWidget* ui = nullptr;
QComboBox* m_comboCamera; QComboBox* m_comboCamera;
QComboBox* m_comboCalibType;
QLabel* m_labelStatus; QLabel* m_labelStatus;
QLineEdit* m_matrixEdits[4][4]; // 4x4 矩阵编辑框 QLineEdit* m_matrixEdits[4][4]; // 4x4 矩阵编辑框
QPushButton* m_btnLoad; QPushButton* m_btnLoad;
@ -195,6 +216,7 @@ private:
QVector<HandEyeCalibData> m_calibDataCache; // 按相机索引缓存 QVector<HandEyeCalibData> m_calibDataCache; // 按相机索引缓存
QString m_defaultFilePath; QString m_defaultFilePath;
bool m_matrixEditable; bool m_matrixEditable;
int m_defaultCalibType;
}; };
#endif // HANDEYECALIBWIDGET_H #endif // HANDEYECALIBWIDGET_H

View File

@ -12,10 +12,12 @@ HandEyeCalibWidget::HandEyeCalibWidget(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::HandEyeCalibWidget) , ui(new Ui::HandEyeCalibWidget)
, m_comboCamera(nullptr) , m_comboCamera(nullptr)
, m_comboCalibType(nullptr)
, m_labelStatus(nullptr) , m_labelStatus(nullptr)
, m_btnLoad(nullptr) , m_btnLoad(nullptr)
, m_btnSave(nullptr) , m_btnSave(nullptr)
, m_matrixEditable(false) , m_matrixEditable(false)
, m_defaultCalibType(0)
{ {
memset(m_matrixEdits, 0, sizeof(m_matrixEdits)); memset(m_matrixEdits, 0, sizeof(m_matrixEdits));
setupUI(); setupUI();
@ -62,6 +64,38 @@ void HandEyeCalibWidget::setCalibData(int cameraIndex, const double matrix[16],
} }
} }
void HandEyeCalibWidget::setDefaultCalibType(int calibType)
{
m_defaultCalibType = (calibType == 1) ? 1 : 0;
const int cameraIndex = currentCameraIndex();
const HandEyeCalibData* data = findCalibData(cameraIndex);
if (!data) {
updateCalibType(m_defaultCalibType);
}
}
void HandEyeCalibWidget::setCalibType(int cameraIndex, int calibType)
{
HandEyeCalibData& data = ensureCalibData(cameraIndex);
data.calibType = (calibType == 1) ? 1 : 0;
if (currentCameraIndex() == cameraIndex) {
updateCalibType(data.calibType);
}
}
bool HandEyeCalibWidget::getCalibType(int cameraIndex, int& outCalibType) const
{
const HandEyeCalibData* data = findCalibData(cameraIndex);
if (!data) {
return false;
}
outCalibType = data->calibType;
return true;
}
void HandEyeCalibWidget::setExtrinsicData(int cameraIndex, int eulerOrder, void HandEyeCalibWidget::setExtrinsicData(int cameraIndex, int eulerOrder,
double rotX, double rotY, double rotZ) double rotX, double rotY, double rotZ)
{ {
@ -214,13 +248,16 @@ void HandEyeCalibWidget::onCameraSelectionChanged(int index)
if (index < 0 || !m_comboCamera || m_comboCamera->count() == 0) { if (index < 0 || !m_comboCamera || m_comboCamera->count() == 0) {
m_btnLoad->setEnabled(false); m_btnLoad->setEnabled(false);
m_btnSave->setEnabled(false); m_btnSave->setEnabled(false);
m_comboCalibType->setEnabled(false);
displayIdentityMatrix(); displayIdentityMatrix();
updateCalibStatus(false); updateCalibStatus(false);
updateCalibType(m_defaultCalibType);
return; return;
} }
m_btnLoad->setEnabled(true); m_btnLoad->setEnabled(true);
m_btnSave->setEnabled(true); m_btnSave->setEnabled(true);
m_comboCalibType->setEnabled(true);
int camIdx = m_comboCamera->itemData(index).toInt(); int camIdx = m_comboCamera->itemData(index).toInt();
const HandEyeCalibData* data = findCalibData(camIdx); const HandEyeCalibData* data = findCalibData(camIdx);
@ -231,7 +268,22 @@ void HandEyeCalibWidget::onCameraSelectionChanged(int index)
displayIdentityMatrix(); displayIdentityMatrix();
updateCalibStatus(false); updateCalibStatus(false);
} }
updateCalibType(data ? data->calibType : m_defaultCalibType);
}
void HandEyeCalibWidget::onCalibTypeChanged(int index)
{
if (index < 0 || !m_comboCalibType) {
return;
}
const int cameraIndex = currentCameraIndex();
if (cameraIndex < 0) {
return;
}
HandEyeCalibData& data = ensureCalibData(cameraIndex);
data.calibType = (m_comboCalibType->itemData(index).toInt() == 1) ? 1 : 0;
} }
void HandEyeCalibWidget::onLoadCalibMatrixClicked() void HandEyeCalibWidget::onLoadCalibMatrixClicked()
@ -254,6 +306,11 @@ void HandEyeCalibWidget::onLoadCalibMatrixClicked()
settings.setIniCodec("UTF-8"); settings.setIniCodec("UTF-8");
settings.beginGroup("CalibMatrixInfo_0"); settings.beginGroup("CalibMatrixInfo_0");
int calibType = settings.value("eCalibType", m_defaultCalibType).toInt();
if (calibType != 0 && calibType != 1) {
calibType = m_defaultCalibType;
}
double matrix[16]; double matrix[16];
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
int row = i / 4; int row = i / 4;
@ -264,6 +321,7 @@ void HandEyeCalibWidget::onLoadCalibMatrixClicked()
settings.endGroup(); settings.endGroup();
setCalibData(camIdx, matrix, true); setCalibData(camIdx, matrix, true);
setCalibType(camIdx, calibType);
emit calibMatrixLoaded(camIdx, matrix); emit calibMatrixLoaded(camIdx, matrix);
} }
@ -322,10 +380,15 @@ void HandEyeCalibWidget::setupUI()
matrixFont.setPointSize(16); matrixFont.setPointSize(16);
m_comboCamera = ui->comboCamera; m_comboCamera = ui->comboCamera;
m_comboCalibType = ui->comboCalibType;
m_labelStatus = ui->labelStatus; m_labelStatus = ui->labelStatus;
m_btnLoad = ui->btnLoad; m_btnLoad = ui->btnLoad;
m_btnSave = ui->btnSave; m_btnSave = ui->btnSave;
m_comboCalibType->addItem(QStringLiteral("眼在手外"), 0);
m_comboCalibType->addItem(QStringLiteral("眼在手上"), 1);
updateCalibType(m_defaultCalibType);
m_matrixEdits[0][0] = ui->editMatrix00; m_matrixEdits[0][0] = ui->editMatrix00;
m_matrixEdits[0][1] = ui->editMatrix01; m_matrixEdits[0][1] = ui->editMatrix01;
m_matrixEdits[0][2] = ui->editMatrix02; m_matrixEdits[0][2] = ui->editMatrix02;
@ -363,6 +426,8 @@ void HandEyeCalibWidget::setupUI()
connect(m_comboCamera, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), connect(m_comboCamera, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &HandEyeCalibWidget::onCameraSelectionChanged); this, &HandEyeCalibWidget::onCameraSelectionChanged);
connect(m_comboCalibType, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &HandEyeCalibWidget::onCalibTypeChanged);
connect(m_btnLoad, &QPushButton::clicked, connect(m_btnLoad, &QPushButton::clicked,
this, &HandEyeCalibWidget::onLoadCalibMatrixClicked); this, &HandEyeCalibWidget::onLoadCalibMatrixClicked);
connect(m_btnSave, &QPushButton::clicked, connect(m_btnSave, &QPushButton::clicked,
@ -411,6 +476,18 @@ void HandEyeCalibWidget::updateCalibStatus(bool isCalibrated)
} }
} }
void HandEyeCalibWidget::updateCalibType(int calibType)
{
if (!m_comboCalibType) {
return;
}
const int index = m_comboCalibType->findData(calibType == 1 ? 1 : 0);
m_comboCalibType->blockSignals(true);
m_comboCalibType->setCurrentIndex(index);
m_comboCalibType->blockSignals(false);
}
bool HandEyeCalibWidget::readMatrixFromUI(double outMatrix[16]) const bool HandEyeCalibWidget::readMatrixFromUI(double outMatrix[16]) const
{ {
for (int r = 0; r < 4; ++r) { for (int r = 0; r < 4; ++r) {
@ -455,6 +532,7 @@ HandEyeCalibData& HandEyeCalibWidget::ensureCalibData(int cameraIndex)
HandEyeCalibData newData; HandEyeCalibData newData;
newData.cameraIndex = cameraIndex; newData.cameraIndex = cameraIndex;
newData.calibType = m_defaultCalibType;
m_calibDataCache.append(newData); m_calibDataCache.append(newData);
return m_calibDataCache.last(); return m_calibDataCache.last();
} }