rodAndBarDetection

version 1.5.0 : 矩森棒材抓取算法改进:加强了对强噪声点云的处理
This commit is contained in:
jerryzeng 2026-08-23 10:51:42 +08:00
parent 0dc9a4904e
commit 8d49089a57
5 changed files with 572 additions and 34 deletions

View File

@ -724,6 +724,9 @@ void _outputRGBDScan_RGBD_rodInfo(
for (int i = 0; i < linePtNum; i++)
{
SVzNL3DPosition* pt3D = &scanLines[line][i];
if (pt3D->pt3D.z < 1e-4)
pt3D->pt3D = { 0.0, 0.0, 0.0 };
if (pt3D->nPointIdx > 0)
{
int centerFlag = pt3D->nPointIdx >> 4;
@ -737,8 +740,6 @@ void _outputRGBDScan_RGBD_rodInfo(
rgb = objColor[pt3D->nPointIdx % 8];
size = 2;
}
}
else //if (pt3D->nPointIdx == 0)
{
@ -756,7 +757,10 @@ void _outputRGBDScan_RGBD_rodInfo(
if (objNum > 0)
{
sw << "Line_" << lineIdx << "_0_" << objNum << std::endl;
int lastLineNum = objNum;
if (objNum < (int)scanLines[0].size())
lastLineNum = (int)scanLines[0].size();
sw << "Line_" << lineIdx << "_0_" << lastLineNum << std::endl;
size = 12;
for (int i = 0; i < objNum; i++)
{
@ -771,6 +775,10 @@ void _outputRGBDScan_RGBD_rodInfo(
sw << "{0,0}-{0,0}-";
sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
}
for (int i = objNum; i < (int)scanLines[0].size(); i++)
{
sw << "{0,0,0}-{0,0}-{0,0}-{0,0,0,1 }" << std::endl;
}
//输出法向
size = 8;
double len = 60;
@ -1315,7 +1323,218 @@ void _convertToGridData_XYZRGB(std::vector<std::vector< SVzNLPointXYZRGBA>>& sca
return;
}
#define ROD_POSITION_TEST_GROUP 6
void EulerRpyToRotation1(const double rpy[3], double matrix3d[9]) {
double cos0 = cos(rpy[0] * PI / 180);
double sin0 = sin(rpy[0] * PI / 180);
double cos1 = cos(rpy[1] * PI / 180);
double sin1 = sin(rpy[1] * PI / 180);
double cos2 = cos(rpy[2] * PI / 180);
double sin2 = sin(rpy[2] * PI / 180);
matrix3d[0] = cos2 * cos1;
matrix3d[1] = cos2 * sin1 * sin0 - sin2 * cos0;
matrix3d[2] = cos2 * sin1 * cos0 + sin2 * sin0;
matrix3d[3] = sin2 * cos1;
matrix3d[4] = sin2 * sin1 * sin0 + cos2 * cos0;
matrix3d[5] = sin2 * sin1 * cos0 - cos2 * sin0;
matrix3d[6] = -sin1;
matrix3d[7] = cos1 * sin0;
matrix3d[8] = cos1 * cos0;
return;
}
SVzNL3DPoint _ptRotate(SVzNL3DPoint pt3D, double matrix3d[9])
{
SVzNL3DPoint _r_pt;
_r_pt.x = pt3D.x * matrix3d[0] + pt3D.y * matrix3d[1] + pt3D.z * matrix3d[2];
_r_pt.y = pt3D.x * matrix3d[3] + pt3D.y * matrix3d[4] + pt3D.z * matrix3d[5];
_r_pt.z = pt3D.x * matrix3d[6] + pt3D.y * matrix3d[7] + pt3D.z * matrix3d[8];
return _r_pt;
}
void _rotateCloudPts(
std::vector<std::vector< SVzNL3DPosition>>& scanLines,
double matrix3d[9],
std::vector<std::vector< SVzNL3DPosition>>& rotateLines,
SVzNLRangeD& rx_range, SVzNLRangeD& ry_range)
{
int lineNum = (int)scanLines.size();
rotateLines.resize(lineNum);
rx_range.min = 0;
rx_range.max = -1;
ry_range.min = 0;
ry_range.max = -1;
for (int line = 0; line < lineNum; line++)
{
for (int i = 0; i < (int)scanLines[line].size(); i++)
{
SVzNL3DPosition& pt3D = scanLines[line][i];
if (pt3D.pt3D.z < 1e-4)
continue;
SVzNL3DPosition r_pt;
r_pt.pt3D = _ptRotate(pt3D.pt3D, matrix3d);
r_pt.nPointIdx = pt3D.nPointIdx;
rotateLines[line].push_back(r_pt);
if (rx_range.max < rx_range.min)
{
rx_range.min = r_pt.pt3D.x;
rx_range.max = r_pt.pt3D.x;
}
else
{
if (rx_range.min > r_pt.pt3D.x)
rx_range.min = r_pt.pt3D.x;
if (rx_range.max < r_pt.pt3D.x)
rx_range.max = r_pt.pt3D.x;
}
if (ry_range.max < ry_range.min)
{
ry_range.min = r_pt.pt3D.y;
ry_range.max = r_pt.pt3D.y;
}
else
{
if (ry_range.min > r_pt.pt3D.y)
ry_range.min = r_pt.pt3D.y;
if (ry_range.max < r_pt.pt3D.y)
ry_range.max = r_pt.pt3D.y;
}
}
}
}
void _XOYprojection_rodInfo(
cv::Mat& img,
std::vector<std::vector< SVzNL3DPosition>>& dataLines,
std::vector<SSX_rodPositionInfo>& rodInfo,
const double scale,
const int sideWidth,
const SVzNLRangeD x_range,
const SVzNLRangeD y_range,
const double dirAngleLen)
{
cv::Vec3b rgb = cv::Vec3b(0, 0, 0);
cv::Vec3b 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;
for (int line = 0; line < dataLines.size(); line++)
{
std::vector< SVzNL3DPosition>& a_line = dataLines[line];
for (int i = 0; i < a_line.size(); i++)
{
SVzNL3DPosition& pt3D = a_line[i];
if (pt3D.pt3D.z < 1e-4)
continue;
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 = { 250, 250, 250 };
size = 1;
}
double x = pt3D.pt3D.x;
double y = pt3D.pt3D.y;
int px = (int)((x - x_range.min) / scale + sideWidth);
int py = (int)((y - y_range.min) / scale + sideWidth);
if (size == 1)
img.at<cv::Vec3b>(py, px) = cv::Vec3b(rgb[2], rgb[1], rgb[0]);
else
cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
}
}
if (rodInfo.size() > 0)
{
for (int i = 0; i < (int)rodInfo.size(); i++)
{
if (i == 0)
rgb = { 255, 255, 0 };
else
rgb = { 255, 0, 0 };
size = int(10.0 / scale);
int px = (int)((rodInfo[i].center.x - x_range.min) / scale + sideWidth);
int py = (int)((rodInfo[i].center.y - y_range.min) / scale + sideWidth);
cv::circle(img, cv::Point(px, py), size, cv::Scalar(rgb[2], rgb[1], rgb[0]), -1);
//画圆
int px1 = (int)((rodInfo[i].startPt.x - x_range.min) / scale + sideWidth);
int py1 = (int)((rodInfo[i].startPt.y - y_range.min) / scale + sideWidth);
int px2 = (int)((rodInfo[i].endPt.x - x_range.min) / scale + sideWidth);
int py2 = (int)((rodInfo[i].endPt.y - y_range.min) / scale + sideWidth);
size = int(5.0 / scale);
if (size == 0)
size = 1;
cv::line(img, cv::Point(px1, py1), cv::Point(px2, py2), cv::Scalar(rgb[2], rgb[1], rgb[0]), size);
}
}
}
void _genXOYProjectionImage_rodInfo(
cv::String& fileName,
std::vector<std::vector< SVzNL3DPosition>>& scanLines,
const double scale,
std::vector<SSX_rodPositionInfo>& rodInfo,
const double rpy[3], const double dirLen)
{
//旋转视角显示
double matrix3d[9];
EulerRpyToRotation1(rpy, matrix3d);
std::vector<SSX_rodPositionInfo> rotatedRod;
for (int i = 0; i < (int)rodInfo.size(); i++)
{
SSX_rodPositionInfo rotateObj;
rotateObj.center = _ptRotate(rodInfo[i].center, matrix3d);
rotateObj.axialDir = _ptRotate(rodInfo[i].axialDir, matrix3d);
rotateObj.normalDir = _ptRotate(rodInfo[i].normalDir, matrix3d);
rotateObj.startPt = _ptRotate(rodInfo[i].startPt, matrix3d);
rotateObj.endPt = _ptRotate(rodInfo[i].endPt, matrix3d);
rotatedRod.push_back(rotateObj);
}
std::vector<std::vector< SVzNL3DPosition>> rotateLines;
SVzNLRangeD rx_range, ry_range;
_rotateCloudPts(scanLines, matrix3d, rotateLines, rx_range, ry_range);
//统计X和Y的范围
int x_cols = (int)((rx_range.max - rx_range.min) / scale) + 1;
if (x_cols % 2 == 1)
x_cols += 1;
int y_rows = (int)((ry_range.max - ry_range.min) / scale) + 1;
if (y_rows % 2 == 1)
y_rows += 1;
int sideWidth = 32;
int imgCols = x_cols + sideWidth * 2;
int imgRows = y_rows + sideWidth * 2;
cv::Mat img = cv::Mat::zeros(imgRows, imgCols, CV_8UC3);
//计算投影比例
_XOYprojection_rodInfo(img, rotateLines, rotatedRod, scale, sideWidth, rx_range, ry_range, dirLen);
cv::imwrite(fileName, img);
return;
}
#define ROD_POSITION_TEST_GROUP 7
#define TEST_CONVERT_TO_GRID 0
#define TEST_COMPUTE_CALIB_PARA 0
#define TEST_COMPUTE_ROD_POSITION 1
@ -1421,17 +1640,18 @@ void rodPositionTest(void)
"F:/ShangGu/项目/冠钦项目/胶布圆棒抓取/模拟测试数据2/", //4
"F:/ShangGu/项目/冠钦项目/矩森棒材抓取/异常点云/", //5
"F:/ShangGu/项目/冠钦项目/矩森棒材抓取/异常点云2/", //6
};
SVzNLRange fileIdx[ROD_POSITION_TEST_GROUP] = {
{1,8}, {1,3}, {1,31},
{1,5},{1,11},{1,26}
{1,5},{1,11},{1,26},{1,41}
};
const char* ver = wd_rodAndBarDetectionVersion();
printf("ver:%s\n", ver);
for (int grp = 5; grp <= 5; grp++)
for (int grp = 0; grp <= 6; grp++)
{
SSG_planeCalibPara poseCalibPara;
//初始化成单位阵
@ -1459,12 +1679,14 @@ void rodPositionTest(void)
for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
{
//fidx =16;
//fidx =10;
char _scan_file[256];
if( (3 == grp) ||(4 == grp))
sprintf_s(_scan_file, "%s%d_LaserData_Hi229156.txt", dataPath[grp], fidx);
else if(5 == grp)
sprintf_s(_scan_file, "%s%d_LaserData_Ik256066.txt", dataPath[grp], fidx);
else if (6 == grp)
sprintf_s(_scan_file, "%s%d_LaserData_Ik256066.txt", dataPath[grp], fidx);
else
sprintf_s(_scan_file, "%sLaserData_%d.txt", dataPath[grp], fidx);
@ -1487,6 +1709,11 @@ void rodPositionTest(void)
rodParam.diameter = 96.0; //圆棒直径
rodParam.len = 440;
}
else if (grp == 6)
{
rodParam.diameter = 62.0; //圆棒直径
rodParam.len = 380;
}
else
{
rodParam.diameter = 68.0; //圆棒直径
@ -1494,8 +1721,8 @@ void rodPositionTest(void)
}
SSG_cornerParam cornerParam;
cornerParam.cornerTh = 45; //45度角
cornerParam.scale = rodParam.diameter / 4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8;
cornerParam.cornerTh = 30; //45度角
cornerParam.scale = rodParam.diameter / 6; // 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; //水平角度,小于此角度视为水平
@ -1506,9 +1733,9 @@ void rodPositionTest(void)
filterParam.outlierTh = 5;
SSG_treeGrowParam growParam;
growParam.maxLineSkipNum = 5;
growParam.yDeviation_max = 10.0;
growParam.maxSkipDistance = 10.0;
growParam.maxLineSkipNum = 15;
growParam.yDeviation_max = 20.0;
growParam.maxSkipDistance = 25.0;
growParam.zDeviation_max = 10.0;//
growParam.minLTypeTreeLen = rodParam.len * 0.75; //mm, 螺杆长度
growParam.minVTypeTreeLen = rodParam.len * 0.75; //mm
@ -1533,6 +1760,14 @@ void rodPositionTest(void)
_outputRGBDScan_RGBD_rodInfo(_scan_file, scanLines, rodInfo);
sprintf_s(_scan_file, "%sresult\\%d_screw_info.txt", dataPath[grp], fidx);
_outputRodtInfo(_scan_file, rodInfo);
#if 1
sprintf_s(_scan_file, "%sresult/%d_result_projection.png", dataPath[grp], fidx);
double rpy[3] = { -60, 0, 10 }; //{ 0,-45, 0 }; //
double angleDrawLen = 15;
double displayScale = 1.0;
cv::String imgName(_scan_file);
_genXOYProjectionImage_rodInfo(imgName, scanLines, displayScale, rodInfo, rpy, angleDrawLen);
#endif
}
}
#endif

View File

@ -265,6 +265,7 @@ SG_APISHARED_EXPORT void wd_getRodArcFeature_segmentPeakCornerMethod(
const double minSegSize,
const double peakChkWin,
const SSG_cornerParam cornerPara,
bool doSmoothing,
std::vector<SWD_rodArcFeature>& line_rodArcs //»·
);

View File

@ -849,7 +849,7 @@ void wd_getRodArcFeatureGrowingTrees(
{
for (int i = 0, i_max = (int)all_lineFeatures.size(); i < i_max; i++)
{
if (i == 630)
if (i == 721)
int kkk = 1;
std::vector<SWD_rodArcFeature>& a_lineFeatures = all_lineFeatures[i];
for (int j = 0, j_max = (int)a_lineFeatures.size(); j < j_max; j++)

View File

@ -4319,28 +4319,43 @@ void _computeDirAngle_perSeg_2(
int vPtIdxEnd = vPtIdxStart + segs[segIdx].len - 1;
for (int i = vPtIdxStart; i <= vPtIdxEnd; i++)
{
if (i == 345)
int kkk = 1;
if (vldPts[i].pt3D.z < 1e-4) //seg内空白点用type区分
{
ptDirAngles[i].pntIdx = i;
ptDirAngles[i].type = -1;
continue;
}
//前向寻找
int pre_i = -1;
for (int j = i - 1; j >= vPtIdxStart; j--)
{
double dist = sqrt(pow(vldPts[i].pt3D.y - vldPts[j].pt3D.y, 2) +
pow(vldPts[i].pt3D.z - vldPts[j].pt3D.z, 2));
if (dist >= cornerPara.scale)
if (vldPts[j].pt3D.z > 1e-4)
{
pre_i = j;
break;
double dist = sqrt(pow(vldPts[i].pt3D.y - vldPts[j].pt3D.y, 2) +
pow(vldPts[i].pt3D.z - vldPts[j].pt3D.z, 2));
if (dist >= cornerPara.scale)
{
pre_i = j;
break;
}
}
}
//后向寻找
int post_i = -1;
for (int j = i + 1; j <= vPtIdxEnd; j++)
{
double dist = sqrt(pow(vldPts[i].pt3D.y - vldPts[j].pt3D.y, 2) +
pow(vldPts[i].pt3D.z - vldPts[j].pt3D.z, 2));
if (dist >= cornerPara.scale)
if (vldPts[j].pt3D.z > 1e-4)
{
post_i = j;
break;
double dist = sqrt(pow(vldPts[i].pt3D.y - vldPts[j].pt3D.y, 2) +
pow(vldPts[i].pt3D.z - vldPts[j].pt3D.z, 2));
if (dist >= cornerPara.scale)
{
post_i = j;
break;
}
}
}
//计算拐角
@ -4704,6 +4719,7 @@ void wd_getRingArcFeature(
return;
}
#if 0
//此处考虑到ZPeak会有波动考虑到方向角计算是以尺度为基准以方向角为准
bool _chkRodArcFeature(
int pkIdx, double searchWin,
@ -4823,6 +4839,146 @@ bool _chkRodArcFeature(
}
return false;
}
#else
//此处考虑到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 = 0;
double realPkRatio = -1;
int realPkIdx = pkIdx;
//向前搜索
for (int i = pkIdx; i >= 0; i--)
{
if (lineData[i].pt3D.z < 1e-4)
continue;
if (ptDirAngles[i].type < 0)
continue;
if (ptDirAngles[i].pntIdx < 0)
break;
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;
if ((ptDirAngles[i].forwardAngle > 0) && (ptDirAngles[i].backwardAngle < 0)&& (ptDirAngles[i].corner < -arcPerPointCornerMinValue))
{
double ratio = abs(ptDirAngles[i].forwardAngle) < abs(ptDirAngles[i].backwardAngle) ?
(abs(ptDirAngles[i].forwardAngle) / abs(ptDirAngles[i].backwardAngle)) :
(abs(ptDirAngles[i].backwardAngle) / abs(ptDirAngles[i].forwardAngle));
if (realPkRatio < 0)
{
realPkRatio = ratio;
realPkIdx = i;
realPkCorner = abs(ptDirAngles[i].corner);
}
else if (realPkRatio < ratio)
{
realPkRatio = ratio;
realPkIdx = i;
realPkCorner = abs(ptDirAngles[i].corner);
}
}
}
//向后搜索
for (int i = pkIdx + 1; i < (int)lineData.size(); i++)
{
if (lineData[i].pt3D.z < 1e-4)
continue;
if (ptDirAngles[i].type < 0) //seg内空白点跳过
continue;
if (ptDirAngles[i].pntIdx < 0) //seg端点结束
break;
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;
if ((ptDirAngles[i].forwardAngle > 0) && (ptDirAngles[i].backwardAngle < 0) && (ptDirAngles[i].corner < -arcPerPointCornerMinValue))
{
double ratio = abs(ptDirAngles[i].forwardAngle) < abs(ptDirAngles[i].backwardAngle) ?
(abs(ptDirAngles[i].forwardAngle) / abs(ptDirAngles[i].backwardAngle)) :
(abs(ptDirAngles[i].backwardAngle) / abs(ptDirAngles[i].forwardAngle));
if (realPkRatio < 0)
{
realPkRatio = ratio;
realPkIdx = i;
realPkCorner = abs(ptDirAngles[i].corner);
}
else if (realPkRatio < ratio)
{
realPkRatio = ratio;
realPkIdx = i;
realPkCorner = abs(ptDirAngles[i].corner);
}
}
}
if (realPkRatio < 0)
return false;
//向后搜索
int searchIdx = realPkIdx;
int pre_idx = realPkIdx;
while (1)
{
if ((ptDirAngles[searchIdx].backwardAngle > -1e-4) || (ptDirAngles[searchIdx].pntIdx < 0)) //isEnding
{
for (int m = searchIdx; m <= realPkIdx; m++)
{
if ((ptDirAngles[m].type >= 0) && (ptDirAngles[m].backwardAngle < -1e-4))
{
pre_idx = m;
break;
}
}
break;
}
pre_idx = ptDirAngles[searchIdx].backwardPntIdx;
searchIdx = ptDirAngles[searchIdx].backwardPntIdx;
}
//向前搜索
searchIdx = realPkIdx;
int post_idx = realPkIdx;
while (1)
{
if ((ptDirAngles[searchIdx].forwardAngle < 1e-4) || (ptDirAngles[searchIdx].pntIdx < 0)) //isEnding
{
for (int m = searchIdx; m >= realPkIdx; m--)
{
if ((ptDirAngles[m].type >= 0) && (ptDirAngles[m].forwardAngle > 1e-4))
{
post_idx = m;
break;
}
}
break;
}
post_idx = ptDirAngles[searchIdx].forwardPntIdx;
searchIdx = ptDirAngles[searchIdx].forwardPntIdx;
}
double totalCorner = ptDirAngles[post_idx].forwardAngle - ptDirAngles[pre_idx].backwardAngle;
if (totalCorner > arcTotalCornerMinValue) //整个圆弧需要至少60度的扇区。
{
a_rodPos.idx = realPkIdx;
a_rodPos.data_0 = pre_idx;
a_rodPos.data_1 = post_idx;
return true;
}
return false;
}
#endif
/// <summary>
/// 提取激光线上的圆环的上半段弧。
@ -4846,7 +5002,7 @@ void wd_getRodArcFeature_peakCornerMethod(
)
{
double arcPerPointCornerMinValue = 5; //arc上每个点的转角最小值
double arcTotalCornerMinValue = 30; //整个Arc的转角最小值
double arcTotalCornerMinValue = 45; //整个Arc的转角最小值
//计算前向角和后向角
std::vector< SSG_pntDirAngle> ptDirAngles;
wd_computeDirAngle_wholeLine( lineData, cornerPara, ptDirAngles);
@ -5222,11 +5378,11 @@ void wd_getRodArcFeature_segmentPeakCornerMethod(
const double minSegSize,
const double peakChkWin,
const SSG_cornerParam cornerPara,
bool doSmoothing,
std::vector<SWD_rodArcFeature>& line_rodArcs //环
)
{
double arcPerPointCornerMinValue = 5.0; //arc上每个点的转角最小值
double arcTotalCornerMinValue = 30; //整个Arc的转角最小值
double arcPerPointCornerMinValue = 3.0;// 5.0; //arc上每个点的转角最小值
std::vector<SSG_RUN> segs;
wd_lineDataSegment_dist_2(
@ -5235,6 +5391,23 @@ void wd_getRodArcFeature_segmentPeakCornerMethod(
maxDistTh,
minSegSize
);
if (true == doSmoothing)
{
int smoothWin = 3;
int segSize = (int)segs.size();
for (int segIdx = 0; segIdx < segSize; segIdx++)
{
int vPtIdxStart = segs[segIdx].start;
int vPtIdxEnd = vPtIdxStart + segs[segIdx].len - 1;
std::vector<SVzNL3DPosition> segData;
segData.insert(segData.end(), lineData.begin() + vPtIdxStart, lineData.begin() + vPtIdxEnd + 1);
std::vector<SVzNL3DPosition> segSmoothData;
sg_lineDataSmoothing(segData, smoothWin, segSmoothData);
std::copy(segSmoothData.begin(), segSmoothData.end(), lineData.begin() + vPtIdxStart);
}
}
//计算前向角和后向角
std::vector< SSG_pntDirAngle> ptDirAngles;
_computeDirAngle_perSeg_2(lineData, segs, cornerPara, ptDirAngles);
@ -5256,7 +5429,7 @@ void wd_getRodArcFeature_segmentPeakCornerMethod(
bool isArc = _chkRodArcFeature(
pkIdx, cornerPara.scale,
ptDirAngles, lineData,
arcPerPointCornerMinValue, arcTotalCornerMinValue,
arcPerPointCornerMinValue, cornerPara.cornerTh,
a_rodPos);
if ( (true == isArc) && (prePos.idx != a_rodPos.idx))
{

View File

@ -30,7 +30,8 @@
//version 1.3.7 : 新的定位盘中心测量功能:进一步优化了内部参数,优化了垂直点去除效果
//version 1.3.8 : 新的螺杆定位算法使用PCA方法确定螺杆轴向
//version 1.4.0 : 矩森棒材抓取算法改进1修正了两个棒材被识别成一根的问题2增强了对噪点的容忍度增强了鲁棒性
std::string m_strVersion = "RodAndBarDetection_1.4.0";
//version 1.5.0 : 矩森棒材抓取算法改进:加强了对强噪声点云的处理
std::string m_strVersion = "RodAndBarDetection_1.5.0";
const char* wd_rodAndBarDetectionVersion(void)
{
return m_strVersion.c_str();
@ -249,18 +250,20 @@ void rodArcFeatueDetection(
const double segment_maxDistTh,
const double segment_minSegSze,
const double rodDiameter,
bool doSmoothing, //对于水平扫描数据,波动比较大,需要平滑处理
std::vector<std::vector<SWD_rodArcFeature>>& arcFeatures)
{
int lineNum = (int)scanLines.size();
int linePtNum = (int)scanLines[0].size();
for (int line = 0; line < lineNum; line++)
{
if (line == 780)
if (line == 810)
int kkk = 1;
std::vector<SVzNL3DPosition>& lineData = scanLines[line];
// Filter outliers from line data
sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], linePtNum, filterParam);
// Extract rod arc features
std::vector<SWD_rodArcFeature> line_rodArcs;
#if 0
@ -283,6 +286,7 @@ void rodArcFeatueDetection(
segment_minSegSze,
rodDiameter / 2,
cornerPara,
doSmoothing,
line_rodArcs //环
);
#endif
@ -533,6 +537,7 @@ SVzNL3DRangeD _getPointCloudROI(std::vector<SWD3DPointPostion>& scanData)
segment_maxDistTh,
segment_minSegSize,
rodDiameter,
false,
arcFeatures);
//特征生长
@ -3437,6 +3442,131 @@ void sx_rodPositioning(
hLines_raw[j][line].pt3D.x = scanLines[line][j].pt3D.y;
hLines_raw[j][line].pt3D.y = scanLines[line][j].pt3D.x;
}
}
//去除垂直段
SSG_cornerParam removeVertialPara;
memset(&removeVertialPara, 0, sizeof(SSG_cornerParam));
removeVertialPara.scale = 3.0;
removeVertialPara.cornerTh = 60;
std::vector<std::vector<int>> 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<std::vector<int>> zVertivalFlags;
for (int line = 0; line < lineNum; line++)
{
if (line == 700)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
scanLines[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[line][i] = 1;
}
}
std::vector<std::vector<int>> zVertivalFlags_h;
for (int line = 0; line < linePtNum; line++)
{
if (line == 1177)
int kkk = 1;
std::vector<int> line_verticalFlags;
wd_getXYVertialFeature_dirAngleMethod(
hLines_raw[line],
line,
removeVertialPara,
line_verticalFlags
);
zVertivalFlags_h.push_back(line_verticalFlags);
for (int i = 0; i < (int)line_verticalFlags.size(); i++)
{
if (line_verticalFlags[i] > 0)
flags[i][line] = 1;
}
}
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
{
scanLines[line][j].pt3D.z = 0;
hLines_raw[j][line].pt3D.z = 0;
}
}
}
//迭代一次
SSG_lineSegParam lineSegPara;
lineSegPara.distScale = 5.0;
lineSegPara.segGapTh_y = 5.0;
lineSegPara.segGapTh_z = 5.0;
const int minSegLen = 5;
for (int line = 0; line < lineNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
scanLines[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[line][idx0 + j] = 1;
}
}
}
for (int line = 0; line < linePtNum; line++)
{
std::vector<SSG_RUN> segs;
wd_getLineDataIntervals(
hLines_raw[line],
lineSegPara,
segs);
for (int i = 0; i < (int)segs.size(); i++)
{
if (segs[i].len <= minSegLen)
{
int idx0 = segs[i].start;
for (int j = 0; j < segs[i].len; j++)
flags[idx0 + j][line] = 1;
}
}
}
//标注
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
scanLines[line][j].nPointIdx = 0; //将原始数据的序列清0会转义使用
}
//将垂直线段去除
for (int line = 0; line < lineNum; line++)
{
for (int j = 0; j < linePtNum; j++)
{
if (flags[line][j] > 0)
{
scanLines[line][j].pt3D.z = 0;
hLines_raw[j][line].pt3D.z = 0;
}
}
}
//内部参数
@ -3444,14 +3574,14 @@ void sx_rodPositioning(
const double segment_minSegSize = rodParam.diameter / 8;
//在垂直方向上分别提取ARC特征并进行特征生长
std::vector<std::vector<SWD_rodArcFeature>> arcFeatures_v;
rodArcFeatueDetection( scanLines, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, arcFeatures_v);
rodArcFeatueDetection( scanLines, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, false, arcFeatures_v);
//特征生长
std::vector<SWD_rodArcFeatureTree> rodArcTrees_v;
wd_getRodArcFeatureGrowingTrees(arcFeatures_v, rodArcTrees_v, growParam);
//水平方向
std::vector<std::vector<SWD_rodArcFeature>> arcFeatures_h;
rodArcFeatueDetection(hLines_raw, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, arcFeatures_h);
rodArcFeatueDetection(hLines_raw, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, true, arcFeatures_h);
//特征生长
std::vector<SWD_rodArcFeatureTree> rodArcTrees_h;
wd_getRodArcFeatureGrowingTrees(arcFeatures_h, rodArcTrees_h, growParam);
@ -3462,7 +3592,6 @@ void sx_rodPositioning(
return;
}
int objNum_v = (int)rodArcTrees_v.size();
int objNum_h = (int)rodArcTrees_h.size();
for (int line = 0; line < lineNum; line++)
@ -4848,7 +4977,7 @@ void sx_rebarWeldSeamPositioning(
const double segment_minSegSize = rodParam.diameter / 8;
std::vector<std::vector<SWD_rodArcFeature>> arcFeatures_v;
#if 1
rodArcFeatueDetection(scanLines, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, arcFeatures_v);
rodArcFeatueDetection(scanLines, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, false, arcFeatures_v);
#else
lineArcAndWeldFeatueDetection(scanLines, cornerPara, filterParam, rodParam.diameter, arcFeatures_v);
#endif
@ -4875,7 +5004,7 @@ void sx_rebarWeldSeamPositioning(
}
//水平方向
std::vector<std::vector<SWD_rodArcFeature>> arcFeatures_h;
rodArcFeatueDetection(hLines_raw, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, arcFeatures_h);
rodArcFeatueDetection(hLines_raw, cornerPara, filterParam, segment_maxDistTh, segment_minSegSize, rodParam.diameter, true, arcFeatures_h);
//特征生长
std::vector<SWD_rodArcFeatureTree> allRodArcTrees_h;
wd_getRodArcFeatureGrowingTrees(arcFeatures_h, allRodArcTrees_h, growParam);