diff --git a/bagPositioning/bagPositioning.vcxproj b/bagPositioning/bagPositioning.vcxproj index 0f1d019..91190a6 100644 --- a/bagPositioning/bagPositioning.vcxproj +++ b/bagPositioning/bagPositioning.vcxproj @@ -42,13 +42,13 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode diff --git a/rodAndBarDetection_test/rodAndBarDetection_test.cpp b/rodAndBarDetection_test/rodAndBarDetection_test.cpp index 9e9a4de..a067a68 100644 --- a/rodAndBarDetection_test/rodAndBarDetection_test.cpp +++ b/rodAndBarDetection_test/rodAndBarDetection_test.cpp @@ -208,7 +208,7 @@ SSG_planeCalibPara _readCalibPara(char* fileName) } -void _outputChanneltInfo(char* fileName, std::vector& screwInfo) +void _outputChanneltInfo(char* fileName, std::vector& screwInfo) { std::ofstream sw(fileName); @@ -216,14 +216,25 @@ void _outputChanneltInfo(char* fileName, std::vector& scre int objNum = (int)screwInfo.size(); for (int i = 0; i < objNum; i++) { - sprintf_s(dataStr, 250, "螺杆_%d: center_( %g, %g, %g ), dir_( %g, %g, %g ), anlge_%g", + sprintf_s(dataStr, 250, "螺杆_%d: center_( %g, %g, %g ), dir_( %g, %g, %g )", i + 1, screwInfo[i].center.x, screwInfo[i].center.y, screwInfo[i].center.z, - screwInfo[i].axialDir.x, screwInfo[i].axialDir.y, screwInfo[i].axialDir.z, screwInfo[i].rotateAngle); + screwInfo[i].axialDir.x, screwInfo[i].axialDir.y, screwInfo[i].axialDir.z); sw << dataStr << std::endl; } sw.close(); } +void _outputPlatePiseInfo(char* fileName, SSX_pointPoseInfo& centerInfo) +{ + std::ofstream sw(fileName); + char dataStr[250]; + sprintf_s(dataStr, 250, "定位盘: center_( %g, %g, %g ), dir_( %g, %g, %g )", + centerInfo.center.x, centerInfo.center.y, centerInfo.center.z, + centerInfo.normalDir.x, centerInfo.normalDir.y, centerInfo.normalDir.z); + sw << dataStr << std::endl; + sw.close(); +} + void _outputRodtInfo(char* fileName, std::vector& rodInfo) { std::ofstream sw(fileName); @@ -241,10 +252,26 @@ void _outputRodtInfo(char* fileName, std::vector& rodInfo) sw.close(); } +void _outputWeldSeamInfo(char* fileName, std::vector& weldSeamInfo) +{ + std::ofstream sw(fileName); + + char dataStr[250]; + int objNum = (int)weldSeamInfo.size(); + for (int i = 0; i < objNum; i++) + { + sprintf_s(dataStr, 250, "螺杆_%d: center_( %g, %g, %g ), dir_normal_( %g, %g, %g )", + i + 1, weldSeamInfo[i].center.x, weldSeamInfo[i].center.y, weldSeamInfo[i].center.z, + weldSeamInfo[i].normalDir.x, weldSeamInfo[i].normalDir.y, weldSeamInfo[i].normalDir.z); + sw << dataStr << std::endl; + } + sw.close(); +} + void _outputRGBDScan_RGBD( char* fileName, std::vector>& scanLines, - std::vector& screwInfo + std::vector& screwInfo ) { int lineNum = (int)scanLines.size(); @@ -377,6 +404,112 @@ void _outputRGBDScan_RGBD( sw.close(); } +void _outputRGBDScan_RGBD_centerPose( + char* fileName, + std::vector>& scanLines, + SSX_pointPoseInfo& poseInfo +) +{ + int lineNum = (int)scanLines.size(); + std::ofstream sw(fileName); + int realLines = lineNum; + realLines += 1; + + sw << "LineNum:" << realLines << std::endl; + sw << "DataType: 0" << std::endl; + sw << "ScanSpeed: 0" << std::endl; + sw << "PointAdjust: 1" << std::endl; + sw << "MaxTimeStamp: 0_0" << std::endl; + + int maxLineIndex = 0; + int max_stamp = 0; + + SG_color rgb = { 0, 0, 0 }; + + SG_color objColor[8] = { + {245,222,179},//淡黄色 + {210,105, 30},//巧克力色 + {240,230,140},//黄褐色 + {135,206,235},//天蓝色 + {250,235,215},//古董白 + {189,252,201},//薄荷色 + {221,160,221},//梅红色 + {188,143,143},//玫瑰红色 + }; + int size = 1; + int lineIdx = 0; + for (int line = 0; line < lineNum; line++) + { + int linePtNum = (int)scanLines[line].size(); + if (linePtNum == 0) + continue; + + sw << "Line_" << lineIdx << "_0_" << linePtNum << std::endl; + lineIdx++; + for (int i = 0; i < linePtNum; i++) + { + SVzNL3DPosition* pt3D = &scanLines[line][i]; + + if (pt3D->nPointIdx == 2) + { + rgb = { 250, 0, 0 }; + size = 5; + } + //else if (pt3D->nPointIdx == 1) + //{ + // rgb = { 0, 0, 250 }; + // size = 3; + //} + else //if (pt3D->nPointIdx == 0) + { + rgb = { 200, 200, 200 }; + size = 1; + } + float x = (float)pt3D->pt3D.x; + float y = (float)pt3D->pt3D.y; + float z = (float)pt3D->pt3D.z; + sw << "{" << x << "," << y << "," << z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl; + } + } + + { + sw << "Line_" << lineIdx << "_0_1" << std::endl; + rgb = { 250, 0, 0 }; + size = 8; + float x = (float)poseInfo.center.x; + float y = (float)poseInfo.center.y; + float z = (float)poseInfo.center.z; + sw << "{" << x << "," << y << "," << z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl; + + //输出法向 + size = 1; + double len = 60; + lineIdx = 0; + { + SVzNL3DPoint pt0 = { poseInfo.center.x - len * poseInfo.normalDir.x, + poseInfo.center.y - len * poseInfo.normalDir.y, + poseInfo.center.z - len * poseInfo.normalDir.z }; + SVzNL3DPoint pt1 = { poseInfo.center.x + len * poseInfo.normalDir.x, + poseInfo.center.y + len * poseInfo.normalDir.y, + poseInfo.center.z + len * poseInfo.normalDir.z }; + //显示法向量 + sw << "Poly_" << lineIdx << "_2" << std::endl; + sw << "{" << (float)pt0.x << "," << (float)pt0.y << "," << (float)pt0.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + sw << "{" << pt1.x << "," << pt1.y << "," << pt1.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + lineIdx++; + } + } + sw.close(); +} + void _outputRGBDScan_RGBD_rodInfo( char* fileName, std::vector>& scanLines, @@ -511,6 +644,139 @@ void _outputRGBDScan_RGBD_rodInfo( } sw.close(); } + +void _outputRGBDScan_RGBD_weldSeam( + char* fileName, + std::vector>& scanLines, + std::vector& weldSeamInfo +) +{ + int lineNum = (int)scanLines.size(); + std::ofstream sw(fileName); + int realLines = lineNum; + int objNum = (int)weldSeamInfo.size(); + if (objNum > 0) + realLines += 1; + + sw << "LineNum:" << realLines << std::endl; + sw << "DataType: 0" << std::endl; + sw << "ScanSpeed: 0" << std::endl; + sw << "PointAdjust: 1" << std::endl; + sw << "MaxTimeStamp: 0_0" << std::endl; + + int maxLineIndex = 0; + int max_stamp = 0; + + SG_color rgb = { 0, 0, 0 }; + + SG_color objColor[8] = { + {245,222,179},//淡黄色 + {210,105, 30},//巧克力色 + {240,230,140},//黄褐色 + {135,206,235},//天蓝色 + {250,235,215},//古董白 + {189,252,201},//薄荷色 + {221,160,221},//梅红色 + {188,143,143},//玫瑰红色 + }; + int size = 1; + int lineIdx = 0; + for (int line = 0; line < lineNum; line++) + { + int linePtNum = (int)scanLines[line].size(); + if (linePtNum == 0) + continue; + + sw << "Line_" << lineIdx << "_0_" << linePtNum << std::endl; + lineIdx++; + for (int i = 0; i < linePtNum; i++) + { + SVzNL3DPosition* pt3D = &scanLines[line][i]; + if (pt3D->nPointIdx > 0) + { + int centerFlag = pt3D->nPointIdx >> 4; + if (centerFlag > 0) + { + rgb = { 180, 0, 0 }; + size = 2; + } + else + { + rgb = objColor[pt3D->nPointIdx % 8]; + size = 2; + } + + + } + else //if (pt3D->nPointIdx == 0) + { + rgb = { 200, 200, 200 }; + size = 1; + } + float x = (float)pt3D->pt3D.x; + float y = (float)pt3D->pt3D.y; + float z = (float)pt3D->pt3D.z; + sw << "{" << x << "," << y << "," << z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl; + } + } + + if (objNum > 0) + { + sw << "Line_" << lineIdx << "_0_" << objNum << std::endl; + size = 12; + for (int i = 0; i < objNum; i++) + { + if (i == 0) + rgb = { 250, 255, 0 }; + else + rgb = { 250, 0, 0 }; + float x = (float)weldSeamInfo[i].center.x; + float y = (float)weldSeamInfo[i].center.y; + float z = (float)weldSeamInfo[i].center.z; + sw << "{" << x << "," << y << "," << z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl; + } + //输出法向 + size = 8; + double len = 60; + lineIdx = 0; + for (int i = 0; i < objNum; i++) + { + if (i == 0) + rgb = { 250, 255, 0 }; + else + rgb = { 250, 0, 0 }; + SVzNL3DPoint pt0 = { weldSeamInfo[i].center.x, weldSeamInfo[i].center.y, weldSeamInfo[i].center.z }; + SVzNL3DPoint pt2 = { weldSeamInfo[i].center.x + len * weldSeamInfo[i].normalDir.x, + weldSeamInfo[i].center.y + len * weldSeamInfo[i].normalDir.y, + weldSeamInfo[i].center.z + len * weldSeamInfo[i].normalDir.z }; + //显示轴向量 + sw << "Poly_" << lineIdx << "_2" << std::endl; + sw << "{" << (float)weldSeamInfo[i].startPt.x << "," << (float)weldSeamInfo[i].startPt.y << "," << (float)weldSeamInfo[i].startPt.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + sw << "{" << (float)weldSeamInfo[i].endPt.x << "," << (float)weldSeamInfo[i].endPt.y << "," << (float)weldSeamInfo[i].endPt.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + lineIdx++; + //显示法向量 + sw << "Poly_" << lineIdx << "_2" << std::endl; + sw << "{" << (float)pt0.x << "," << (float)pt0.y << "," << (float)pt0.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + sw << "{" << (float)pt2.x << "," << (float)pt2.y << "," << (float)pt2.z << "}-"; + sw << "{0,0}-{0,0}-"; + sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl; + lineIdx++; + } + lineIdx++; + } + sw.close(); +} + #define SCREW_TEST_GROUP 1 void screwTest(void) { @@ -566,7 +832,7 @@ void screwTest(void) bool isHorizonScan = true; //true:激光线平行槽道;false:激光线垂直槽道 int errCode = 0; - std::vector screwInfo; + std::vector screwInfo; sx_hexHeadScrewMeasure( scanLines, isHorizonScan, //true:激光线平行槽道;false:激光线垂直槽道 @@ -588,6 +854,64 @@ void screwTest(void) } } +#define LOCATING_PALTE_TEST_GROUP 1 +void locatingPlateTest(void) +{ + const char* dataPath[SCREW_TEST_GROUP] = { + "F:/ShangGu/项目/冠钦项目/螺杆测量/配天现场点云/定位盘点云/", //0 + }; + + SVzNLRange fileIdx[LOCATING_PALTE_TEST_GROUP] = { + {1,16}, + }; + + const char* ver = wd_rodAndBarDetectionVersion(); + printf("ver:%s\n", ver); + + for (int grp = 0; grp < LOCATING_PALTE_TEST_GROUP; grp++) + { + for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++) + { + //fidx =4; + char _scan_file[256]; + sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[grp], fidx); + + std::vector> scanLines; + wdReadLaserScanPointFromFile_XYZ_vector(_scan_file, scanLines); + + //转成plyTxt格式 + //sprintf_s(_scan_file, "%s%d_ply_Hi229229.txt", dataPath[grp], fidx); + //wdSavePlyTxt(_scan_file, scanLines); + + long t1 = (long)GetTickCount64();//统计时间 + + double rodDiameter = 10.0; + + SSG_cornerParam cornerParam; + cornerParam.cornerTh = 60; //45度角 + cornerParam.scale = rodDiameter / 4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8; + cornerParam.minEndingGap = 20; // algoParam.bagParam.bagW / 4; + cornerParam.minEndingGap_z = 5.0; + cornerParam.jumpCornerTh_1 = 15; //水平角度,小于此角度视为水平 + cornerParam.jumpCornerTh_2 = 60; + + int errCode = 0; + SSX_pointPoseInfo centerPose = sx_getLocationPlatePose( + scanLines, + cornerParam, + & errCode); + + long t2 = (long)GetTickCount64(); + printf("%s: %d(ms)!\n", _scan_file, (int)(t2 - t1)); + //输出测试结果 + sprintf_s(_scan_file, "%sresult\\%d_result.txt", dataPath[grp], fidx); + _outputRGBDScan_RGBD_centerPose(_scan_file, scanLines, centerPose); + sprintf_s(_scan_file, "%sresult\\%d_screw_info.txt", dataPath[grp], fidx); + _outputPlatePiseInfo(_scan_file, centerPose); + } + } +} + #define ROD_POSITION_TEST_GROUP 1 void rodPositionTest(void) { @@ -685,12 +1009,118 @@ void rodPositionTest(void) } } + +#define WELD_SEAM_TEST_GROUP 2 +void rodWeldSeamPosition_test(void) +{ + const char* dataPath[WELD_SEAM_TEST_GROUP] = { + "F:/ShangGu/项目/冠钦项目/筑裕视觉钢结构焊接/视觉照片1/", //0 + "F:/ShangGu/项目/冠钦项目/筑裕视觉钢结构焊接/视觉照片2/", //0 + }; + + SVzNLRange fileIdx[WELD_SEAM_TEST_GROUP] = { + {1,20},{1,20}, + }; + + const char* ver = wd_rodAndBarDetectionVersion(); + printf("ver:%s\n", ver); + + for (int grp = 0; grp < WELD_SEAM_TEST_GROUP; grp++) + { + SSG_planeCalibPara poseCalibPara; + //初始化成单位阵 + poseCalibPara.planeCalib[0] = 1.0; + poseCalibPara.planeCalib[1] = 0.0; + poseCalibPara.planeCalib[2] = 0.0; + poseCalibPara.planeCalib[3] = 0.0; + poseCalibPara.planeCalib[4] = 1.0; + poseCalibPara.planeCalib[5] = 0.0; + poseCalibPara.planeCalib[6] = 0.0; + poseCalibPara.planeCalib[7] = 0.0; + poseCalibPara.planeCalib[8] = 1.0; + poseCalibPara.planeHeight = -1.0; + for (int i = 0; i < 9; i++) + poseCalibPara.invRMatrix[i] = poseCalibPara.planeCalib[i]; + //char calibFile[250]; + //sprintf_s(calibFile, "%sground_calib_para.txt", dataPath[grp]); + //poseCalibPara = _readCalibPara(calibFile); + + for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++) + { + //fidx =1; + char _scan_file[256]; + sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[grp], fidx); + + std::vector> scanLines; + wdReadLaserScanPointFromFile_XYZ_vector(_scan_file, scanLines); + + //转成plyTxt格式 + //sprintf_s(_scan_file, "%s%d_ply_Hi229229.txt", dataPath[grp], fidx); + //wdSavePlyTxt(_scan_file, scanLines); + + long t1 = (long)GetTickCount64();//统计时间 + + SSX_rodParam rodParam; + rodParam.diameter = 52.0; //圆棒直径 + rodParam.len = 290; + + SSG_cornerParam cornerParam; + cornerParam.cornerTh = 60; //45度角 + cornerParam.scale = rodParam.diameter / 4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8; + cornerParam.minEndingGap = 20; // algoParam.bagParam.bagW / 4; + cornerParam.minEndingGap_z = 5.0; + cornerParam.jumpCornerTh_1 = 15; //水平角度,小于此角度视为水平 + cornerParam.jumpCornerTh_2 = 60; + + SSG_outlierFilterParam filterParam; + filterParam.continuityTh = 5.0; //噪声滤除。当相邻点的z跳变大于此门限时,检查是否为噪声。若长度小于outlierLen, 视为噪声 + filterParam.outlierTh = 5; + + SSG_treeGrowParam growParam; + growParam.maxLineSkipNum = 5; + growParam.yDeviation_max = 10.0; + growParam.maxSkipDistance = 10.0; + growParam.zDeviation_max = 10.0;// + growParam.minLTypeTreeLen = 100; //mm, 螺杆长度 + growParam.minVTypeTreeLen = 100; //mm + + bool isHorizonScan = true; //true:激光线平行槽道;false:激光线垂直槽道 + int errCode = 0; + std::vector weldSeamInfo; + sx_rebarWeldSeamPositioning( + scanLines, + poseCalibPara, + cornerParam, + filterParam, + growParam, + rodParam, + weldSeamInfo, + &errCode); + long t2 = (long)GetTickCount64(); + printf("%s: %d(ms)!\n", _scan_file, (int)(t2 - t1)); + //输出测试结果 + sprintf_s(_scan_file, "%sresult\\%d_result.txt", dataPath[grp], fidx); + _outputRGBDScan_RGBD_weldSeam(_scan_file, scanLines, weldSeamInfo); + sprintf_s(_scan_file, "%sresult\\%d_screw_info.txt", dataPath[grp], fidx); + _outputWeldSeamInfo(_scan_file, weldSeamInfo); + } + } +} + int main() { -#if 0 //螺杆定位测试 +#if 1 //螺杆定位测试 +#if 0 screwTest(); +#else + locatingPlateTest(); +#endif #else //棒材抓取定位测试 +#if 0 rodPositionTest(); +#else + rodWeldSeamPosition_test(); +#endif #endif return 0; } diff --git a/sourceCode/SG_baseAlgo_Export.h b/sourceCode/SG_baseAlgo_Export.h index 4cadef3..39fcf0d 100644 --- a/sourceCode/SG_baseAlgo_Export.h +++ b/sourceCode/SG_baseAlgo_Export.h @@ -139,6 +139,14 @@ SG_APISHARED_EXPORT void wd_getLineCornerFeature_PSM( const SSG_cornerParam cornerPara, SSG_lineFeature* line_features); +SG_APISHARED_EXPORT void wd_lineDataSegment_zDist( + std::vector< SVzNL3DPosition>& lineData, + std::vector< SVzNL3DPosition>& vldPts, + std::vector& segs, + std::vector& backIndexing, + const SSG_cornerParam cornerPara +); + SG_APISHARED_EXPORT void wd_computeDirAngle_wholeLine( std::vector< SVzNL3DPosition>& line_data, const SSG_cornerParam cornerPara, @@ -643,8 +651,8 @@ SG_APISHARED_EXPORT void vzCaculateLaserPlane( SG_APISHARED_EXPORT Plane robustFitPlane( const std::vector& points, - RobustType type = TUKEY, - double delta = 0.5, // ֵ>ֵΪȺ㣨mm + RobustType type = HUBER, + double delta = 1.0, // ֵ>ֵΪȺ㣨mm int maxIter = 20, // double convergeThresh = 1e-5 // ֵƽ仯㹻Сͣ ); @@ -740,6 +748,7 @@ SG_APISHARED_EXPORT void wd_pointClustering_speedUp( std::vector< SVzNL3DPosition>& pts, int lineNum, int ptSize, int clusterCheckWin, // double clusterDist, + int distType, //0 - 2d distance; 1- 3d distance std::vector>& objClusters //result ); diff --git a/sourceCode/SG_clustering.cpp b/sourceCode/SG_clustering.cpp index e562a37..d02214e 100644 --- a/sourceCode/SG_clustering.cpp +++ b/sourceCode/SG_clustering.cpp @@ -41,6 +41,7 @@ void _seedClustering_speedUp( std::vector< SVzNL3DPosition>& pts, std::vector& flags, double clusterDist, + int distType, //0 - 2d distance; 1- 3d distance std::vector>& indexing2D, int lineNum, int ptSize, int clusterCheckWin) // { @@ -66,7 +67,11 @@ void _seedClustering_speedUp( continue; if (flags[backIdx] < 0) continue; - double dist = sqrt(pow(a_seed.pt3D.x - pts[backIdx].pt3D.x,2) + pow(a_seed.pt3D.y - pts[backIdx].pt3D.y,2)); + double dist; + if(0 == distType) + dist = sqrt(pow(a_seed.pt3D.x - pts[backIdx].pt3D.x, 2) + pow(a_seed.pt3D.y - pts[backIdx].pt3D.y, 2)); + else + dist = sqrt(pow(a_seed.pt3D.x - pts[backIdx].pt3D.x, 2) + pow(a_seed.pt3D.y - pts[backIdx].pt3D.y, 2) + pow(a_seed.pt3D.z - pts[backIdx].pt3D.z, 2)); if (dist < clusterDist) { a_cluster.push_back(pts[backIdx]); @@ -129,6 +134,7 @@ void wd_pointClustering_speedUp( std::vector< SVzNL3DPosition>& pts, int lineNum, int linePtSize, int clusterCheckWin, // double clusterDist, + int distType, //0 - 2d distance; 1- 3d distance std::vector>& objClusters //result ) { @@ -170,9 +176,11 @@ void wd_pointClustering_speedUp( pts, flags, clusterDist, + distType, indexing2D, lineNum, linePtSize, clusterCheckWin); - objClusters.push_back(a_cluster); //һ + if(a_cluster.size() >= 5) + objClusters.push_back(a_cluster); //һ } idx++; } diff --git a/sourceCode/SG_lineFeature.cpp b/sourceCode/SG_lineFeature.cpp index 267013e..b8abfa0 100644 --- a/sourceCode/SG_lineFeature.cpp +++ b/sourceCode/SG_lineFeature.cpp @@ -3825,7 +3825,7 @@ bool compareByPtIdx(const SSG_basicFeature1D& a, const SSG_basicFeature1D& b) { } //ZԷֶ -void _lineDataSegment_zDist( +void wd_lineDataSegment_zDist( std::vector< SVzNL3DPosition>& lineData, std::vector< SVzNL3DPosition>& vldPts, std::vector& segs, @@ -4089,7 +4089,7 @@ void wd_getRingArcFeature( backIndexing.resize(dataSize); //zԷֶ - _lineDataSegment_zDist(lineData, vldPts, segs, backIndexing, cornerPara); + wd_lineDataSegment_zDist(lineData, vldPts, segs, backIndexing, cornerPara); //ǰǺͺ std::vector< SSG_pntDirAngle> ptDirAngles; _computeDirAngle_perSeg(vldPts, segs, cornerPara, ptDirAngles); diff --git a/sourceCode/rodAndBarDetection.cpp b/sourceCode/rodAndBarDetection.cpp index 9550bef..adb7c48 100644 --- a/sourceCode/rodAndBarDetection.cpp +++ b/sourceCode/rodAndBarDetection.cpp @@ -8,7 +8,8 @@ //version 1.0.0 : base version release to customer //version 1.1.0 : ˵ƽͰĶλ //version 1.1.1 : ʼͻİ汾 -std::string m_strVersion = "1.1.1"; +//version 1.2.0 : ݸ˲˶λIJ +std::string m_strVersion = "1.2.0"; const char* wd_rodAndBarDetectionVersion(void) { return m_strVersion.c_str(); @@ -204,6 +205,7 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9]) return _r_pt; } +//ݸ˶˲ĵλ void sx_hexHeadScrewMeasure( std::vector< std::vector>& scanLines, bool isHorizonScan, //true:ƽв۵false:ߴֱ۵ @@ -211,7 +213,7 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9]) const SSG_outlierFilterParam filterParam, const SSG_treeGrowParam growParam, double rodDiameter, - std::vector& screwInfo, + std::vector& screwInfo, int* errCode) { *errCode = 0; @@ -429,10 +431,9 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9]) //תԭϵ SVzNL3DPoint surfaceCenter = _ptRotate(projectionCenter, rotatePara.invRMatrix); //RodϢ - SSX_hexHeadScrewInfo a_rod; + SSX_rodPoseInfo a_rod; a_rod.center = surfaceCenter; a_rod.axialDir = P1_dir; - a_rod.rotateAngle = 0; screwInfo.push_back(a_rod); } if (true == isHorizonScan) @@ -452,6 +453,402 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9]) return; } +double _getListMeanZ(std::vector< SVzNL3DPosition>& listData) +{ + if (listData.size() == 0) + return 0; + double meanZ = 0; + for (int i = 0; i < (int)listData.size(); i++) + meanZ += listData[i].pt3D.z; + meanZ = meanZ / (double)listData.size(); + return meanZ; +} + +SSG_ROIRectD _getListROI(std::vector< SVzNL3DPosition>& listData) +{ + if (listData.size() == 0) + return { 0,0,0,0 }; + SSG_ROIRectD roi = { listData[0].pt3D.x, listData[0].pt3D.x, listData[0].pt3D.y, listData[0].pt3D.y}; + for (int i = 0; i < (int)listData.size(); i++) + { + roi.left = roi.left > listData[i].pt3D.x ? listData[i].pt3D.x : roi.left; + roi.right = roi.right < listData[i].pt3D.x ? listData[i].pt3D.x : roi.right; + roi.top = roi.top > listData[i].pt3D.y ? listData[i].pt3D.y : roi.top; + roi.bottom = roi.bottom < listData[i].pt3D.y ? listData[i].pt3D.y : roi.bottom; + } + return roi; +} + +//㶨λĵλ +SSX_pointPoseInfo sx_getLocationPlatePose( + std::vector< std::vector>& scanLines, + const SSG_cornerParam cornerPara, + int* errCode) +{ + *errCode = 0; + SSX_pointPoseInfo resultPose; + resultPose.center = { 0, 0, 0 }; + resultPose.normalDir = { 0, 0, 0 }; + int lineNum = (int)scanLines.size(); + if (lineNum == 0) + { + *errCode = SG_ERR_3D_DATA_NULL; + return resultPose; + } + + int linePtNum = (int)scanLines[0].size(); + + //жݸʽǷΪgrid㷨ֻܴgridݸʽ + bool isGridData = true; + for (int line = 0; line < lineNum; line++) + { + if (linePtNum != (int)scanLines[line].size()) + { + isGridData = false; + break; + } + } + if (false == isGridData)//ݲʽ + { + *errCode = SG_ERR_NOT_GRID_FORMAT; + return resultPose; + } + + //ˮƽɨ + std::vector< std::vector> scanLines_h; + scanLines_h.resize(linePtNum); + for (int i = 0; i < linePtNum; i++) + scanLines_h[i].resize(lineNum); + for (int line = 0; line < lineNum; line++) + { + for (int j = 0; j < linePtNum; j++) + { + scanLines[line][j].nPointIdx = 0; //ԭʼݵ0תʹã + scanLines_h[j][line] = scanLines[line][j]; + scanLines_h[j][line].pt3D.x = scanLines[line][j].pt3D.y; + scanLines_h[j][line].pt3D.y = scanLines[line][j].pt3D.x; + } + } + for (int line = 0; line < linePtNum; line++) + { + for (int j = 0, j_max = (int)scanLines_h[line].size(); j < j_max; j++) + scanLines_h[line][j].nPointIdx = j; + } + + //ȡλ˵ + //ֱ + std::vector> flags; + flags.resize(lineNum); + for (int i = 0; i < lineNum; i++) + { + flags[i].resize(linePtNum); + std::fill(flags[i].begin(), flags[i].end(), 0); + } + + std::vector< SVzNL3DPosition> endingPts; + for (int line = 0; line < lineNum; line++) + { + std::vector< SVzNL3DPosition> vldPts; + std::vector segs; + std::vector backIndexing; + backIndexing.resize(scanLines[line].size()); + wd_lineDataSegment_zDist( + scanLines[line], + vldPts, + segs, + backIndexing, + cornerPara + ); + for (int i = 0; i < (int)segs.size(); i++) + { + int idx_0 = segs[i].start; + int idx_1 = segs[i].start + segs[i].len - 1; + SVzNL3DPosition pt_0 = vldPts[idx_0]; + SVzNL3DPosition pt_1 = vldPts[idx_1]; + flags[line][pt_0.nPointIdx] = 1; + flags[line][pt_1.nPointIdx] = 1; + pt_0.nPointIdx = pt_0.nPointIdx & 0xffff | (line << 16); + pt_1.nPointIdx = pt_1.nPointIdx & 0xffff | (line << 16); + endingPts.push_back(pt_0); + endingPts.push_back(pt_1); + } + } + for (int line = 0; line < linePtNum; line++) + { + std::vector< SVzNL3DPosition> vldPts; + std::vector segs; + std::vector backIndexing; + backIndexing.resize(scanLines_h[line].size()); + wd_lineDataSegment_zDist( + scanLines_h[line], + vldPts, + segs, + backIndexing, + cornerPara + ); + for (int i = 0; i < (int)segs.size(); i++) + { + int idx_0 = segs[i].start; + int idx_1 = segs[i].start + segs[i].len - 1; + SVzNL3DPosition pt_0 = vldPts[idx_0]; + SVzNL3DPosition pt_1 = vldPts[idx_1]; + if (0 == flags[pt_0.nPointIdx][line])//ʹֱȡĵظ + { + flags[pt_0.nPointIdx][line] = 1; + pt_0.pt3D = scanLines[pt_0.nPointIdx][line].pt3D; //ȡԭʼ + pt_0.nPointIdx = (pt_0.nPointIdx <<16) | (line & 0xffff); + endingPts.push_back(pt_0); + } + if (0 == flags[pt_1.nPointIdx][line]) //ʹֱȡĵظ + { + flags[pt_1.nPointIdx][line] = 1; + pt_1.pt3D = scanLines[pt_1.nPointIdx][line].pt3D; //ȡԭʼ + pt_1.nPointIdx = (pt_1.nPointIdx << 16) | (line & 0xffff); + endingPts.push_back(pt_1); + } + } + } + //ע + for (int line = 0; line < lineNum; line++) + { + for (int j = 0; j < linePtNum; j++) + scanLines[line][j].nPointIdx = 0; //ԭʼݵ0תʹã + } + for (int i = 0; i < (int)endingPts.size(); i++) + { + int line = endingPts[i].nPointIdx >> 16; + int ptIdx = endingPts[i].nPointIdx & 0x0000FFFF; + scanLines[line][ptIdx].nPointIdx = 1; + } + + // + //ڲ + int clusterCheckWin = 5; + double clusterDist = 5.0; + double topLayerThickness = 10.0; + double centerZ_R = 20.0; + int distType = 1; //0 - 2d distance; 1- 3d distance + std::vector> objClusters; //result + wd_pointClustering_speedUp( + endingPts, + lineNum, linePtNum, clusterCheckWin, // + clusterDist, + distType, + objClusters //result + ); + + //жϱ + std::vector objMeanZ; + objMeanZ.resize(objClusters.size()); + std::vector< SSG_ROIRectD> objROIs; + objROIs.resize(objClusters.size()); + //˳СΧZ + double minMeanZ = -1; + for (int i = 0; i < (int)objClusters.size(); i++) + { + SSG_ROIRectD a_roi = _getListROI(objClusters[i]); + objROIs[i] = a_roi; + double w = a_roi.right - a_roi.left; + double h = a_roi.bottom - a_roi.top; + + double meanZ = _getListMeanZ(objClusters[i]); + objMeanZ[i] = meanZ; + if ( (meanZ > 1e-4) && (w > 150) && (h > 100)) + { + if (minMeanZ < 0) + minMeanZ = meanZ; + else + minMeanZ = minMeanZ > meanZ ? meanZ : minMeanZ; + } + } + //ѡROIĿΪ + int objIdx = -1; + double maxSize = 0; + for (int i = 0; i < (int)objClusters.size(); i++) + { + if (objMeanZ[i] > 1e-4) + { + double zDist = objMeanZ[i] - minMeanZ; + if (zDist < topLayerThickness) //ͬڶ + { + double size = (objROIs[i].right - objROIs[i].left) * (objROIs[i].bottom - objROIs[i].top); + if (maxSize < -1e-4) + { + maxSize = size; + objIdx = i; + } + else + { + if (maxSize < size) + { + maxSize = size; + objIdx = i; + } + } + } + } + } + + if (objIdx < 0) + { + *errCode = SG_ERR_ZERO_OBJECTS; + return resultPose; + } + //ע + for (int i = 0; i < (int)objClusters[objIdx].size(); i++) + { + int line = objClusters[objIdx][i].nPointIdx >> 16; + int ptIdx = objClusters[objIdx][i].nPointIdx & 0x0000FFFF; + scanLines[line][ptIdx].nPointIdx = 2; + } + + //ƽ + std::vector Points3ds; + for (int i = 0; i < (int)objClusters[objIdx].size(); i++) + { + cv::Point3f a_pt = cv::Point3f(objClusters[objIdx][i].pt3D.x, objClusters[objIdx][i].pt3D.y, objClusters[objIdx][i].pt3D.z); + Points3ds.push_back(a_pt); + } + //: z = Ax + By + C + //res: [0]=A, [1]= B, [2]=-1.0, [3]=C, + //std::vector out_inliers; + //Plane res = ransacFitPlane( Points3ds, out_inliers ); + Plane res = robustFitPlane(Points3ds); + + //std::vector res; + //vzCaculateLaserPlane(Points3ds, res); + //ͶӰ + SVzNL3DPoint vec_1 = {res.A, res.B, res.C}; + SVzNL3DPoint vec_2 = { 0, 0, 1.0 }; + SSG_planeCalibPara poseR = wd_computeRTMatrix(vec_1, vec_2); + + //ͶӰ + std::vector projectPoints3ds; + projectPoints3ds.resize(Points3ds.size()); + double sum_x = 0, sum_y = 0; + for (int i = 0; i < (int)Points3ds.size(); i++) + { + double x = Points3ds[i].x * poseR.planeCalib[0] + Points3ds[i].y * poseR.planeCalib[1] + Points3ds[i].z * poseR.planeCalib[2]; + double y = Points3ds[i].x * poseR.planeCalib[3] + Points3ds[i].y * poseR.planeCalib[4] + Points3ds[i].z * poseR.planeCalib[5]; + double z = Points3ds[i].x * poseR.planeCalib[6] + Points3ds[i].y * poseR.planeCalib[7] + Points3ds[i].z * poseR.planeCalib[8]; + projectPoints3ds[i] = cv::Point3f(x, y, z); + sum_x += x; + sum_y += y; + } + + for (int i = 0; i < lineNum; i++) + { + if (i == 14) + int kkk = 1; + //д + //ƽȥ + lineDataRT_vector(scanLines[i], poseR.planeCalib, -1); + } + + // + double center_x = sum_x / (double)Points3ds.size(); + double center_y = sum_y / (double)Points3ds.size(); + + //4 + SVzNL2DPointD top_pt = { center_x, center_y - centerZ_R }; + SVzNL2DPointD bottom_pt = { center_x, center_y + centerZ_R }; + SVzNL2DPointD left_pt = { center_x - centerZ_R, center_y}; + SVzNL2DPointD roght_pt = { center_x + centerZ_R, center_y}; + //Z + SVzNL3DPoint ptTop = { 0, 0, 0 }; + SVzNL3DPoint ptBtm = { 0, 0, 0 }; + SVzNL3DPoint ptLeft = { 0, 0, 0 }; + SVzNL3DPoint ptRight = { 0, 0, 0 }; + double minDistTop = -1, minDistBtm = -1, minDistLeft = -1, minDistRight = -1; + for (int line = 0; line < lineNum; line++) + { + for (int j = 0; j < linePtNum; j++) + { + if (scanLines[line][j].pt3D.z > 1e-4) + { + //top + if (minDistTop < 1e-4) + { + ptTop = scanLines[line][j].pt3D; + minDistTop = sqrt(pow(top_pt.x - scanLines[line][j].pt3D.x, 2) + pow(top_pt.y - scanLines[line][j].pt3D.y, 2)); + } + else + { + double dist = sqrt(pow(top_pt.x - scanLines[line][j].pt3D.x, 2) + pow(top_pt.y - scanLines[line][j].pt3D.y, 2)); + if (minDistTop > dist) + { + ptTop = scanLines[line][j].pt3D; + minDistTop = dist; + } + } + //bottom + if (minDistBtm < 1e-4) + { + ptBtm = scanLines[line][j].pt3D; + minDistBtm = sqrt(pow(bottom_pt.x - scanLines[line][j].pt3D.x, 2) + pow(bottom_pt.y - scanLines[line][j].pt3D.y, 2)); + } + else + { + double dist = sqrt(pow(bottom_pt.x - scanLines[line][j].pt3D.x, 2) + pow(bottom_pt.y - scanLines[line][j].pt3D.y, 2)); + if (minDistBtm > dist) + { + ptBtm = scanLines[line][j].pt3D; + minDistBtm = dist; + } + } + //left + if (minDistLeft < 1e-4) + { + ptLeft = scanLines[line][j].pt3D; + minDistLeft = sqrt(pow(left_pt.x - scanLines[line][j].pt3D.x, 2) + pow(left_pt.y - scanLines[line][j].pt3D.y, 2)); + } + else + { + double dist = sqrt(pow(left_pt.x - scanLines[line][j].pt3D.x, 2) + pow(left_pt.y - scanLines[line][j].pt3D.y, 2)); + if (minDistLeft > dist) + { + ptLeft = scanLines[line][j].pt3D; + minDistLeft = dist; + } + } + //right + if (minDistRight < 1e-4) + { + ptRight = scanLines[line][j].pt3D; + minDistRight = sqrt(pow(roght_pt.x - scanLines[line][j].pt3D.x, 2) + pow(roght_pt.y - scanLines[line][j].pt3D.y, 2)); + } + else + { + double dist = sqrt(pow(roght_pt.x - scanLines[line][j].pt3D.x, 2) + pow(roght_pt.y - scanLines[line][j].pt3D.y, 2)); + if (minDistRight > dist) + { + ptRight = scanLines[line][j].pt3D; + minDistRight = dist; + } + } + } + } + } + double center_z = (ptTop.z + ptBtm.z + ptLeft.z + ptRight.z) / 4; + resultPose.center = { center_x, center_y, center_z }; + resultPose.normalDir = { 0, 0, -1.0 }; + //תȥ + for (int i = 0; i < lineNum; i++) + { + //д + //ƽȥ + lineDataRT_vector(scanLines[i], poseR.invRMatrix, -1); + } + double x = resultPose.center.x * poseR.invRMatrix[0] + resultPose.center.y * poseR.invRMatrix[1] + resultPose.center.z * poseR.invRMatrix[2]; + double y = resultPose.center.x * poseR.invRMatrix[3] + resultPose.center.y * poseR.invRMatrix[4] + resultPose.center.z * poseR.invRMatrix[5]; + double z = resultPose.center.x * poseR.invRMatrix[6] + resultPose.center.y * poseR.invRMatrix[7] + resultPose.center.z * poseR.invRMatrix[8]; + resultPose.center = { x, y, z }; + x = resultPose.normalDir.x * poseR.invRMatrix[0] + resultPose.normalDir.y * poseR.invRMatrix[1] + resultPose.normalDir.z * poseR.invRMatrix[2]; + y = resultPose.normalDir.x * poseR.invRMatrix[3] + resultPose.normalDir.y * poseR.invRMatrix[4] + resultPose.normalDir.z * poseR.invRMatrix[5]; + z = resultPose.normalDir.x * poseR.invRMatrix[6] + resultPose.normalDir.y * poseR.invRMatrix[7] + resultPose.normalDir.z * poseR.invRMatrix[8]; + resultPose.normalDir = { x, y, z }; + return resultPose; +} void rodAarcFeatueDetection( std::vector< std::vector>& scanLines, @@ -824,3 +1221,123 @@ void sx_rodPositioning( return; } +//ԣֽṹֽ춨λ +void sx_rebarWeldSeamPositioning( + std::vector< std::vector>& scanLines, + const SSG_planeCalibPara poseCalibPara, + const SSG_cornerParam cornerPara, + const SSG_outlierFilterParam filterParam, + const SSG_treeGrowParam growParam, + const SSX_rodParam rodParam, + std::vector& weldSeamInfo, + int* errCode) +{ + *errCode = 0; + int lineNum = (int)scanLines.size(); + if (lineNum == 0) + { + *errCode = SG_ERR_3D_DATA_NULL; + return; + } + + int linePtNum = (int)scanLines[0].size(); + + //жݸʽǷΪgrid㷨ֻܴgridݸʽ + bool isGridData = true; + for (int line = 0; line < lineNum; line++) + { + if (linePtNum != (int)scanLines[line].size()) + { + isGridData = false; + break; + } + } + if (false == isGridData)//ݲʽ + { + *errCode = SG_ERR_NOT_GRID_FORMAT; + return; + } + + for (int i = 0, i_max = (int)scanLines.size(); i < i_max; i++) + { + if (i == 14) + int kkk = 1; + //д + //ƽȥ + double cuttingZ = -1; + sx_rodPosition_lineDataR(scanLines[i], poseCalibPara.planeCalib, cuttingZ); + } + + //Ѱˮƽʹֱĸֽ + //ˮƽɨ + std::vector> hLines_raw; + hLines_raw.resize(linePtNum); + for (int i = 0; i < linePtNum; i++) + hLines_raw[i].resize(lineNum); + for (int line = 0; line < lineNum; line++) + { + for (int j = 0; j < linePtNum; j++) + { + scanLines[line][j].nPointIdx = 0; //ԭʼݵ0תʹã + hLines_raw[j][line] = scanLines[line][j]; + hLines_raw[j][line].pt3D.x = scanLines[line][j].pt3D.y; + hLines_raw[j][line].pt3D.y = scanLines[line][j].pt3D.x; + } + } + + //ڴֱϷֱȡARC + std::vector> arcFeatures_v; + rodAarcFeatueDetection(scanLines, cornerPara, filterParam, rodParam.diameter, arcFeatures_v); + // + std::vector rodArcTrees_v; + wd_getRodArcFeatureGrowingTrees(arcFeatures_v, rodArcTrees_v, growParam); + + //ˮƽ + std::vector> arcFeatures_h; + rodAarcFeatueDetection(hLines_raw, cornerPara, filterParam, rodParam.diameter, arcFeatures_h); + // + std::vector rodArcTrees_h; + wd_getRodArcFeatureGrowingTrees(arcFeatures_h, rodArcTrees_h, growParam); + + if ((rodArcTrees_v.size() == 0) && (rodArcTrees_h.size() == 0)) + { + *errCode = SG_ERR_NOT_GRID_FORMAT; + return; + } + + int objNum_v = (int)rodArcTrees_v.size(); + int objNum_h = (int)rodArcTrees_h.size(); + for (int line = 0; line < lineNum; line++) + { + for (int j = 0; j < linePtNum; j++) + { + scanLines[line][j].nPointIdx = 0; //ԭʼݵ0תʹã + } + } + //ñ־debug + for (int i = 0; i < objNum_v; i++) + { + int nodeNum = (int)rodArcTrees_v[i].treeNodes.size(); + for (int j = 0; j < nodeNum; j++) + { + int lineIdx = rodArcTrees_v[i].treeNodes[j].lineIdx; + int centerPtIdx = rodArcTrees_v[i].treeNodes[j].peakPtIdx; + for (int m = rodArcTrees_v[i].treeNodes[j].startPtIdx; m <= rodArcTrees_v[i].treeNodes[j].endPtIdx; m++) + scanLines[lineIdx][m].nPointIdx = 1; + scanLines[lineIdx][centerPtIdx].nPointIdx |= 0x10; + } + } + //ñ־debug + for (int i = 0; i < objNum_h; i++) + { + int nodeNum = (int)rodArcTrees_h[i].treeNodes.size(); + for (int j = 0; j < nodeNum; j++) + { + int ptIdx = rodArcTrees_h[i].treeNodes[j].lineIdx; + int centerLineIdx = rodArcTrees_h[i].treeNodes[j].peakPtIdx; + for (int m = rodArcTrees_h[i].treeNodes[j].startPtIdx; m <= rodArcTrees_h[i].treeNodes[j].endPtIdx; m++) + scanLines[m][ptIdx].nPointIdx |= 2; + scanLines[centerLineIdx][ptIdx].nPointIdx |= 0x20; + } + } +} diff --git a/sourceCode/rodAndBarDetection_Export.h b/sourceCode/rodAndBarDetection_Export.h index 1c496bb..a3cadb6 100644 --- a/sourceCode/rodAndBarDetection_Export.h +++ b/sourceCode/rodAndBarDetection_Export.h @@ -9,8 +9,13 @@ typedef struct { SVzNL3DPoint center; //ݸ˶˲ĵ SVzNL3DPoint axialDir; // - double rotateAngle; //-30 - 30 -}SSX_hexHeadScrewInfo; //ͷݸ +}SSX_rodPoseInfo; // + +typedef struct +{ + SVzNL3DPoint center; //ݸ˶˲ĵ + SVzNL3DPoint normalDir; // +}SSX_pointPoseInfo; // typedef struct { @@ -27,6 +32,14 @@ typedef struct SVzNL3DPoint endPt; }SSX_rodPositionInfo; +typedef struct +{ + SVzNL3DPoint startPt; + SVzNL3DPoint endPt; + SVzNL3DPoint center; + SVzNL3DPoint normalDir; // +}SSX_weldSeamInfo; + //汾 SG_APISHARED_EXPORT const char* wd_rodAndBarDetectionVersion(void); @@ -52,9 +65,16 @@ SG_APISHARED_EXPORT void sx_hexHeadScrewMeasure( const SSG_outlierFilterParam filterParam, const SSG_treeGrowParam growParam, double rodDiameter, - std::vector& screwInfo, + std::vector& screwInfo, int* errCode); +//㶨λĵλ +SG_APISHARED_EXPORT SSX_pointPoseInfo sx_getLocationPlatePose( + std::vector< std::vector>& scanLines, + const SSG_cornerParam cornerPara, + int* errCode); + +//ץȡλ SG_APISHARED_EXPORT void sx_rodPositioning( std::vector< std::vector>& scanLines, const SSG_planeCalibPara poseCalibPara, @@ -63,4 +83,15 @@ SG_APISHARED_EXPORT void sx_rodPositioning( const SSG_treeGrowParam growParam, const SSX_rodParam rodParam, std::vector& rodInfo, + int* errCode); + +//ԣֽṹֽ춨λ +SG_APISHARED_EXPORT void sx_rebarWeldSeamPositioning( + std::vector< std::vector>& scanLines, + const SSG_planeCalibPara poseCalibPara, + const SSG_cornerParam cornerPara, + const SSG_outlierFilterParam filterParam, + const SSG_treeGrowParam growParam, + const SSX_rodParam rodParam, + std::vector& weldSeamInfo, int* errCode); \ No newline at end of file