SX_lapWeldDetection

version 1.1.0 :焊缝(平缝)识别修正回归测试中发现的bug
This commit is contained in:
jerryzeng 2026-08-15 22:34:05 +08:00
parent 881f8f9b0a
commit 2d145399fd
3 changed files with 75 additions and 19 deletions

View File

@ -999,17 +999,34 @@ void sg_cornerFeaturesGrowing(
} }
} }
bool _gapTreeMatch(SSG_basicFeatureGap& a_gap, SSG_gapFeatureTree& a_tree, const SSG_treeGrowParam growParam, double* yDeviation) bool _gapTreeMatch(SSG_basicFeatureGap& a_gap, SSG_gapFeatureTree& a_tree, const SSG_treeGrowParam growParam, double* yDeviation, int meanValueWin=5)
{ {
//检查生长点 //检查生长点
SSG_basicFeatureGap last_node = a_tree.treeNodes.back(); SSG_basicFeatureGap last_node = a_tree.treeNodes.back();
double last_cx = (last_node.gapPt_0.pt3D.x + last_node.gapPt_1.pt3D.x) / 2; #if 1
double last_cy = (last_node.gapPt_0.pt3D.y + last_node.gapPt_1.pt3D.y) / 2; //È¡×îºó5¸öµãµÄƽ¾ù
double last_cz = (last_node.gapPt_0.pt3D.z + last_node.gapPt_1.pt3D.z) / 2; int lastNodeIdx = (int)a_tree.treeNodes.size() - 1;
int sumNum = 0;
double last_cy = 0;
for (int i = 0; i < meanValueWin; i++)
{
last_cy += a_tree.treeNodes[lastNodeIdx].gapPeak.pt3D.y;
sumNum++;
lastNodeIdx--;
if (lastNodeIdx < 0)
break;
}
last_cy = last_cy / sumNum;
#else
double last_cy = last_node.gapPeak.pt3D.y; //(last_node.gapPt_0.pt3D.y + last_node.gapPt_1.pt3D.y) / 2;
#endif
double last_cx = last_node.gapPeak.pt3D.x; // (last_node.gapPt_0.pt3D.x + last_node.gapPt_1.pt3D.x) / 2;
double last_cz = last_node.gapPeak.pt3D.z; // (last_node.gapPt_0.pt3D.z + last_node.gapPt_1.pt3D.z) / 2;
//判断生长点 //判断生长点
double curr_cx = (a_gap.gapPt_0.pt3D.x + a_gap.gapPt_1.pt3D.x) / 2; double curr_cx = a_gap.gapPeak.pt3D.x;// (a_gap.gapPt_0.pt3D.x + a_gap.gapPt_1.pt3D.x) / 2;
double curr_cy = (a_gap.gapPt_0.pt3D.y + a_gap.gapPt_1.pt3D.y) / 2; double curr_cy = a_gap.gapPeak.pt3D.y;// (a_gap.gapPt_0.pt3D.y + a_gap.gapPt_1.pt3D.y) / 2;
double curr_cz = (a_gap.gapPt_0.pt3D.z + a_gap.gapPt_1.pt3D.z) / 2; double curr_cz = a_gap.gapPeak.pt3D.z;// (a_gap.gapPt_0.pt3D.z + a_gap.gapPt_1.pt3D.z) / 2;
double y_diff = abs(curr_cy - last_cy); double y_diff = abs(curr_cy - last_cy);
double z_diff = abs(curr_cz - last_cz); double z_diff = abs(curr_cz - last_cz);
int line_diff = abs(a_gap.lineIdx - last_node.lineIdx); int line_diff = abs(a_gap.lineIdx - last_node.lineIdx);
@ -1146,6 +1163,8 @@ void sg_lineGapsGrowing_treeFirst(
for (int i = 0; i < (int)trees.size(); i++) for (int i = 0; i < (int)trees.size(); i++)
{ {
SSG_gapFeatureTree& a_tree = trees[i]; SSG_gapFeatureTree& a_tree = trees[i];
if (a_tree.treeState == TREE_STATE_DEAD)
continue;
int bestMatchLeafId = -1; int bestMatchLeafId = -1;
double minYDiff = -1; double minYDiff = -1;
@ -1173,6 +1192,9 @@ void sg_lineGapsGrowing_treeFirst(
} }
} }
} }
if ((lineIdx == 286) && (bestMatchLeafId == 3))
int kkk = 1;
if(bestMatchLeafId >= 0) if(bestMatchLeafId >= 0)
{ {
a_tree.eLineIdx = lineIdx; a_tree.eLineIdx = lineIdx;

View File

@ -9734,7 +9734,7 @@ void _valleyDetect(
int realPeakPos = preEdge; int realPeakPos = preEdge;
for (int m = preEdge; m <= postEdge; m++) for (int m = preEdge; m <= postEdge; m++)
{ {
if ((a_line[realPeakPos].pt3D.z > a_line[m].pt3D.z) && (a_line[m].nPointIdx >= 0)) if ((a_line[realPeakPos].pt3D.z < a_line[m].pt3D.z) && (a_line[m].nPointIdx >= 0))
realPeakPos = m; realPeakPos = m;
} }
@ -9768,6 +9768,9 @@ void wd_getLineVFlaws(
const SWD_valleyParam valleyParam, const SWD_valleyParam valleyParam,
std::vector< SSG_basicFeatureGap>& valleys) std::vector< SSG_basicFeatureGap>& valleys)
{ {
if (lineIdx == 286)
int kkk = 1;
//处理栅格数据(填补空洞,统计有效点 //处理栅格数据(填补空洞,统计有效点
int startId = -1, endId = 0; int startId = -1, endId = 0;
for (int i = 0; i < (int)a_line.size(); i++) for (int i = 0; i < (int)a_line.size(); i++)

View File

@ -6,7 +6,9 @@
#include <limits> #include <limits>
//version 1.0.0 :焊缝(平缝)识别检测算法初始发布 //version 1.0.0 :焊缝(平缝)识别检测算法初始发布
std::string m_strVersion = "weldSeamAlgo_1.0.0"; //version 1.1.0 :焊缝(平缝)识别修正回归测试中发现的bug
std::string m_strVersion = "weldSeamAlgo_1.1.0";
const char* wd_weldSeamAlgoVersion(void) const char* wd_weldSeamAlgoVersion(void)
{ {
return m_strVersion.c_str(); return m_strVersion.c_str();
@ -432,6 +434,25 @@ double _getMeanZ(std::vector<double>& ptZ)
return meanZ; return meanZ;
} }
double _getNearestZ(std::vector<SVzNL3DPoint>& pts, double refx)
{
if (pts.size() == 0)
return 0;
double minDist = abs(pts[0].x - refx);
double bestZ = pts[0].z;
for (int i = 1; i < (int)pts.size(); i++)
{
double xDist = abs(pts[i].x = refx);
if (minDist > xDist)
{
minDist = xDist;
bestZ = pts[i].z;
}
}
return bestZ;
}
bool _compareByXValue(const SVzNL3DPoint& a, const SVzNL3DPoint& b) { bool _compareByXValue(const SVzNL3DPoint& a, const SVzNL3DPoint& b) {
return a.x < b.x; return a.x < b.x;
} }
@ -445,6 +466,12 @@ void BQ_getWeldSeamPose(
{ {
*errCode = 0; *errCode = 0;
if (trees.size() == 0)
{
*errCode = SX_ERR_ZERO_OBJECTS;
return;
}
//保留最长的tree //保留最长的tree
int bestId = 0; int bestId = 0;
trees[0].treeState = 0; trees[0].treeState = 0;
@ -506,9 +533,9 @@ void BQ_getWeldSeamPose(
int refSegNum = weldRefPoints + 1; int refSegNum = weldRefPoints + 1;
refSegNum = refSegNum * 2; //以段长一半进行区分 refSegNum = refSegNum * 2; //以段长一半进行区分
std::vector<std::vector<SVzNL3DPoint>> refSegments; std::vector<std::vector<SVzNL3DPoint>> refSegments;
std::vector<std::vector<double>> refSegZ; std::vector<std::vector<SVzNL3DPoint>> refSegValleyPt;
refSegments.resize(refSegNum); refSegments.resize(refSegNum);
refSegZ.resize(refSegNum); refSegValleyPt.resize(refSegNum);
SVzNLRangeD xRange = _getTreesXRange(weldSeam); SVzNLRangeD xRange = _getTreesXRange(weldSeam);
double segLen = (xRange.max - xRange.min) / refSegNum; double segLen = (xRange.max - xRange.min) / refSegNum;
for (int i = 0; i < (int)weldSeam.size(); i++) for (int i = 0; i < (int)weldSeam.size(); i++)
@ -525,7 +552,10 @@ void BQ_getWeldSeamPose(
segIdx = refSegNum - 1; segIdx = refSegNum - 1;
refSegments[segIdx].push_back(weldSeam[i].treeNodes[j].gapPeak.pt3D); refSegments[segIdx].push_back(weldSeam[i].treeNodes[j].gapPeak.pt3D);
double valleyZ = (weldSeam[i].treeNodes[j].gapPt_0.pt3D.z + weldSeam[i].treeNodes[j].gapPt_1.pt3D.z) / 2; double valleyZ = (weldSeam[i].treeNodes[j].gapPt_0.pt3D.z + weldSeam[i].treeNodes[j].gapPt_1.pt3D.z) / 2;
refSegZ[segIdx].push_back(valleyZ); double valleyX = (weldSeam[i].treeNodes[j].gapPt_0.pt3D.x + weldSeam[i].treeNodes[j].gapPt_1.pt3D.x) / 2;
double valleyY = (weldSeam[i].treeNodes[j].gapPt_0.pt3D.y + weldSeam[i].treeNodes[j].gapPt_1.pt3D.y) / 2;
SVzNL3DPoint a_valley = { valleyX , valleyY, valleyZ };
refSegValleyPt[segIdx].push_back(a_valley);
} }
} }
//分段按X大小排序 //分段按X大小排序
@ -540,16 +570,16 @@ void BQ_getWeldSeamPose(
int segIdx_0 = i * 2 - 1; int segIdx_0 = i * 2 - 1;
int segIdx_1 = i * 2; int segIdx_1 = i * 2;
std::vector<SVzNL3DPoint> fittingPoints; std::vector<SVzNL3DPoint> fittingPoints;
std::vector<double> fittingPtZ; std::vector<SVzNL3DPoint> fittingValleyPt;
if (segIdx_0 >= 0) if (segIdx_0 >= 0)
{ {
fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_0].begin(), refSegments[segIdx_0].end()); //左半段 fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_0].begin(), refSegments[segIdx_0].end()); //左半段
fittingPtZ.insert(fittingPtZ.end(), refSegZ[segIdx_0].begin(), refSegZ[segIdx_0].end()); fittingValleyPt.insert(fittingValleyPt.end(), refSegValleyPt[segIdx_0].begin(), refSegValleyPt[segIdx_0].end());
} }
if (segIdx_1 < refSegNum) if (segIdx_1 < refSegNum)
{ {
fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_1].begin(), refSegments[segIdx_1].end()); //右半段 fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_1].begin(), refSegments[segIdx_1].end()); //右半段
fittingPtZ.insert(fittingPtZ.end(), refSegZ[segIdx_1].begin(), refSegZ[segIdx_1].end()); fittingValleyPt.insert(fittingValleyPt.end(), refSegValleyPt[segIdx_1].begin(), refSegValleyPt[segIdx_1].end());
} }
while (fittingPoints.size() < 10) //保证足够的拟合点 while (fittingPoints.size() < 10) //保证足够的拟合点
{ {
@ -559,13 +589,13 @@ void BQ_getWeldSeamPose(
if (segIdx_0 >= 0) if (segIdx_0 >= 0)
{ {
fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_0].begin(), refSegments[segIdx_0].end()); fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_0].begin(), refSegments[segIdx_0].end());
fittingPtZ.insert(fittingPtZ.end(), refSegZ[segIdx_0].begin(), refSegZ[segIdx_0].end()); fittingValleyPt.insert(fittingValleyPt.end(), refSegValleyPt[segIdx_0].begin(), refSegValleyPt[segIdx_0].end());
} }
segIdx_1++; segIdx_1++;
if (segIdx_1 < refSegNum) if (segIdx_1 < refSegNum)
{ {
fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_1].begin(), refSegments[segIdx_1].end()); fittingPoints.insert(fittingPoints.end(), refSegments[segIdx_1].begin(), refSegments[segIdx_1].end());
fittingPtZ.insert(fittingPtZ.end(), refSegZ[segIdx_1].begin(), refSegZ[segIdx_1].end()); fittingValleyPt.insert(fittingValleyPt.end(), refSegValleyPt[segIdx_1].begin(), refSegValleyPt[segIdx_1].end());
} }
if (oldSize == (int)fittingPoints.size()) if (oldSize == (int)fittingPoints.size())
break; break;
@ -573,13 +603,14 @@ void BQ_getWeldSeamPose(
//直线拟合 //直线拟合
double _a, _b, _c; double _a, _b, _c;
lineFitting_abc(fittingPoints, &_a, &_b, &_c); lineFitting_abc(fittingPoints, &_a, &_b, &_c);
double meanZ = _getMeanZ(fittingPtZ);
double x = segLen * i * 2.0 + xRange.min; double x = segLen * i * 2.0 + xRange.min;
double y = -(_a * x + _c) / _b; double y = -(_a * x + _c) / _b;
double nearestZ = _getNearestZ(fittingValleyPt, x); //_getMeanZ(fittingPtZ);
SVzNL3DPoint a_pt; SVzNL3DPoint a_pt;
a_pt.x = x; a_pt.x = x;
a_pt.y = y; a_pt.y = y;
a_pt.z = meanZ; a_pt.z = nearestZ;
weldOps.push_back(a_pt); weldOps.push_back(a_pt);
} }
return; return;