diff --git a/beltTearingDetection_test/beltTearingDetection_test.vcxproj b/beltTearingDetection_test/beltTearingDetection_test.vcxproj
index aaa99d0..a634840 100644
--- a/beltTearingDetection_test/beltTearingDetection_test.vcxproj
+++ b/beltTearingDetection_test/beltTearingDetection_test.vcxproj
@@ -42,13 +42,13 @@
Application
true
- v142
+ v143
Unicode
Application
false
- v142
+ v143
true
Unicode
diff --git a/rodAndBarDetection/rodAndBarDetection.vcxproj b/rodAndBarDetection/rodAndBarDetection.vcxproj
index 4bae6c4..6bae8c4 100644
--- a/rodAndBarDetection/rodAndBarDetection.vcxproj
+++ b/rodAndBarDetection/rodAndBarDetection.vcxproj
@@ -48,13 +48,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 06523df..e94b956 100644
--- a/rodAndBarDetection_test/rodAndBarDetection_test.cpp
+++ b/rodAndBarDetection_test/rodAndBarDetection_test.cpp
@@ -165,6 +165,49 @@ void _outputScanDataFile(char* fileName, std::vector& screwInfo)
{
std::ofstream sw(fileName);
@@ -181,6 +224,23 @@ void _outputChanneltInfo(char* fileName, std::vector& scre
sw.close();
}
+void _outputRodtInfo(char* fileName, std::vector& rodInfo)
+{
+ std::ofstream sw(fileName);
+
+ char dataStr[250];
+ int objNum = (int)rodInfo.size();
+ for (int i = 0; i < objNum; i++)
+ {
+ sprintf_s(dataStr, 250, "螺杆_%d: center_( %g, %g, %g ), dir_axia( %g, %g, %g ), dir_normal_( %g, %g, %g )",
+ i + 1, rodInfo[i].center.x, rodInfo[i].center.y, rodInfo[i].center.z,
+ rodInfo[i].axialDir.x, rodInfo[i].axialDir.y, rodInfo[i].axialDir.z,
+ rodInfo[i].normalDir.x, rodInfo[i].normalDir.y, rodInfo[i].normalDir.z);
+ sw << dataStr << std::endl;
+ }
+ sw.close();
+}
+
void _outputRGBDScan_RGBD(
char* fileName,
std::vector>& scanLines,
@@ -317,21 +377,161 @@ void _outputRGBDScan_RGBD(
sw.close();
}
-#define TEST_GROUP 1
-int main()
+void _outputRGBDScan_RGBD_rodInfo(
+ char* fileName,
+ std::vector>& scanLines,
+ std::vector& rodInfo
+)
{
- const char* dataPath[TEST_GROUP] = {
+ int lineNum = (int)scanLines.size();
+ std::ofstream sw(fileName);
+ int realLines = lineNum;
+ int objNum = (int)rodInfo.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 = { 250, 0, 0 };
+ size = 6;
+ }
+ else
+ {
+ rgb = objColor[pt3D->nPointIdx % 8];
+ 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;
+ }
+ }
+
+ if (objNum > 0)
+ {
+ sw << "Line_" << lineIdx << "_0_" << objNum << std::endl;
+ rgb = { 250, 0, 0 };
+ size = 8;
+ for (int i = 0; i < objNum; i++)
+ {
+ float x = (float)rodInfo[i].center.x;
+ float y = (float)rodInfo[i].center.y;
+ float z = (float)rodInfo[i].center.z;
+ sw << "{" << x << "," << y << "," << z << "}-";
+ sw << "{0,0}-{0,0}-";
+ sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
+ }
+ //多输出一个,修正显示工具bug
+ float x = (float)rodInfo[0].center.x;
+ float y = (float)rodInfo[0].center.y;
+ float z = (float)rodInfo[0].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;
+ for (int i = 0; i < objNum; i++)
+ {
+ SVzNL3DPoint pt0 = { rodInfo[i].center.x - len * rodInfo[i].axialDir.x,
+ rodInfo[i].center.y - len * rodInfo[i].axialDir.y,
+ rodInfo[i].center.z - len * rodInfo[i].axialDir.z };
+ SVzNL3DPoint pt1 = { rodInfo[i].center.x + len * rodInfo[i].axialDir.x,
+ rodInfo[i].center.y + len * rodInfo[i].axialDir.y,
+ rodInfo[i].center.z + len * rodInfo[i].axialDir.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++;
+ }
+ //多输出一个,修正显示工具bug
+ SVzNL3DPoint pt0 = { rodInfo[0].center.x - len * rodInfo[0].axialDir.x,
+ rodInfo[0].center.y - len * rodInfo[0].axialDir.y,
+ rodInfo[0].center.z - len * rodInfo[0].axialDir.z };
+ SVzNL3DPoint pt1 = { rodInfo[0].center.x + len * rodInfo[0].axialDir.x,
+ rodInfo[0].center.y + len * rodInfo[0].axialDir.y,
+ rodInfo[0].center.z + len * rodInfo[0].axialDir.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();
+}
+#define SCREW_TEST_GROUP 1
+void screwTest(void)
+{
+ const char* dataPath[SCREW_TEST_GROUP] = {
"F:/ShangGu/项目/冠钦项目/螺杆测量/数据/模拟数据/", //0
};
- SVzNLRange fileIdx[TEST_GROUP] = {
+ SVzNLRange fileIdx[SCREW_TEST_GROUP] = {
{1,4},
};
const char* ver = wd_rodAndBarDetectionVersion();
printf("ver:%s\n", ver);
- for (int grp = 0; grp < TEST_GROUP; grp++)
+ for (int grp = 0; grp < SCREW_TEST_GROUP; grp++)
{
for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
{
@@ -392,7 +592,113 @@ int main()
_outputChanneltInfo(_scan_file, screwInfo);
}
}
+}
+#define ROD_POSITION_TEST_GROUP 1
+void rodPositionTest(void)
+{
+ const char* dataPath[ROD_POSITION_TEST_GROUP] = {
+ "F:/ShangGu/项目/冠钦项目/棒材抓取/", //0
+ };
+
+ SVzNLRange fileIdx[ROD_POSITION_TEST_GROUP] = {
+ {1,8},
+ };
+
+ const char* ver = wd_rodAndBarDetectionVersion();
+ printf("ver:%s\n", ver);
+
+ for (int grp = 0; grp < ROD_POSITION_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 rodInfo;
+ sx_rodPositioning(
+ scanLines,
+ poseCalibPara,
+ cornerParam,
+ filterParam,
+ growParam,
+ rodParam,
+ rodInfo,
+ &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_rodInfo(_scan_file, scanLines, rodInfo);
+ sprintf_s(_scan_file, "%sresult\\%d_screw_info.txt", dataPath[grp], fidx);
+ _outputRodtInfo(_scan_file, rodInfo);
+ }
+ }
+}
+
+int main()
+{
+#if 0 //螺杆定位测试
+ screwTest();
+#else //棒材抓取定位测试
+ rodPositionTest();
+#endif
+ return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
diff --git a/rodAndBarDetection_test/rodAndBarDetection_test.vcxproj b/rodAndBarDetection_test/rodAndBarDetection_test.vcxproj
index a5d5c8d..e1fed7d 100644
--- a/rodAndBarDetection_test/rodAndBarDetection_test.vcxproj
+++ b/rodAndBarDetection_test/rodAndBarDetection_test.vcxproj
@@ -42,13 +42,13 @@
Application
true
- v142
+ v143
Unicode
Application
false
- v142
+ v143
true
Unicode
diff --git a/sourceCode/SG_baseAlgo_Export.h b/sourceCode/SG_baseAlgo_Export.h
index a710163..be6d586 100644
--- a/sourceCode/SG_baseAlgo_Export.h
+++ b/sourceCode/SG_baseAlgo_Export.h
@@ -149,6 +149,14 @@ SG_APISHARED_EXPORT void wd_getRingArcFeature(
SVzNLRangeD ringArcWidth, //ӵĻ
std::vector& line_ringArcs //
);
+//ݰArcĶZСֵZСֵĹս
+SG_APISHARED_EXPORT void wd_getRodArcFeature_peakCornerMethod(
+ std::vector< SVzNL3DPosition>& lineData,
+ int lineIdx,
+ const double peakChkWin,
+ const SSG_cornerParam cornerPara,
+ std::vector& line_rodArcs //
+);
///
/// ȡϵĹյPSM LVTypeFeature, BQȹյ㷨Ļϵİ汾
@@ -269,6 +277,13 @@ SG_APISHARED_EXPORT void sg_getLineLocalPeaks(
std::vector< SSG_basicFeature1D>& localMax,
std::vector< SSG_basicFeature1D>& localMin);
+SG_APISHARED_EXPORT void sg_getLineLocalPeaks_2(
+ std::vector& lineData,
+ int lineIdx,
+ const double scaleWin,
+ std::vector< SSG_basicFeature1D>& localZMax,
+ std::vector< SSG_basicFeature1D>& localZMin);
+
SG_APISHARED_EXPORT void sg_getFlatLineLocalPeaks_vector(
std::vector& lineData,
int lineIdx,
@@ -303,6 +318,12 @@ SG_APISHARED_EXPORT void wd_getSegFeatureGrowingTrees(
std::vector& feature_trees,
SSG_treeGrowParam growParam);
+//rodArcfeature
+SG_APISHARED_EXPORT void wd_getRodArcFeatureGrowingTrees(
+ std::vector>& all_lineFeatures,
+ std::vector& feature_trees,
+ const SSG_treeGrowParam growParam);
+
SG_APISHARED_EXPORT void sg_lineFeaturesGrowing(
int lineIdx,
bool isLastLine,
diff --git a/sourceCode/SG_baseDataType.h b/sourceCode/SG_baseDataType.h
index 267b853..d6e497e 100644
--- a/sourceCode/SG_baseDataType.h
+++ b/sourceCode/SG_baseDataType.h
@@ -257,6 +257,18 @@ typedef struct
double featureValue;
}SWD_segFeature;
+typedef struct
+{
+ int lineIdx;
+ int startPtIdx;
+ int endPtIdx;
+ int peakPtIdx;
+ SVzNL3DPoint startPt;
+ SVzNL3DPoint endPt;
+ SVzNL3DPoint peakPt;
+ double featureValue;
+}SWD_rodArcFeature;
+
typedef struct
{
double sameGapTh;
@@ -352,6 +364,15 @@ typedef struct
std::vector< SWD_segFeature> treeNodes;
}SWD_segFeatureTree;
+typedef struct
+{
+ int treeState;
+ int sLineIdx;
+ int eLineIdx;
+ double tree_value;
+ std::vector< SWD_rodArcFeature> treeNodes;
+}SWD_rodArcFeatureTree;
+
typedef struct
{
int vTreeFlag;
@@ -549,6 +570,8 @@ typedef struct
typedef struct
{
int pntIdx;
+ int forwardPntIdx;
+ int backwardPntIdx;
int type;
double forwardAngle; //ǰ
double backwardAngle; //
diff --git a/sourceCode/SG_featureGrow.cpp b/sourceCode/SG_featureGrow.cpp
index 4f0044f..1610126 100644
--- a/sourceCode/SG_featureGrow.cpp
+++ b/sourceCode/SG_featureGrow.cpp
@@ -146,6 +146,36 @@ bool _segFeatureGrowing(SWD_segFeature& a_feature, const int lineIdx, std::vecto
return false;
}
+//segment featuretreesѰҺʵûкʵ㣬 false
+bool _rodArcFeatureGrowing(SWD_rodArcFeature& a_feature, const int lineIdx, std::vector& trees, const SSG_treeGrowParam growParam)
+{
+ for (int i = 0, i_max = (int)trees.size(); i < i_max; i++)
+ {
+ SWD_rodArcFeatureTree& a_tree = trees[i];
+ if (TREE_STATE_DEAD == a_tree.treeState)
+ continue;
+ //
+ SWD_rodArcFeature last_node = a_tree.treeNodes.back();
+ if (last_node.lineIdx == a_feature.lineIdx) //xΪlineIdxͬһɨϵIJ
+ continue;
+
+ //ж
+ double y_diff_1 = abs(a_feature.peakPt.y - last_node.peakPt.y);
+ double z_diff_1 = abs(a_feature.peakPt.z - last_node.peakPt.z);
+ int line_diff = abs(a_feature.lineIdx - last_node.lineIdx);
+ double x_diff = abs(a_feature.peakPt.x - last_node.peakPt.x);
+ if ((y_diff_1 < growParam.yDeviation_max) && (z_diff_1 < growParam.zDeviation_max) &&
+ ((line_diff < growParam.maxLineSkipNum) || (x_diff < growParam.maxSkipDistance)))
+ {
+ a_tree.eLineIdx = lineIdx;
+ a_tree.treeNodes.push_back(a_feature);
+ a_tree.tree_value += (a_feature.startPt.z + a_feature.endPt.z) / 2;
+ return true;
+ }
+ }
+ return false;
+}
+
int _getMatchedTree_angleCheck(
SSG_basicFeature1D& a_feature,
const int lineIdx,
@@ -638,7 +668,7 @@ void wd_getFeatureGrowingTrees_noTypeMatch(
void wd_getSegFeatureGrowingTrees(
std::vector>& all_lineFeatures,
std::vector& feature_trees,
- SSG_treeGrowParam growParam)
+ const SSG_treeGrowParam growParam)
{
for (int i = 0, i_max = (int)all_lineFeatures.size(); i < i_max; i++)
{
@@ -702,6 +732,76 @@ void wd_getSegFeatureGrowingTrees(
}
+void wd_getRodArcFeatureGrowingTrees(
+ std::vector>& all_lineFeatures,
+ std::vector& feature_trees,
+ SSG_treeGrowParam growParam)
+{
+ for (int i = 0, i_max = (int)all_lineFeatures.size(); i < i_max; i++)
+ {
+ if (i == 424)
+ int kkk = 1;
+ std::vector& a_lineFeatures = all_lineFeatures[i];
+ for (int j = 0, j_max = (int)a_lineFeatures.size(); j < j_max; j++)
+ {
+ SWD_rodArcFeature& a_feature = a_lineFeatures[j];
+ bool isMatched = _rodArcFeatureGrowing(a_feature, i, feature_trees, growParam);
+ if (false == isMatched)
+ {
+ //µ
+ SWD_rodArcFeatureTree a_newTree;
+ a_newTree.treeNodes.push_back(a_feature);
+ a_newTree.treeState = TREE_STATE_ALIVE;
+ a_newTree.sLineIdx = a_feature.lineIdx;
+ a_newTree.eLineIdx = a_feature.lineIdx;
+ a_newTree.tree_value = (a_feature.startPt.z + a_feature.endPt.z) / 2;
+ feature_trees.push_back(a_newTree);
+ }
+ }
+ //ֹͣ,١
+ //ڵΪ1Ƴ
+ int lineIdx = i;
+ int m_max = (int)feature_trees.size();
+ for (int m = m_max - 1; m >= 0; m--) //ӺǰɾӰѭ
+ {
+ if (TREE_STATE_ALIVE == feature_trees[m].treeState)
+ {
+ int line_diff = abs(lineIdx - feature_trees[m].treeNodes.back().lineIdx);
+ if (line_diff > 0)
+ {
+ SWD_rodArcFeature* first_node = &(feature_trees[m].treeNodes[0]);
+ SWD_rodArcFeature* last_node = &(feature_trees[m].treeNodes[feature_trees[m].treeNodes.size() - 1]);
+ double len = sqrt(pow(first_node->peakPt.x - last_node->peakPt.x, 2) +
+ pow(first_node->peakPt.y - last_node->peakPt.y, 2) +
+ pow(first_node->peakPt.z - last_node->peakPt.z, 2));
+ int tree_lines = feature_trees[m].eLineIdx - feature_trees[m].sLineIdx;
+ if (tree_lines > 0)
+ {
+ double mean_stepping = len / tree_lines;
+ double x_skip = mean_stepping * line_diff;
+ if (((growParam.maxLineSkipNum > 0) && (line_diff > growParam.maxLineSkipNum)) ||
+ ((growParam.maxLineSkipNum <= 0) && (x_skip > growParam.maxSkipDistance)) ||
+ (i == i_max - 1))
+ {
+ feature_trees[m].treeState = TREE_STATE_DEAD;
+ if (len <= growParam.minLTypeTreeLen)
+ feature_trees.erase(feature_trees.begin() + m);
+ }
+ }
+ }
+ }
+ }
+ }
+ //nodeΪ1treeȥʱȥnodeΪ1tree
+ int m_max = (int)feature_trees.size();
+ for (int m = m_max - 1; m >= 0; m--) //ӺǰɾӰѭ
+ {
+ int tree_lines = feature_trees[m].eLineIdx - feature_trees[m].sLineIdx;
+ if (tree_lines == 0)
+ feature_trees.erase(feature_trees.begin() + m);
+ }
+}
+
void sg_lineFeaturesGrowing(
int lineIdx,
bool isLastLine,
diff --git a/sourceCode/SG_lineFeature.cpp b/sourceCode/SG_lineFeature.cpp
index 0d8cdf9..9f2c1ec 100644
--- a/sourceCode/SG_lineFeature.cpp
+++ b/sourceCode/SG_lineFeature.cpp
@@ -443,6 +443,359 @@ void sg_lineDataRemoveOutlier_ptDistMethod(SVzNL3DPosition* lineData, int dataSi
return;
}
+///
+/// ȡϵļֵ㣨ֵͼСֵ㣩
+///
+///
+void sg_getLineLocalPeaks(
+ SVzNL3DPosition* lineData,
+ int dataSize,
+ int lineIdx,
+ const double scaleWin,
+ std::vector< SSG_basicFeature1D>& localMax,
+ std::vector< SSG_basicFeature1D>& localMin)
+{
+ if (dataSize < 2)
+ return;
+
+ int _state = 0;
+ int pre_i = -1;
+ int sEdgePtIdx = -1;
+ int eEdgePtIdx = -1;
+ SVzNL3DPosition* pre_data = NULL;
+ std::vector< SVzNL3DPosition> pkTop;
+ std::vector< SVzNL3DPosition> pkBtm;
+ for (int i = 0; i < dataSize; i++)
+ {
+ lineData[i].nPointIdx = i;
+ SVzNL3DPosition* curr_data = &lineData[i];
+ if (curr_data->pt3D.z < 1e-4)
+ {
+ if (i == dataSize - 1) //һ
+ {
+ if (1 == _state) //
+ {
+ pkTop.push_back(lineData[eEdgePtIdx]);
+ }
+ else if (2 == _state) //½
+ {
+ pkBtm.push_back(lineData[eEdgePtIdx]);
+ }
+ }
+ continue;
+ }
+
+ if (NULL == pre_data)
+ {
+ sEdgePtIdx = i;
+ eEdgePtIdx = i;
+ pre_data = curr_data;
+ pre_i = i;
+ continue;
+ }
+
+ eEdgePtIdx = i;
+ double z_diff = curr_data->pt3D.z - pre_data->pt3D.z;
+ switch (_state)
+ {
+ case 0: //̬
+ if (z_diff > 0) //½
+ {
+ _state = 2;
+ }
+ else if (z_diff < 0) //
+ {
+ _state = 1;
+ }
+ break;
+ case 1: //
+ if (z_diff > 0) //½
+ {
+ pkTop.push_back(*pre_data);
+ _state = 2;
+ }
+ break;
+ case 2: //½
+ if (z_diff < 0) //
+ {
+ pkBtm.push_back(*pre_data);
+ _state = 1;
+ }
+ break;
+ default:
+ _state = 0;
+ break;
+ }
+ pre_data = curr_data;
+ pre_i = i;
+ }
+ //ע⣺һΪλ
+
+ //Сֵ㣨嶥
+ //ֵȽϣڳ߶ȴѰҾֲֵ
+ double square_distTh = scaleWin * scaleWin;
+ for (int i = 0, i_max = (int)pkTop.size(); i < i_max; i++)
+ {
+ bool isPeak = true;
+ //ǰ
+ for (int j = i - 1; j >= 0; j--)
+ {
+ double dist = pow(pkTop[i].pt3D.y - pkTop[j].pt3D.y, 2); // + pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2) ;
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (pkTop[i].pt3D.z > pkTop[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ //
+ if (true == isPeak)
+ {
+ for (int j = i + 1; j < i_max; j++)
+ {
+ double dist = pow(pkTop[i].pt3D.y - pkTop[j].pt3D.y, 2); // +pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (pkTop[i].pt3D.z > pkTop[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ }
+ if (true == isPeak)
+ {
+ SSG_basicFeature1D a_feature;
+ a_feature.featureType = LINE_FEATURE_PEAK_TOP;
+ a_feature.jumpPos = pkTop[i].pt3D;
+ a_feature.jumpPos2D = { lineIdx, pkTop[i].nPointIdx };
+ localMin.push_back(a_feature);
+ }
+ }
+ //ֵ㣨ȵף
+ for (int i = 0, i_max = (int)pkBtm.size(); i < i_max; i++)
+ {
+ bool isPeak = true;
+ //ǰ
+ for (int j = i - 1; j >= 0; j--)
+ {
+ double dist = pow(pkBtm[i].pt3D.y - pkBtm[j].pt3D.y, 2); // +pow(pkBtm[i].pt3D.x - pkBtm[j].pt3D.x, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (pkBtm[i].pt3D.z < pkBtm[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ //
+ if (true == isPeak)
+ {
+ for (int j = i + 1; j < i_max; j++)
+ {
+ double dist = pow(pkBtm[i].pt3D.y - pkBtm[j].pt3D.y, 2); // +pow(pkBtm[i].pt3D.x - pkBtm[j].pt3D.x, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (pkBtm[i].pt3D.z < pkBtm[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ }
+ if (true == isPeak)
+ {
+ SSG_basicFeature1D a_feature;
+ a_feature.featureType = LINE_FEATURE_PEAK_BOTTOM;
+ a_feature.jumpPos = pkBtm[i].pt3D;
+ a_feature.jumpPos2D = { lineIdx, pkBtm[i].nPointIdx };
+ localMax.push_back(a_feature);
+ }
+ }
+
+ return;
+}
+
+void sg_getLineLocalPeaks_2(
+ std::vector& lineData,
+ int lineIdx,
+ const double scaleWin,
+ std::vector< SSG_basicFeature1D>& localZMax,
+ std::vector< SSG_basicFeature1D>& localZMin)
+{
+ int dataSize = (int)lineData.size();
+ if (dataSize < 2)
+ return;
+
+ int _state = 0;
+ int pre_i = -1;
+ int sEdgePtIdx = -1;
+ int eEdgePtIdx = -1;
+ SVzNL3DPosition* pre_data = NULL;
+ std::vector< SVzNL3DPosition> zTop;
+ std::vector< SVzNL3DPosition> zBtm;
+ for (int i = 0; i < dataSize; i++)
+ {
+ if (i == 355)
+ int kkk = 1;
+ lineData[i].nPointIdx = i;
+ SVzNL3DPosition* curr_data = &lineData[i];
+ if (curr_data->pt3D.z < 1e-4)
+ {
+ if (i == dataSize - 1) //һ
+ {
+ if (1 == _state) //
+ {
+ zTop.push_back(lineData[eEdgePtIdx]);
+ }
+ else if (2 == _state) //½
+ {
+ zBtm.push_back(lineData[eEdgePtIdx]);
+ }
+ }
+ continue;
+ }
+
+ if (NULL == pre_data)
+ {
+ sEdgePtIdx = i;
+ eEdgePtIdx = i;
+ pre_data = curr_data;
+ pre_i = i;
+ continue;
+ }
+
+ eEdgePtIdx = i;
+ double z_diff = curr_data->pt3D.z - pre_data->pt3D.z;
+ switch (_state)
+ {
+ case 0: //̬
+ if (z_diff < 0) //½
+ {
+ _state = 2;
+ }
+ else if (z_diff > 0) //
+ {
+ _state = 1;
+ }
+ break;
+ case 1: //
+ if (z_diff <0) //½
+ {
+ zTop.push_back(*pre_data);
+ _state = 2;
+ }
+ break;
+ case 2: //½
+ if (z_diff > 0) //
+ {
+ zBtm.push_back(*pre_data);
+ _state = 1;
+ }
+ break;
+ default:
+ _state = 0;
+ break;
+ }
+ pre_data = curr_data;
+ pre_i = i;
+ }
+ //ע⣺һΪλ
+
+ //Сֵ㣨嶥
+ //ֵȽϣڳ߶ȴѰҾֲֵ
+ double square_distTh = scaleWin * scaleWin;
+ for (int i = 0, i_max = (int)zTop.size(); i < i_max; i++)
+ {
+ bool isPeak = true;
+ //ǰ
+ for (int j = i - 1; j >= 0; j--)
+ {
+ double dist = pow(zTop[i].pt3D.y - zTop[j].pt3D.y, 2) + pow(zTop[i].pt3D.z - zTop[j].pt3D.z, 2) ;
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (zTop[i].pt3D.z < zTop[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ //
+ if (true == isPeak)
+ {
+ for (int j = i + 1; j < i_max; j++)
+ {
+ double dist = pow(zTop[i].pt3D.y - zTop[j].pt3D.y, 2) + pow(zTop[i].pt3D.z - zTop[j].pt3D.z, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (zTop[i].pt3D.z < zTop[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ }
+ if (true == isPeak)
+ {
+ SSG_basicFeature1D a_feature;
+ a_feature.featureType = LINE_FEATURE_PEAK_TOP;
+ a_feature.jumpPos = zTop[i].pt3D;
+ a_feature.jumpPos2D = { lineIdx, zTop[i].nPointIdx };
+ localZMax.push_back(a_feature);
+ }
+ }
+ //ֵ㣨ȵף
+ for (int i = 0, i_max = (int)zBtm.size(); i < i_max; i++)
+ {
+ bool isPeak = true;
+ //ǰ
+ for (int j = i - 1; j >= 0; j--)
+ {
+ double dist = pow(zBtm[i].pt3D.y - zBtm[j].pt3D.y, 2) + pow(zBtm[i].pt3D.z - zBtm[j].pt3D.z, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (zBtm[i].pt3D.z > zBtm[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ //
+ if (true == isPeak)
+ {
+ for (int j = i + 1; j < i_max; j++)
+ {
+ double dist = pow(zBtm[i].pt3D.y - zBtm[j].pt3D.y, 2); pow(zBtm[i].pt3D.z - zBtm[j].pt3D.z, 2);
+ if (dist > square_distTh) //߶ȴ
+ break;
+
+ if (zBtm[i].pt3D.z > zBtm[j].pt3D.z)
+ {
+ isPeak = false;
+ break;
+ }
+ }
+ }
+ if (true == isPeak)
+ {
+ SSG_basicFeature1D a_feature;
+ a_feature.featureType = LINE_FEATURE_PEAK_BOTTOM;
+ a_feature.jumpPos = zBtm[i].pt3D;
+ a_feature.jumpPos2D = { lineIdx, zBtm[i].nPointIdx };
+ localZMin.push_back(a_feature);
+ }
+ }
+ return;
+}
+
///
/// ȡɨеб£¼беڵ֮䡣
/// ͬʱ¼EndingûмӣֻҴʱEndingEnding֮СΪӿȵ1/4
@@ -3429,32 +3782,17 @@ void wd_getLineCornerFeature_PSM(
bool compareByPtIdx(const SSG_basicFeature1D& a, const SSG_basicFeature1D& b) {
return a.jumpPos2D.y < b.jumpPos2D.y;
}
-///
-/// ȡϵԲϰλԲĿȷ
-/// seg˵㣺z
-/// nPointIdx¶Feature
-/// 㷨̣
-/// 1ǰǺͺ
-/// 2սǣ˳ʱΪʱΪ
-/// 3սǵļֵ
-/// 4жϹսǷΪ
-///
-void wd_getRingArcFeature(
+
+//ZԷֶ
+void _lineDataSegment_zDist(
std::vector< SVzNL3DPosition>& lineData,
- int lineIdx,
- const SSG_cornerParam cornerPara,
- SVzNLRangeD ringArcWidth, //
- std::vector& line_ringArcs //
+ std::vector< SVzNL3DPosition>& vldPts,
+ std::vector& segs,
+ std::vector& backIndexing,
+ const SSG_cornerParam cornerPara
)
{
int dataSize = (int)lineData.size();
- //ȥ
- std::vector< SVzNL3DPosition> vldPts;
- //std::vector< int> vldPtSegIdx;
- std::vector segs;
- std::vector backIndexing;
- backIndexing.resize(dataSize);
-
int runIdx = 1;
SSG_RUN_EX a_run = { 0, -1, 0, false, false }; //startIdx, len, lastIdx
double pre_z = 0;
@@ -3515,21 +3853,17 @@ void wd_getRingArcFeature(
}
if (a_run.len > 0)
segs.push_back(a_run);
+}
-#if 0
- //ñ־
- for (int i = 0, i_max = (int)segs.size(); i < i_max; i++)
- {
- int idx1 = segs[i].start;
- int idx2 = segs[i].start + segs[i].len - 1;
- lineData[idx1].nPointIdx |= 0x100000;
- lineData[idx2].nPointIdx |= 0x200000;
- }
-#endif
-
- //ǰǺͺ
- std::vector< SSG_pntDirAngle> corners;
- corners.resize(vldPts.size());
+//μ㷽
+void _computeDirAngle_perSeg(
+ std::vector< SVzNL3DPosition>& vldPts,
+ std::vector& segs,
+ const SSG_cornerParam cornerPara,
+ std::vector< SSG_pntDirAngle>& ptDirAngles
+)
+{
+ ptDirAngles.resize(vldPts.size());
//ν
int segSize = (int)segs.size();
for (int segIdx = 0; segIdx < segSize; segIdx++)
@@ -3565,12 +3899,14 @@ void wd_getRingArcFeature(
//ս
if ((pre_i < 0) || (post_i < 0))
{
- corners[i].pntIdx = -1;
- corners[i].forwardAngle = 0;
- corners[i].backwardAngle = 0;
- corners[i].corner = 0;
- corners[i].forwardDiffZ = 0;
- corners[i].backwardDiffZ = 0;
+ ptDirAngles[i].pntIdx = -1;
+ ptDirAngles[i].forwardPntIdx = 0;
+ ptDirAngles[i].backwardPntIdx = 0;
+ ptDirAngles[i].forwardAngle = 0;
+ ptDirAngles[i].backwardAngle = 0;
+ ptDirAngles[i].corner = 0;
+ ptDirAngles[i].forwardDiffZ = 0;
+ ptDirAngles[i].backwardDiffZ = 0;
}
else
{
@@ -3578,15 +3914,134 @@ void wd_getRingArcFeature(
double tanValue_post = (vldPts[post_i].pt3D.z - vldPts[i].pt3D.z) / abs(vldPts[post_i].pt3D.y - vldPts[i].pt3D.y);
double forwardAngle = atan(tanValue_post) * 180.0 / PI;
double backwardAngle = atan(tanValue_pre) * 180.0 / PI;
- corners[i].pntIdx = i;
- corners[i].forwardAngle = forwardAngle;
- corners[i].backwardAngle = backwardAngle;
- corners[i].corner = -(forwardAngle - backwardAngle); //ͼϵϵy෴С-
- corners[i].forwardDiffZ = vldPts[post_i].pt3D.z - vldPts[i].pt3D.z;
- corners[i].backwardDiffZ = vldPts[i].pt3D.z - vldPts[pre_i].pt3D.z;
+ ptDirAngles[i].pntIdx = i;
+ ptDirAngles[i].forwardPntIdx = post_i;
+ ptDirAngles[i].backwardPntIdx = pre_i;
+ ptDirAngles[i].forwardAngle = forwardAngle;
+ ptDirAngles[i].backwardAngle = backwardAngle;
+ ptDirAngles[i].corner = -(forwardAngle - backwardAngle); //ͼϵϵy෴С-
+ ptDirAngles[i].forwardDiffZ = vldPts[post_i].pt3D.z - vldPts[i].pt3D.z;
+ ptDirAngles[i].backwardDiffZ = vldPts[i].pt3D.z - vldPts[pre_i].pt3D.z;
}
}
}
+}
+
+//㷽(ֶΣ
+void _computeDirAngle_wholeLine(
+ std::vector< SVzNL3DPosition>& line_data,
+ const SSG_cornerParam cornerPara,
+ std::vector< SSG_pntDirAngle>& ptDirAngles
+)
+{
+ ptDirAngles.resize(line_data.size());
+ int dataSize = (int)line_data.size();
+ for (int i = 0; i < dataSize; i++)
+ {
+ if (line_data[i].pt3D.z < 1e-4)
+ {
+ ptDirAngles[i].pntIdx = i;
+ ptDirAngles[i].forwardPntIdx = 0;
+ ptDirAngles[i].backwardPntIdx = 0;
+ ptDirAngles[i].type = -1;
+ ptDirAngles[i].forwardAngle = 0;
+ ptDirAngles[i].backwardAngle = 0;
+ ptDirAngles[i].corner = 0;
+ ptDirAngles[i].forwardDiffZ = 0;
+ ptDirAngles[i].backwardDiffZ = 0;
+ continue;
+
+ }
+ //ǰѰ
+ int pre_i = -1;
+ for (int j = i - 1; j >= 0; j--)
+ {
+ if (line_data[j].pt3D.z < 1e-4)
+ continue;
+
+ double dist = sqrt(pow(line_data[i].pt3D.y - line_data[j].pt3D.y, 2) +
+ pow(line_data[i].pt3D.z - line_data[j].pt3D.z, 2));
+ if (dist >= cornerPara.scale)
+ {
+ pre_i = j;
+ break;
+ }
+ }
+ //Ѱ
+ int post_i = -1;
+ for (int j = i + 1; j < dataSize; j++)
+ {
+ double dist = sqrt(pow(line_data[i].pt3D.y - line_data[j].pt3D.y, 2) +
+ pow(line_data[i].pt3D.z - line_data[j].pt3D.z, 2));
+ if (dist >= cornerPara.scale)
+ {
+ post_i = j;
+ break;
+ }
+ }
+ //ս
+ if ((pre_i < 0) || (post_i < 0))
+ {
+ ptDirAngles[i].pntIdx = i;
+ ptDirAngles[i].type = -1;
+ ptDirAngles[i].forwardAngle = 0;
+ ptDirAngles[i].backwardAngle = 0;
+ ptDirAngles[i].forwardPntIdx = 0;
+ ptDirAngles[i].backwardPntIdx = 0;
+ ptDirAngles[i].corner = 0;
+ ptDirAngles[i].forwardDiffZ = 0;
+ ptDirAngles[i].backwardDiffZ = 0;
+ }
+ else
+ {
+ double tanValue_pre = (line_data[i].pt3D.z - line_data[pre_i].pt3D.z) / abs(line_data[i].pt3D.y - line_data[pre_i].pt3D.y);
+ double tanValue_post = (line_data[post_i].pt3D.z - line_data[i].pt3D.z) / abs(line_data[post_i].pt3D.y - line_data[i].pt3D.y);
+ double forwardAngle = atan(tanValue_post) * 180.0 / PI;
+ double backwardAngle = atan(tanValue_pre) * 180.0 / PI;
+ ptDirAngles[i].pntIdx = i;
+ ptDirAngles[i].forwardPntIdx = post_i;
+ ptDirAngles[i].backwardPntIdx = pre_i;
+ ptDirAngles[i].type = 0;
+ ptDirAngles[i].forwardAngle = forwardAngle;
+ ptDirAngles[i].backwardAngle = backwardAngle;
+ ptDirAngles[i].corner = -(forwardAngle - backwardAngle); //ͼϵϵy෴С-
+ ptDirAngles[i].forwardDiffZ = line_data[post_i].pt3D.z - line_data[i].pt3D.z;
+ ptDirAngles[i].backwardDiffZ = line_data[i].pt3D.z - line_data[pre_i].pt3D.z;
+ }
+ }
+}
+
+///
+/// ȡϵԲϰλԲĿȷ
+/// seg˵㣺z
+/// nPointIdx¶Feature
+/// 㷨̣
+/// 1ǰǺͺ
+/// 2սǣ˳ʱΪʱΪ
+/// 3սǵļֵ
+/// 4жϹսǷΪ
+///
+void wd_getRingArcFeature(
+ std::vector< SVzNL3DPosition>& lineData,
+ int lineIdx,
+ const SSG_cornerParam cornerPara,
+ SVzNLRangeD ringArcWidth, //
+ std::vector& line_ringArcs //
+)
+{
+ int dataSize = (int)lineData.size();
+ //ȥ
+ std::vector< SVzNL3DPosition> vldPts;
+ //std::vector< int> vldPtSegIdx;
+ std::vector segs;
+ std::vector backIndexing;
+ backIndexing.resize(dataSize);
+
+ //zԷֶ
+ _lineDataSegment_zDist(lineData, vldPts, segs, backIndexing, cornerPara);
+ //ǰǺͺ
+ std::vector< SSG_pntDirAngle> ptDirAngles;
+ _computeDirAngle_perSeg(vldPts, segs, cornerPara, ptDirAngles);
//ѰĸcornerΡArcϵÿһ㶼Ǹcorner
int vldPtSize = (int)vldPts.size();
@@ -3594,25 +4049,26 @@ void wd_getRingArcFeature(
int endIdx = -1;
double startAngle = 0;
double endAngle = 0;
+ int segSize = (int)segs.size();
for (int segIdx = 0; segIdx < segSize; segIdx++)
{
int vPtIdxStart = segs[segIdx].start;
int vPtIdxEnd = vPtIdxStart + segs[segIdx].len - 1;
for (int i = vPtIdxStart; i <= vPtIdxEnd; i++)
{
- if (corners[i].corner < 0)
+ if (ptDirAngles[i].corner < 0)
{
if (startIdx < 0)
{
startIdx = i;
endIdx = i;
- startAngle = corners[i].backwardAngle;
- endAngle = corners[i].forwardAngle;
+ startAngle = ptDirAngles[i].backwardAngle;
+ endAngle = ptDirAngles[i].forwardAngle;
}
else
{
endIdx = i;
- endAngle = corners[i].forwardAngle;
+ endAngle = ptDirAngles[i].forwardAngle;
if (i == dataSize - 1)
{
double totalCorner = abs(endAngle - startAngle);
@@ -3631,7 +4087,7 @@ void wd_getRingArcFeature(
SWD_segFeature a_ringFeautre;
memset(&a_ringFeautre, 0, sizeof(SWD_segFeature));
a_ringFeautre.lineIdx = lineIdx;
- if ((corners[preIdx].pntIdx < 0) && (corners[postIdx].pntIdx < 0))
+ if ((ptDirAngles[preIdx].pntIdx < 0) && (ptDirAngles[postIdx].pntIdx < 0))
{
a_ringFeautre.startPt = vldPts[vPtIdxStart].pt3D;
a_ringFeautre.endPt = vldPts[vPtIdxEnd].pt3D;
@@ -3671,7 +4127,7 @@ void wd_getRingArcFeature(
SWD_segFeature a_ringFeautre;
memset(&a_ringFeautre, 0, sizeof(SWD_segFeature));
a_ringFeautre.lineIdx = lineIdx;
- if ((corners[preIdx].pntIdx < 0) && (corners[postIdx].pntIdx < 0))
+ if ((ptDirAngles[preIdx].pntIdx < 0) && (ptDirAngles[postIdx].pntIdx < 0))
{
a_ringFeautre.startPt = vldPts[vPtIdxStart].pt3D;
a_ringFeautre.endPt = vldPts[vPtIdxEnd].pt3D;
@@ -3700,6 +4156,154 @@ void wd_getRingArcFeature(
return;
}
+//˴ǵZPeakвǵǼԳ߶ΪԷΪ
+bool _chkRodArcFeature(
+ int pkIdx, double searchWin,
+ std::vector< SSG_pntDirAngle>& ptDirAngles,
+ std::vector< SVzNL3DPosition>& lineData,
+ const double arcPerPointCornerMinValue, //arcÿתСֵ
+ const double arcTotalCornerMinValue, //ArcתСֵ
+ SSG_intPair& a_rodPos)
+{
+ //pkIdxܻв
+ double realPkCorner = abs(ptDirAngles[pkIdx].forwardAngle + ptDirAngles[pkIdx].backwardAngle);
+ int realPkIdx = pkIdx;
+ //ǰ
+ for (int i = pkIdx - 1; i >= 0; i--)
+ {
+ if (lineData[i].pt3D.z < 1e-4)
+ continue;
+
+ double dist = sqrt(pow(lineData[pkIdx].pt3D.y - lineData[i].pt3D.y, 2) + pow(lineData[pkIdx].pt3D.z - lineData[i].pt3D.z, 2));
+ if (dist > searchWin)
+ break;
+
+ double flatAngle = abs(ptDirAngles[i].forwardAngle + ptDirAngles[i].backwardAngle);
+ if (realPkCorner > flatAngle)
+ {
+ realPkCorner = flatAngle;
+ realPkIdx = i;
+ }
+ }
+ //
+ for (int i = pkIdx + 1; i < (int)lineData.size(); i++)
+ {
+ if (lineData[i].pt3D.z < 1e-4)
+ continue;
+
+ double dist = sqrt(pow(lineData[pkIdx].pt3D.y - lineData[i].pt3D.y, 2) + pow(lineData[pkIdx].pt3D.z - lineData[i].pt3D.z, 2));
+ if (dist > searchWin)
+ break;
+
+ double flatAngle = abs(ptDirAngles[i].forwardAngle + ptDirAngles[i].backwardAngle);
+ if (realPkCorner > flatAngle)
+ {
+ realPkCorner = flatAngle;
+ realPkIdx = i;
+ }
+ }
+
+ if ((ptDirAngles[realPkIdx].forwardAngle > 0) && (ptDirAngles[realPkIdx].backwardAngle < 0) &&
+ (realPkCorner <10) &&(ptDirAngles[realPkIdx].corner < -arcPerPointCornerMinValue)) //ǰΪΪֵȣ<10), սΪֵ10
+ {
+ //ǰ
+ int pre_idx = -1;
+ for (int i = realPkIdx - 1; i >= 0; i--)
+ {
+ if (ptDirAngles[i].type < 0)
+ continue;
+ if (ptDirAngles[i].corner < -arcPerPointCornerMinValue)
+ pre_idx = i;
+ else
+ break;
+ }
+ //
+ int post_idx = -1;
+ for (int i = realPkIdx + 1; i < (int)ptDirAngles.size(); i++)
+ {
+ if (ptDirAngles[i].type < 0)
+ continue;
+ if (ptDirAngles[i].corner < -arcPerPointCornerMinValue)
+ post_idx = i;
+ else
+ break;
+ }
+ if ((pre_idx >= 0) && (post_idx >= 0))
+ {
+ double totalCornerAngle = ptDirAngles[post_idx].forwardAngle - ptDirAngles[pre_idx].backwardAngle;
+ if (totalCornerAngle > arcTotalCornerMinValue) //ԲҪ60ȵ
+ {
+ a_rodPos.idx = realPkIdx;
+ a_rodPos.data_0 = pre_idx;
+ a_rodPos.data_1 = post_idx;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+///
+/// ȡϵԲϰλ
+/// seg˵㣺z
+/// nPointIdx¶Feature
+/// 㷨̣
+/// 1ǰǺͺ
+/// 2ͬĹս
+/// 2Zֵ
+/// 2սǣ˳ʱΪʱΪ
+/// 3սǵļֵ
+/// 4жϹսǷΪ
+///
+///
+void wd_getRodArcFeature_peakCornerMethod(
+ std::vector< SVzNL3DPosition>& lineData,
+ int lineIdx,
+ const double peakChkWin,
+ const SSG_cornerParam cornerPara,
+ std::vector& line_rodArcs //
+)
+{
+ double arcPerPointCornerMinValue = 5; //arcÿתСֵ
+ double arcTotalCornerMinValue = 45; //ArcתСֵ
+ //ǰǺͺ
+ std::vector< SSG_pntDirAngle> ptDirAngles;
+ _computeDirAngle_wholeLine( lineData, cornerPara, ptDirAngles);
+
+ int dataSize = (int)lineData.size();
+ //zֵ
+ std::vector< SSG_basicFeature1D> localZMax;
+ std::vector< SSG_basicFeature1D> localZMin;
+ sg_getLineLocalPeaks_2( lineData, lineIdx, peakChkWin, localZMax, localZMin);
+
+ //Сֵж
+ int peakNum = (int)localZMin.size();
+ for (int i = 0; i < peakNum; i++)
+ {
+ int pkIdx = localZMin[i].jumpPos2D.y;
+ SSG_intPair a_rodPos;
+ bool isArc = _chkRodArcFeature(
+ pkIdx, cornerPara.scale,
+ ptDirAngles, lineData,
+ arcPerPointCornerMinValue, arcTotalCornerMinValue,
+ a_rodPos);
+ if (true == isArc)
+ {
+ SWD_rodArcFeature a_rodArc;
+ memset(&a_rodArc, 0, sizeof(SWD_rodArcFeature));
+ a_rodArc.lineIdx = lineIdx;
+ a_rodArc.startPtIdx = a_rodPos.data_0;
+ a_rodArc.endPtIdx = a_rodPos.data_1;
+ a_rodArc.peakPtIdx = a_rodPos.idx;
+ a_rodArc.startPt = lineData[a_rodPos.data_0].pt3D;
+ a_rodArc.endPt = lineData[a_rodPos.data_1].pt3D;
+ a_rodArc.peakPt = lineData[a_rodPos.idx].pt3D;
+ a_rodArc.featureValue = ptDirAngles[a_rodPos.idx].corner;
+ line_rodArcs.push_back(a_rodArc);
+ }
+ }
+ return;
+}
//ȡcornerֵʵֺʹô˺дŻ
void _searchCornerPeaks(
std::vector< SSG_pntDirAngle>& corners,
@@ -5463,184 +6067,6 @@ void wd_getLineGloveArcs(
return;
}
-///
-/// ȡϵļֵ㣨ֵͼСֵ㣩
-///
-///
-void sg_getLineLocalPeaks(
- SVzNL3DPosition* lineData,
- int dataSize,
- int lineIdx,
- const double scaleWin,
- std::vector< SSG_basicFeature1D>& localMax,
- std::vector< SSG_basicFeature1D>& localMin)
-{
- if (dataSize < 2)
- return;
-
- int _state = 0;
- int pre_i = -1;
- int sEdgePtIdx = -1;
- int eEdgePtIdx = -1;
- SVzNL3DPosition* pre_data = NULL;
- std::vector< SVzNL3DPosition> pkTop;
- std::vector< SVzNL3DPosition> pkBtm;
- for (int i = 0; i < dataSize; i++)
- {
- lineData[i].nPointIdx = i;
- SVzNL3DPosition* curr_data = &lineData[i];
- if (curr_data->pt3D.z < 1e-4)
- {
- if (i == dataSize - 1) //һ
- {
- if ( 1 == _state ) //
- {
- pkTop.push_back(lineData[eEdgePtIdx]);
- }
- else if (2 == _state) //½
- {
- pkBtm.push_back(lineData[eEdgePtIdx]);
- }
- }
- continue;
- }
-
- if (NULL == pre_data)
- {
- sEdgePtIdx = i;
- eEdgePtIdx = i;
- pre_data = curr_data;
- pre_i = i;
- continue;
- }
-
- eEdgePtIdx = i;
- double z_diff = curr_data->pt3D.z - pre_data->pt3D.z;
- switch (_state)
- {
- case 0: //̬
- if (z_diff > 0) //½
- {
- _state = 2;
- }
- else if (z_diff < 0) //
- {
- _state = 1;
- }
- break;
- case 1: //
- if (z_diff > 0) //½
- {
- pkTop.push_back(*pre_data);
- _state = 2;
- }
- break;
- case 2: //½
- if (z_diff < 0) //
- {
- pkBtm.push_back(*pre_data);
- _state = 1;
- }
- break;
- default:
- _state = 0;
- break;
- }
- pre_data = curr_data;
- pre_i = i;
- }
- //ע⣺һΪλ
-
- //Сֵ㣨嶥
- //ֵȽϣڳ߶ȴѰҾֲֵ
- double square_distTh = scaleWin * scaleWin;
- for (int i = 0, i_max = (int)pkTop.size(); i < i_max; i++)
- {
- bool isPeak = true;
- //ǰ
- for (int j = i - 1; j >= 0; j--)
- {
- double dist = pow(pkTop[i].pt3D.y - pkTop[j].pt3D.y, 2); // + pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2) ;
- if (dist > square_distTh) //߶ȴ
- break;
-
- if (pkTop[i].pt3D.z > pkTop[j].pt3D.z)
- {
- isPeak = false;
- break;
- }
- }
- //
- if (true == isPeak)
- {
- for (int j = i + 1; j < i_max; j++)
- {
- double dist = pow(pkTop[i].pt3D.y - pkTop[j].pt3D.y, 2); // +pow(pkTop[i].pt3D.x - pkTop[j].pt3D.x, 2);
- if (dist > square_distTh) //߶ȴ
- break;
-
- if (pkTop[i].pt3D.z > pkTop[j].pt3D.z)
- {
- isPeak = false;
- break;
- }
- }
- }
- if (true == isPeak)
- {
- SSG_basicFeature1D a_feature;
- a_feature.featureType = LINE_FEATURE_PEAK_TOP;
- a_feature.jumpPos = pkTop[i].pt3D;
- a_feature.jumpPos2D = { lineIdx, pkTop[i].nPointIdx };
- localMin.push_back(a_feature);
- }
- }
- //ֵ㣨ȵף
- for (int i = 0, i_max = (int)pkBtm.size(); i < i_max; i++)
- {
- bool isPeak = true;
- //ǰ
- for (int j = i - 1; j >= 0; j--)
- {
- double dist = pow(pkBtm[i].pt3D.y - pkBtm[j].pt3D.y, 2); // +pow(pkBtm[i].pt3D.x - pkBtm[j].pt3D.x, 2);
- if (dist > square_distTh) //߶ȴ
- break;
-
- if (pkBtm[i].pt3D.z < pkBtm[j].pt3D.z)
- {
- isPeak = false;
- break;
- }
- }
- //
- if (true == isPeak)
- {
- for (int j = i + 1; j < i_max; j++)
- {
- double dist = pow(pkBtm[i].pt3D.y - pkBtm[j].pt3D.y, 2); // +pow(pkBtm[i].pt3D.x - pkBtm[j].pt3D.x, 2);
- if (dist > square_distTh) //߶ȴ
- break;
-
- if (pkBtm[i].pt3D.z < pkBtm[j].pt3D.z)
- {
- isPeak = false;
- break;
- }
- }
- }
- if (true == isPeak)
- {
- SSG_basicFeature1D a_feature;
- a_feature.featureType = LINE_FEATURE_PEAK_BOTTOM;
- a_feature.jumpPos = pkBtm[i].pt3D;
- a_feature.jumpPos2D = { lineIdx, pkBtm[i].nPointIdx };
- localMax.push_back(a_feature);
- }
- }
-
- return;
-}
-
#if 0
typedef struct
{
diff --git a/sourceCode/rodAndBarDetection.cpp b/sourceCode/rodAndBarDetection.cpp
index 1d466aa..e5e4e26 100644
--- a/sourceCode/rodAndBarDetection.cpp
+++ b/sourceCode/rodAndBarDetection.cpp
@@ -6,12 +6,44 @@
#include
//version 1.0.0 : base version release to customer
-std::string m_strVersion = "1.0.0";
+//version 1.1.0 : ˵ƽͰĶλ
+std::string m_strVersion = "1.1.0";
const char* wd_rodAndBarDetectionVersion(void)
{
return m_strVersion.c_str();
}
+//һƽƽ
+//пһƽͲοƽƽ棬ߵƽеƽ
+//תΪƽƽ淨ΪֱIJ
+SSG_planeCalibPara sx_rodPosition_getBaseCalibPara(
+ std::vector< std::vector>& scanLines)
+{
+ return sg_getPlaneCalibPara2(scanLines);
+}
+
+//̬ƽȥ
+void sx_rodPosition_lineDataR(
+ std::vector< SVzNL3DPosition>& a_line,
+ const double* camPoseR,
+ double groundH)
+{
+ lineDataRT_vector(a_line, camPoseR, groundH);
+}
+
+SVzNL3DPoint _translatePoint(SVzNL3DPoint point, const double rMatrix[9])
+{
+ SVzNL3DPoint result;
+ double x = point.x * rMatrix[0] + point.y * rMatrix[1] + point.z * rMatrix[2];
+ double y = point.x * rMatrix[3] + point.y * rMatrix[4] + point.z * rMatrix[5];
+ double z = point.x * rMatrix[6] + point.y * rMatrix[7] + point.z * rMatrix[8];
+ result.x = x;
+ result.y = y;
+ result.z = z;
+ return result;
+}
+
+
SVzNL3DPoint getArcPeak(
std::vector< std::vector>& scanLines,
SWD_segFeature & a_arcFeature,
@@ -420,5 +452,235 @@ SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
}
+void rodAarcFeatueDetection(
+ std::vector< std::vector>& scanLines,
+ const SSG_cornerParam cornerPara,
+ const SSG_outlierFilterParam filterParam,
+ const double rodDiameter,
+ std::vector>& arcFeatures)
+{
+ int lineNum = (int)scanLines.size();
+ int linePtNum = (int)scanLines[0].size();
+ for (int line = 0; line < lineNum; line++)
+ {
+ if (line == 424)
+ int kkk = 1;
+ std::vector& lineData = scanLines[line];
+
+ //˲˳쳣
+ sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], linePtNum, filterParam);
+ //ȡrodArc
+ std::vector line_rodArcs;
+ wd_getRodArcFeature_peakCornerMethod(lineData, line, rodDiameter/2, cornerPara, line_rodArcs );
+ arcFeatures.push_back(line_rodArcs);
+ }
+ return;
+}
+
+void sx_rodPositioning(
+ 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& rodInfo,
+ 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;
+ }
+ }
+ //Ŀж
+ //(1)ȹ
+ for (int i = 0; i < (int)rodArcTrees_v.size(); i++)
+ {
+ int nodeSize = rodArcTrees_v[i].treeNodes.size();
+ SVzNL3DPoint startCenter = rodArcTrees_v[i].treeNodes[0].peakPt;
+ SVzNL3DPoint endCenter = rodArcTrees_v[i].treeNodes[nodeSize-1].peakPt;
+ double len = sqrt(pow(startCenter.x - endCenter.x, 2) +
+ pow(startCenter.y - endCenter.y, 2) +
+ pow(startCenter.z - endCenter.z, 2));
+ double lenDiff = abs(len - rodParam.len);
+ if (lenDiff < 10.0) //validObj
+ {
+ //XYƽֱ
+ //Ϊ˷ֹ˲Ӱ죬
+ std::vector fittingPoints;
+ for (int j = 0; j < nodeSize; j++)
+ {
+ double dist1 = sqrt(pow(rodArcTrees_v[i].treeNodes[j].peakPt.x - startCenter.x, 2) +
+ pow(rodArcTrees_v[i].treeNodes[j].peakPt.y - startCenter.y, 2) +
+ pow(rodArcTrees_v[i].treeNodes[j].peakPt.z - startCenter.z, 2));
+ double dist2 = sqrt(pow(rodArcTrees_v[i].treeNodes[j].peakPt.x - endCenter.x, 2) +
+ pow(rodArcTrees_v[i].treeNodes[j].peakPt.y - endCenter.y, 2) +
+ pow(rodArcTrees_v[i].treeNodes[j].peakPt.z - endCenter.z, 2));
+ if ((dist1 > rodParam.diameter / 2) && (dist2 > rodParam.diameter / 2))
+ fittingPoints.push_back(rodArcTrees_v[i].treeNodes[j].peakPt);
+ }
+ if (fittingPoints.size() < 3)
+ continue;
+ //
+ double _a, _b, _c;
+ lineFitting_abc(fittingPoints, &_a, &_b, &_c);
+ int dataSize = (int)fittingPoints.size();
+ SVzNL2DPointD foot1 = sx_getFootPoint_abc(fittingPoints[0].x, fittingPoints[0].y, _a, _b, _c);
+ SVzNL2DPointD foot2 = sx_getFootPoint_abc(fittingPoints[dataSize - 1].x, fittingPoints[dataSize - 1].y, _a, _b, _c);
+ //ֱߵ
+ SVzNL3DPoint axialDir = { foot2.x - foot1.x, foot2.y - foot1.y, fittingPoints[dataSize - 1].z - fittingPoints[0].z };
+ double theta = atan2(foot2.y - foot1.y, foot2.x - foot1.x);
+ double sinTheta = sin(theta);
+ double cosTheta = cos(theta);
+ SVzNL3DPoint tmpDir = { sinTheta, -cosTheta, 0 };
+ SVzNL3DPoint normalDir = { axialDir.y * tmpDir.z - tmpDir.y * axialDir.z,
+ axialDir.z * tmpDir.x - tmpDir.z * axialDir.x,
+ axialDir.x * tmpDir.y - tmpDir.x * axialDir.y };
+
+ SSX_rodPositionInfo a_objRod;
+ //ȷյ㣺ֱ߾С5mm
+ double tmpData = sqrt(_a * _a + _b * _b);
+ _a = _a / tmpData;
+ _b = _b / tmpData;
+ _c = _c / tmpData;
+ SVzNL3DPoint realStart, realEnd;
+ bool foundStart = false;
+ for (int j = 0; j < nodeSize; j++)
+ {
+ double dist = abs(rodArcTrees_v[i].treeNodes[j].peakPt.x * _a +
+ rodArcTrees_v[i].treeNodes[j].peakPt.y * _b + _c);
+ if (dist < 5.0)
+ {
+ realStart = rodArcTrees_v[i].treeNodes[j].peakPt;
+ foundStart = true;
+ break;
+ }
+ }
+
+
+ }
+ }
+ //2ڵж
+
+
+
+ //ͶԭϵԱ۱궨ȷ
+ for (int i = 0; i < lineNum; i++)
+ sx_rodPosition_lineDataR(scanLines[i], poseCalibPara.invRMatrix, -1);
+ //Ͷԭϵ
+ for (int i = 0; i < (int)rodInfo.size(); i++)
+ {
+ SSX_rodPositionInfo& a_rod = rodInfo[i];
+ SVzNL3DPoint rawObj = _translatePoint(a_rod.center, poseCalibPara.invRMatrix);
+ a_rod.center = rawObj;
+ rawObj = _translatePoint(a_rod.axialDir, poseCalibPara.invRMatrix);
+ a_rod.axialDir = rawObj;
+ rawObj = _translatePoint(a_rod.normalDir, poseCalibPara.invRMatrix);
+ a_rod.normalDir = rawObj;
+ }
+ return;
+}
+
diff --git a/sourceCode/rodAndBarDetection_Export.h b/sourceCode/rodAndBarDetection_Export.h
index 8b1a0fa..1c496bb 100644
--- a/sourceCode/rodAndBarDetection_Export.h
+++ b/sourceCode/rodAndBarDetection_Export.h
@@ -12,9 +12,38 @@ typedef struct
double rotateAngle; //-30 - 30
}SSX_hexHeadScrewInfo; //ͷݸ
+typedef struct
+{
+ double diameter;
+ double len;
+}SSX_rodParam; //Ϣ
+
+typedef struct
+{
+ SVzNL3DPoint center; //ݸ˶˲ĵ
+ SVzNL3DPoint axialDir; //
+ SVzNL3DPoint normalDir; //
+ SVzNL3DPoint startPt;
+ SVzNL3DPoint endPt;
+}SSX_rodPositionInfo;
+
//汾
SG_APISHARED_EXPORT const char* wd_rodAndBarDetectionVersion(void);
+//һƽƽ
+//пһƽͲοƽƽ棬ߵƽеƽ
+//תΪƽƽ淨ΪֱIJ
+SG_APISHARED_EXPORT SSG_planeCalibPara sx_rodPosition_getBaseCalibPara(
+ std::vector< std::vector>& scanLines);
+
+#if 0
+//̬ƽȥ
+SG_APISHARED_EXPORT void sx_rodPosition_lineDataR(
+ std::vector< SVzNL3DPosition>& a_line,
+ const double* camPoseR,
+ double groundH);
+#endif
+
//ͷݸ˶˲ĵ
SG_APISHARED_EXPORT void sx_hexHeadScrewMeasure(
std::vector< std::vector>& scanLines,
@@ -25,3 +54,13 @@ SG_APISHARED_EXPORT void sx_hexHeadScrewMeasure(
double rodDiameter,
std::vector& screwInfo,
int* errCode);
+
+SG_APISHARED_EXPORT void sx_rodPositioning(
+ 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& rodInfo,
+ int* errCode);
\ No newline at end of file