SX_lapWeldDetection
version 1.2.0 :焊缝(平缝)识别添加博清模拟数据中的凸起焊缝,通过参数选择识别类型(不支持自动识别)
This commit is contained in:
parent
8d49089a57
commit
737d741406
@ -744,6 +744,19 @@ void _removeZeroLines_XYZ(std::vector<std::vector< SVzNL3DPosition>>& scanData)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _outputWeldInfo(char* outFileName, std::vector<SVzNL3DPoint>& weldRawPoints)
|
||||||
|
{
|
||||||
|
std::ofstream sw(outFileName);
|
||||||
|
char dataStr[250];
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)weldRawPoints.size(); i++)
|
||||||
|
{
|
||||||
|
sprintf_s(dataStr, 250, "id_%d: (%g, %g, %g)", i+1, weldRawPoints[i].x, weldRawPoints[i].y, weldRawPoints[i].z);
|
||||||
|
sw << dataStr << std::endl;
|
||||||
|
}
|
||||||
|
sw.close();
|
||||||
|
}
|
||||||
|
|
||||||
#define CONVERT_TO_GRID 0
|
#define CONVERT_TO_GRID 0
|
||||||
#define TEST_COMPUTE_CALIB_PARA 0
|
#define TEST_COMPUTE_CALIB_PARA 0
|
||||||
#define TEST_COMPUTE_POSITION 1
|
#define TEST_COMPUTE_POSITION 1
|
||||||
@ -916,15 +929,16 @@ void lapWeldTest()
|
|||||||
|
|
||||||
#define TEST_BQ_CALIB_PARA 0
|
#define TEST_BQ_CALIB_PARA 0
|
||||||
#define TEST_BQ_WELD_SEAM 1
|
#define TEST_BQ_WELD_SEAM 1
|
||||||
#define BQ_TEST_GROUP 1
|
#define BQ_TEST_GROUP 2
|
||||||
void BQ_thinWeldSeamTest()
|
void BQ_thinWeldSeamTest()
|
||||||
{
|
{
|
||||||
const char* dataPath[BQ_TEST_GROUP] = {
|
const char* dataPath[BQ_TEST_GROUP] = {
|
||||||
"F:/ShangGu/项目/冠钦_博清科技/焊缝识别/数据/", //0
|
"F:/ShangGu/项目/冠钦_博清科技/焊缝识别/数据/", //0
|
||||||
|
"F:/ShangGu/项目/冠钦_博清科技/焊缝识别/博清实验室模拟数据/", //0
|
||||||
};
|
};
|
||||||
|
|
||||||
SVzNLRange fileIdx[BQ_TEST_GROUP] = {
|
SVzNLRange fileIdx[BQ_TEST_GROUP] = {
|
||||||
{1,4},
|
{1,4},{1,2}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1003,7 +1017,7 @@ void BQ_thinWeldSeamTest()
|
|||||||
|
|
||||||
#if TEST_BQ_WELD_SEAM
|
#if TEST_BQ_WELD_SEAM
|
||||||
//for (int group = 0; group < TEST_GROUPS; group++)
|
//for (int group = 0; group < TEST_GROUPS; group++)
|
||||||
for (int grp = 0; grp < BQ_TEST_GROUP; grp++)
|
for (int grp = 1; grp < BQ_TEST_GROUP; grp++)
|
||||||
{
|
{
|
||||||
SSG_planeCalibPara groundCalibPara;
|
SSG_planeCalibPara groundCalibPara;
|
||||||
//初始化成单位阵
|
//初始化成单位阵
|
||||||
@ -1020,8 +1034,11 @@ void BQ_thinWeldSeamTest()
|
|||||||
for (int i = 0; i < 9; i++)
|
for (int i = 0; i < 9; i++)
|
||||||
groundCalibPara.invRMatrix[i] = groundCalibPara.planeCalib[i];
|
groundCalibPara.invRMatrix[i] = groundCalibPara.planeCalib[i];
|
||||||
char calibFile[250];
|
char calibFile[250];
|
||||||
sprintf_s(calibFile, "%sground_calib_para.txt", dataPath[grp]);
|
if (0 == grp)
|
||||||
groundCalibPara = _readCalibPara(calibFile);
|
{
|
||||||
|
sprintf_s(calibFile, "%sground_calib_para.txt", dataPath[grp]);
|
||||||
|
groundCalibPara = _readCalibPara(calibFile);
|
||||||
|
}
|
||||||
|
|
||||||
double para_chkWidth_wide = 2.5f;
|
double para_chkWidth_wide = 2.5f;
|
||||||
|
|
||||||
@ -1029,22 +1046,32 @@ void BQ_thinWeldSeamTest()
|
|||||||
SVzNLRangeD gapParam;
|
SVzNLRangeD gapParam;
|
||||||
|
|
||||||
SWD_valleyParam valleyParam;
|
SWD_valleyParam valleyParam;
|
||||||
valleyParam.chkWin_width = 2.5; //mm, 检测2.5mm宽的V型
|
valleyParam.chkWin_width = 5.0; // 2.5; //mm, 检测2.5mm宽的V型
|
||||||
valleyParam.maxWidth = 20.0; //最大宽度20mm,用于过滤虚假信号
|
valleyParam.maxWidth = 20.0; //最大宽度20mm,用于过滤虚假信号
|
||||||
valleyParam.minHeight = 1.0;
|
valleyParam.minHeight = 0.5;
|
||||||
|
|
||||||
SSG_treeGrowParam growParam;
|
SSG_treeGrowParam growParam;
|
||||||
growParam.maxLineSkipNum = 50;
|
growParam.maxLineSkipNum = 50;
|
||||||
growParam.yDeviation_max = 1.0;
|
growParam.yDeviation_max = 1.5;
|
||||||
growParam.maxSkipDistance = 30.0;
|
growParam.maxSkipDistance = 30.0;
|
||||||
growParam.zDeviation_max = 5.0;//
|
growParam.zDeviation_max = 5.0;//
|
||||||
growParam.minLTypeTreeLen = 50; //mm,
|
growParam.minLTypeTreeLen = 50; //mm,
|
||||||
growParam.minVTypeTreeLen = 50; //mm
|
growParam.minVTypeTreeLen = 50; //mm
|
||||||
|
|
||||||
|
EWD_FlawType detectType;
|
||||||
|
if(0 == grp)
|
||||||
|
detectType = keWD_FlawType_Depression;
|
||||||
|
else
|
||||||
|
detectType = keWD_FlawType_Protrusion;
|
||||||
|
|
||||||
for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
|
for (int fidx = fileIdx[grp].nMin; fidx <= fileIdx[grp].nMax; fidx++)
|
||||||
{
|
{
|
||||||
|
//fidx = 2;
|
||||||
char _scan_file[256];
|
char _scan_file[256];
|
||||||
sprintf_s(_scan_file, "%s%d_LaserData_Jl26C077.txt", dataPath[grp], fidx);
|
if(0 == grp)
|
||||||
|
sprintf_s(_scan_file, "%s%d_LaserData_Jl26C077.txt", dataPath[grp], fidx);
|
||||||
|
else
|
||||||
|
sprintf_s(_scan_file, "%s%d_LaserData_Jh26B083.txt", dataPath[grp], fidx);
|
||||||
printf("process: %s......\n", _scan_file);
|
printf("process: %s......\n", _scan_file);
|
||||||
|
|
||||||
std::vector<std::vector< SVzNL3DPosition>> scanLines;
|
std::vector<std::vector< SVzNL3DPosition>> scanLines;
|
||||||
@ -1059,6 +1086,9 @@ void BQ_thinWeldSeamTest()
|
|||||||
std::vector<SSG_gapFeatureTree> trees;
|
std::vector<SSG_gapFeatureTree> trees;
|
||||||
for (int i = 0; i < (int)scanLines.size(); i++)
|
for (int i = 0; i < (int)scanLines.size(); i++)
|
||||||
{
|
{
|
||||||
|
if (i == 117)
|
||||||
|
int kkk = 1;
|
||||||
|
|
||||||
std::vector<SVzNL3DPosition>& a_line = scanLines[i];
|
std::vector<SVzNL3DPosition>& a_line = scanLines[i];
|
||||||
std::vector< SSG_basicFeatureGap> line_valleys;
|
std::vector< SSG_basicFeatureGap> line_valleys;
|
||||||
sx_lineDataR(scanLines[i], groundCalibPara.planeCalib, -1);//调平,去除地面
|
sx_lineDataR(scanLines[i], groundCalibPara.planeCalib, -1);//调平,去除地面
|
||||||
@ -1074,11 +1104,12 @@ void BQ_thinWeldSeamTest()
|
|||||||
a_line,
|
a_line,
|
||||||
i,
|
i,
|
||||||
valleyParam,
|
valleyParam,
|
||||||
|
detectType,
|
||||||
line_valleys);
|
line_valleys);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
bool isLastLine = i == ((int)scanLines.size() - 1) ? true : false;
|
bool isLastLine = i == ((int)scanLines.size() - 1) ? true : false;
|
||||||
sg_lineGapsGrowing(
|
sg_lineGapsGrowing_treeFirst(
|
||||||
i,
|
i,
|
||||||
isLastLine,
|
isLastLine,
|
||||||
line_valleys,
|
line_valleys,
|
||||||
@ -1127,6 +1158,9 @@ void BQ_thinWeldSeamTest()
|
|||||||
std::vector< std::vector<SVzNL3DPoint>> multiSeam;
|
std::vector< std::vector<SVzNL3DPoint>> multiSeam;
|
||||||
multiSeam.push_back(weldOps);
|
multiSeam.push_back(weldOps);
|
||||||
_outputRGBDScanLapWeld_RGBD(outFileName, scanLines, multiSeam, true);
|
_outputRGBDScanLapWeld_RGBD(outFileName, scanLines, multiSeam, true);
|
||||||
|
sprintf_s(outFileName, "%sresult\\LaserLine%d_weldInfo.txt", dataPath[grp], fidx);
|
||||||
|
_outputWeldInfo(outFileName, weldOps);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1133,4 +1133,5 @@ SG_APISHARED_EXPORT void wd_getLineVFlaws(
|
|||||||
std::vector<SVzNL3DPosition>& a_line,
|
std::vector<SVzNL3DPosition>& a_line,
|
||||||
const int lineIdx,
|
const int lineIdx,
|
||||||
const SWD_valleyParam valleyParam,
|
const SWD_valleyParam valleyParam,
|
||||||
|
const EWD_FlawType detectFlawType,
|
||||||
std::vector< SSG_basicFeatureGap>& valleys);
|
std::vector< SSG_basicFeatureGap>& valleys);
|
||||||
|
|||||||
@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
#define PI 3.14159265358979323846
|
#define PI 3.14159265358979323846
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
keWD_FlawType_Uknown = 0,
|
||||||
|
keWD_FlawType_Depression, //凹陷
|
||||||
|
keWD_FlawType_Protrusion, //凸起
|
||||||
|
keSG_FlawType_Dep_Prot, //凹陷和凸起混合
|
||||||
|
} EWD_FlawType;
|
||||||
|
|
||||||
// 定义欧拉角结构体(单位:度)
|
// 定义欧拉角结构体(单位:度)
|
||||||
typedef struct{
|
typedef struct{
|
||||||
double roll; // 绕X轴旋转(横滚)
|
double roll; // 绕X轴旋转(横滚)
|
||||||
@ -90,6 +98,12 @@ typedef struct
|
|||||||
int end;
|
int end;
|
||||||
}SWD_Interval; //区间
|
}SWD_Interval; //区间
|
||||||
|
|
||||||
|
typedef struct SWD_IndexedValue
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
double value;
|
||||||
|
}SWD_IndexedValue;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool validFlag; //指示结果是否有效
|
bool validFlag; //指示结果是否有效
|
||||||
|
|||||||
@ -9702,7 +9702,7 @@ if (i == 98)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum STATES { null = 0, UP, DOWN };
|
enum STATES { null = 0, UP, DOWN, USED };
|
||||||
struct posAttri
|
struct posAttri
|
||||||
{
|
{
|
||||||
int peakPos;
|
int peakPos;
|
||||||
@ -9797,8 +9797,17 @@ float _computeHeight(SVzNL3DPoint& startPt, SVzNL3DPoint& endPt, SVzNL3DPoint& v
|
|||||||
float height = fabs(_a * valleyPt.y + _b * valleyPt.z + _c) / sqrt(pow(_a, 2) + pow(_b, 2));
|
float height = fabs(_a * valleyPt.y + _b * valleyPt.z + _c) / sqrt(pow(_a, 2) + pow(_b, 2));
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _sortFormZMaxToMin(const SWD_IndexedValue& a, const SWD_IndexedValue& b) {
|
||||||
|
return a.value > b.value;
|
||||||
|
}
|
||||||
|
bool _sortFormZMinToMax(const SWD_IndexedValue& a, const SWD_IndexedValue& b) {
|
||||||
|
return a.value < b.value;
|
||||||
|
}
|
||||||
|
|
||||||
/* startId, endId: 有效点的起止位置。对于栅格数据格式,开始的空点和结束的空点都不是有效点 */
|
/* startId, endId: 有效点的起止位置。对于栅格数据格式,开始的空点和结束的空点都不是有效点 */
|
||||||
void _valleyDetect(
|
//凹陷检测(depression)
|
||||||
|
void _depressionDetect(
|
||||||
std::vector<SVzNL3DPosition>& a_line,
|
std::vector<SVzNL3DPosition>& a_line,
|
||||||
const int lineIdx, const int startId, const int endId,
|
const int lineIdx, const int startId, const int endId,
|
||||||
std::vector<posAttri>& deriv_1_peaks,
|
std::vector<posAttri>& deriv_1_peaks,
|
||||||
@ -9816,129 +9825,300 @@ void _valleyDetect(
|
|||||||
double y_start = a_line[startId].pt3D.y;
|
double y_start = a_line[startId].pt3D.y;
|
||||||
double y_end = a_line[endId].pt3D.y;
|
double y_end = a_line[endId].pt3D.y;
|
||||||
|
|
||||||
//逐个peak检测:正peak
|
//按peak(DOWN)值进行排序
|
||||||
|
std::vector<SWD_IndexedValue> indexedPeaks;
|
||||||
for (int i = 0; i < deriv_2_peaks.size(); i++)
|
for (int i = 0; i < deriv_2_peaks.size(); i++)
|
||||||
{
|
{
|
||||||
if (i == 153)
|
|
||||||
int kkk = 1;
|
|
||||||
posAttri a_pos = deriv_2_peaks[i];
|
posAttri a_pos = deriv_2_peaks[i];
|
||||||
if ((a_pos.peakState == DOWN) && (deriv_2[a_pos.peakPos] < 0))
|
if ((a_pos.peakState == DOWN) && (deriv_2[a_pos.peakPos] < 0))
|
||||||
{
|
{
|
||||||
//检查两侧
|
SWD_IndexedValue a_indexdPeak;
|
||||||
int preEdge = -1;
|
a_indexdPeak.idx = i;
|
||||||
for (int j = a_pos.peakPos - 1; j > 0; j--)
|
a_indexdPeak.value = a_line[a_pos.peakPos].pt3D.z;
|
||||||
|
indexedPeaks.push_back(a_indexdPeak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(indexedPeaks.begin(), indexedPeaks.end(), _sortFormZMaxToMin);
|
||||||
|
//逐个peak检测:正peak
|
||||||
|
for (int i = 0; i < (int)indexedPeaks.size(); i++)
|
||||||
|
{
|
||||||
|
int idx = indexedPeaks[i].idx;
|
||||||
|
if (idx == 153)
|
||||||
|
int kkk = 1;
|
||||||
|
posAttri a_pos = deriv_2_peaks[idx];
|
||||||
|
//检查两侧
|
||||||
|
int preEdge = -1;
|
||||||
|
for (int j = a_pos.peakPos - 1; j > 0; j--)
|
||||||
|
{
|
||||||
|
if ( (buff[j].peakState == DOWN)|| (buff[j].peakState == USED))
|
||||||
|
break;
|
||||||
|
else if (buff[j].peakState == UP)
|
||||||
{
|
{
|
||||||
if (buff[j].peakState == DOWN)
|
if (deriv_1[j] > 0)
|
||||||
break;
|
preEdge = j;
|
||||||
else if (buff[j].peakState == UP)
|
break;
|
||||||
{
|
|
||||||
if (deriv_1[j] > 0)
|
|
||||||
preEdge = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int postEdge = -1;
|
}
|
||||||
for (int j = a_pos.peakPos + 1; j < (int)a_line.size(); j++)
|
int postEdge = -1;
|
||||||
|
for (int j = a_pos.peakPos + 1; j < (int)a_line.size(); j++)
|
||||||
|
{
|
||||||
|
if ((buff[j].peakState == UP)|| (buff[j].peakState == USED))
|
||||||
|
break;
|
||||||
|
else if (buff[j].peakState == DOWN)
|
||||||
{
|
{
|
||||||
if (buff[j].peakState == UP)
|
if (deriv_1[j] < 0)
|
||||||
break;
|
postEdge = j;
|
||||||
else if (buff[j].peakState == DOWN)
|
break;
|
||||||
{
|
|
||||||
if (deriv_1[j] < 0)
|
|
||||||
postEdge = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//
|
}
|
||||||
if ((preEdge >= 0) && (postEdge >= 0)) //初步符合凹陷特点
|
//
|
||||||
|
if ((preEdge >= 0) && (postEdge >= 0)) //初步符合凹陷特点
|
||||||
|
{
|
||||||
|
float edge_value_pre = deriv_1[preEdge];
|
||||||
|
float edge_value_post = deriv_1[postEdge];
|
||||||
|
//检测对称性
|
||||||
|
float min_value, max_value;
|
||||||
|
if (edge_value_pre < (-edge_value_post))
|
||||||
{
|
{
|
||||||
float edge_value_pre = deriv_1[preEdge];
|
min_value = edge_value_pre;
|
||||||
float edge_value_post = deriv_1[postEdge];
|
max_value = -edge_value_post;
|
||||||
//检测对称性
|
}
|
||||||
float min_value, max_value;
|
else
|
||||||
if (edge_value_pre < (-edge_value_post))
|
{
|
||||||
|
max_value = edge_value_pre;
|
||||||
|
min_value = -edge_value_post;
|
||||||
|
}
|
||||||
|
if (min_value > max_value / 10) //2023.05.02: 放宽。当凹陷在斜面上时,不再是maxValue/2的理想情况
|
||||||
|
{
|
||||||
|
//检查凹陷宽度深度,滤除噪声
|
||||||
|
float th_pre = edge_value_pre * 0.5;
|
||||||
|
int edge_pos_pre = -1;
|
||||||
|
for (int j = preEdge; j >= 0; j--)
|
||||||
{
|
{
|
||||||
min_value = edge_value_pre;
|
if ( (deriv_1[j] <= th_pre) && (a_line[j].nPointIdx >= 0)) //非填充点
|
||||||
max_value = -edge_value_post;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
max_value = edge_value_pre;
|
|
||||||
min_value = -edge_value_post;
|
|
||||||
}
|
|
||||||
if (min_value > max_value / 10) //2023.05.02: 放宽。当凹陷在斜面上时,不再是maxValue/2的理想情况
|
|
||||||
{
|
|
||||||
//检查凹陷宽度深度,滤除噪声
|
|
||||||
float th_pre = edge_value_pre * 0.5;
|
|
||||||
int edge_pos_pre = -1;
|
|
||||||
for (int j = preEdge; j >= 0; j--)
|
|
||||||
{
|
{
|
||||||
if ( (deriv_1[j] <= th_pre) && (a_line[j].nPointIdx >= 0)) //非填充点
|
edge_pos_pre = j;
|
||||||
{
|
break;
|
||||||
edge_pos_pre = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float th_post = edge_value_post * 0.5;
|
float th_post = edge_value_post * 0.5;
|
||||||
int edge_pos_post = -1;
|
int edge_pos_post = -1;
|
||||||
for (int j = postEdge; j < (int)a_line.size(); j++)
|
for (int j = postEdge; j < (int)a_line.size(); j++)
|
||||||
|
{
|
||||||
|
if ((deriv_1[j] >= th_post) && (a_line[j].nPointIdx >= 0)) //非填充点
|
||||||
{
|
{
|
||||||
if ((deriv_1[j] >= th_post) && (a_line[j].nPointIdx >= 0)) //非填充点
|
edge_pos_post = j;
|
||||||
{
|
break;
|
||||||
edge_pos_post = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//检测宽度
|
//检测宽度
|
||||||
if ((edge_pos_pre >= 0) && (edge_pos_post >= 0))
|
if ((edge_pos_pre >= 0) && (edge_pos_post >= 0))
|
||||||
|
{
|
||||||
|
//float width = a_line->m_p3DPositiont[edge_pos_post].pt3D.y - a_line->m_p3DPositiont[edge_pos_pre].pt3D.y;
|
||||||
|
float width = a_line[postEdge].pt3D.y - a_line[preEdge].pt3D.y;
|
||||||
|
if (width < valleyParam.maxWidth)
|
||||||
{
|
{
|
||||||
//float width = a_line->m_p3DPositiont[edge_pos_post].pt3D.y - a_line->m_p3DPositiont[edge_pos_pre].pt3D.y;
|
float height = _computeHeight(a_line[edge_pos_pre].pt3D,
|
||||||
float width = a_line[postEdge].pt3D.y - a_line[preEdge].pt3D.y;
|
a_line[edge_pos_post].pt3D,
|
||||||
if (width < valleyParam.maxWidth)
|
a_line[a_pos.peakPos].pt3D);
|
||||||
|
if (height > valleyParam.minHeight)
|
||||||
{
|
{
|
||||||
float height = _computeHeight(a_line[edge_pos_pre].pt3D,
|
//精确确定peak点
|
||||||
a_line[edge_pos_post].pt3D,
|
int realPeakPos = preEdge;
|
||||||
a_line[a_pos.peakPos].pt3D);
|
for (int m = preEdge; m <= postEdge; m++)
|
||||||
if (height > valleyParam.minHeight)
|
|
||||||
{
|
{
|
||||||
//精确确定peak点
|
if ((a_line[realPeakPos].pt3D.z < a_line[m].pt3D.z) && (a_line[m].nPointIdx >= 0))
|
||||||
int realPeakPos = preEdge;
|
realPeakPos = m;
|
||||||
for (int m = preEdge; m <= postEdge; m++)
|
|
||||||
{
|
|
||||||
if ((a_line[realPeakPos].pt3D.z < a_line[m].pt3D.z) && (a_line[m].nPointIdx >= 0))
|
|
||||||
realPeakPos = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSG_basicFeatureGap a_valley;
|
|
||||||
memset(&a_valley, 0, sizeof(SSG_basicFeatureGap));
|
|
||||||
a_valley.gapPeak.nPointIdx = realPeakPos;
|
|
||||||
a_valley.gapPeak.pt3D = a_line[realPeakPos].pt3D;
|
|
||||||
a_valley.gapPt_0.nPointIdx = edge_pos_pre;
|
|
||||||
a_valley.gapPt_0.pt3D = a_line[edge_pos_pre].pt3D;
|
|
||||||
a_valley.gapPt_1.nPointIdx = edge_pos_post;
|
|
||||||
a_valley.gapPt_1.pt3D = a_line[edge_pos_post].pt3D;
|
|
||||||
a_valley.lineIdx = lineIdx;
|
|
||||||
a_valley.gap_start = a_line[preEdge].pt3D.y;
|
|
||||||
a_valley.gap_width = width;
|
|
||||||
a_valley.gap_depth = height;
|
|
||||||
valleys.push_back(a_valley);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SSG_basicFeatureGap a_valley;
|
||||||
|
memset(&a_valley, 0, sizeof(SSG_basicFeatureGap));
|
||||||
|
a_valley.gapPeak.nPointIdx = realPeakPos;
|
||||||
|
a_valley.gapPeak.pt3D = a_line[realPeakPos].pt3D;
|
||||||
|
a_valley.gapPt_0.nPointIdx = edge_pos_pre;
|
||||||
|
a_valley.gapPt_0.pt3D = a_line[edge_pos_pre].pt3D;
|
||||||
|
a_valley.gapPt_1.nPointIdx = edge_pos_post;
|
||||||
|
a_valley.gapPt_1.pt3D = a_line[edge_pos_post].pt3D;
|
||||||
|
a_valley.lineIdx = lineIdx;
|
||||||
|
a_valley.gap_start = a_line[preEdge].pt3D.y;
|
||||||
|
a_valley.gap_width = width;
|
||||||
|
a_valley.gap_depth = height;
|
||||||
|
valleys.push_back(a_valley);
|
||||||
|
|
||||||
|
buff[preEdge].peakState = USED;
|
||||||
|
buff[postEdge].peakState = USED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//凸起检测(protrusion)
|
||||||
|
void _protrusionDetect(
|
||||||
|
std::vector<SVzNL3DPosition>& a_line,
|
||||||
|
const int lineIdx, const int startId, const int endId,
|
||||||
|
std::vector<posAttri>& deriv_1_peaks,
|
||||||
|
std::vector<posAttri>& deriv_2_peaks,
|
||||||
|
std::vector<double>& deriv_1,
|
||||||
|
std::vector<double>& deriv_2,
|
||||||
|
std::vector<SSG_basicFeatureGap>& valleys,
|
||||||
|
const SWD_valleyParam valleyParam)
|
||||||
|
{
|
||||||
|
std::vector< posAttri> buff;
|
||||||
|
buff.resize(a_line.size());
|
||||||
|
for (int i = 0; i < deriv_1_peaks.size(); i++)
|
||||||
|
buff[deriv_1_peaks[i].peakPos] = deriv_1_peaks[i];
|
||||||
|
|
||||||
|
double y_start = a_line[startId].pt3D.y;
|
||||||
|
double y_end = a_line[endId].pt3D.y;
|
||||||
|
|
||||||
|
//按peak(UP)值进行排序
|
||||||
|
std::vector<SWD_IndexedValue> indexedPeaks;
|
||||||
|
for (int i = 0; i < deriv_2_peaks.size(); i++)
|
||||||
|
{
|
||||||
|
posAttri a_pos = deriv_2_peaks[i];
|
||||||
|
if ((a_pos.peakState == UP) && (deriv_2[a_pos.peakPos] > 0))
|
||||||
|
{
|
||||||
|
SWD_IndexedValue a_indexdPeak;
|
||||||
|
a_indexdPeak.idx = i;
|
||||||
|
a_indexdPeak.value = a_line[a_pos.peakPos].pt3D.z;
|
||||||
|
indexedPeaks.push_back(a_indexdPeak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(indexedPeaks.begin(), indexedPeaks.end(), _sortFormZMinToMax);
|
||||||
|
|
||||||
|
//逐个peak检测:正peak
|
||||||
|
for (int i = 0; i < (int)indexedPeaks.size(); i++)
|
||||||
|
{
|
||||||
|
if (i == 153)
|
||||||
|
int kkk = 1;
|
||||||
|
int idx = indexedPeaks[i].idx;
|
||||||
|
posAttri a_pos = deriv_2_peaks[idx];
|
||||||
|
|
||||||
|
//检查两侧
|
||||||
|
int preEdge = -1;
|
||||||
|
for (int j = a_pos.peakPos - 1; j > 0; j--)
|
||||||
|
{
|
||||||
|
if ( (buff[j].peakState == UP)|| (buff[j].peakState == USED))
|
||||||
|
break;
|
||||||
|
else if (buff[j].peakState == DOWN)
|
||||||
|
{
|
||||||
|
if (deriv_1[j] < 0)
|
||||||
|
preEdge = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int postEdge = -1;
|
||||||
|
for (int j = a_pos.peakPos + 1; j < (int)a_line.size(); j++)
|
||||||
|
{
|
||||||
|
if ( (buff[j].peakState == DOWN) || (buff[j].peakState == USED))
|
||||||
|
break;
|
||||||
|
else if (buff[j].peakState == UP)
|
||||||
|
{
|
||||||
|
if (deriv_1[j] > 0)
|
||||||
|
postEdge = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if ((preEdge >= 0) && (postEdge >= 0)) //初步符合凸起特点
|
||||||
|
{
|
||||||
|
float edge_value_pre = deriv_1[preEdge];
|
||||||
|
float edge_value_post = deriv_1[postEdge];
|
||||||
|
//检测对称性
|
||||||
|
float min_value, max_value;
|
||||||
|
if ((-edge_value_pre) < edge_value_post)
|
||||||
|
{
|
||||||
|
min_value = -edge_value_pre;
|
||||||
|
max_value = edge_value_post;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
max_value = -edge_value_pre;
|
||||||
|
min_value = edge_value_post;
|
||||||
|
}
|
||||||
|
if (min_value > max_value / 5) //2023.05.02: 放宽。当凹陷在斜面上时,不再是maxValue/2的理想情况
|
||||||
|
{
|
||||||
|
//检查凹陷宽度深度,滤除噪声
|
||||||
|
float th_pre = edge_value_pre * 0.5;
|
||||||
|
int edge_pos_pre = -1;
|
||||||
|
for (int j = preEdge; j >= 0; j--)
|
||||||
|
{
|
||||||
|
if ((deriv_1[j] >= th_pre) && (a_line[j].nPointIdx >= 0)) //非填充点
|
||||||
|
{
|
||||||
|
edge_pos_pre = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float th_post = edge_value_post * 0.5;
|
||||||
|
int edge_pos_post = -1;
|
||||||
|
for (int j = postEdge; j < (int)a_line.size(); j++)
|
||||||
|
{
|
||||||
|
if ((deriv_1[j] <= th_post) && (a_line[j].nPointIdx >= 0)) //非填充点
|
||||||
|
{
|
||||||
|
edge_pos_post = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//检测宽度
|
||||||
|
if ((edge_pos_pre >= 0) && (edge_pos_post >= 0))
|
||||||
|
{
|
||||||
|
//float width = a_line->m_p3DPositiont[edge_pos_post].pt3D.y - a_line->m_p3DPositiont[edge_pos_pre].pt3D.y;
|
||||||
|
float width = a_line[postEdge].pt3D.y - a_line[preEdge].pt3D.y;
|
||||||
|
if (width < valleyParam.maxWidth)
|
||||||
|
{
|
||||||
|
float height = _computeHeight(a_line[edge_pos_pre].pt3D,
|
||||||
|
a_line[edge_pos_post].pt3D,
|
||||||
|
a_line[a_pos.peakPos].pt3D);
|
||||||
|
if (height > valleyParam.minHeight)
|
||||||
|
{
|
||||||
|
//精确确定peak点
|
||||||
|
int realPeakPos = preEdge;
|
||||||
|
for (int m = preEdge; m <= postEdge; m++)
|
||||||
|
{
|
||||||
|
if ((a_line[realPeakPos].pt3D.z > a_line[m].pt3D.z) && (a_line[m].nPointIdx >= 0))
|
||||||
|
realPeakPos = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSG_basicFeatureGap a_valley;
|
||||||
|
memset(&a_valley, 0, sizeof(SSG_basicFeatureGap));
|
||||||
|
a_valley.gapPeak.nPointIdx = realPeakPos;
|
||||||
|
a_valley.gapPeak.pt3D = a_line[realPeakPos].pt3D;
|
||||||
|
a_valley.gapPt_0.nPointIdx = edge_pos_pre;
|
||||||
|
a_valley.gapPt_0.pt3D = a_line[edge_pos_pre].pt3D;
|
||||||
|
a_valley.gapPt_1.nPointIdx = edge_pos_post;
|
||||||
|
a_valley.gapPt_1.pt3D = a_line[edge_pos_post].pt3D;
|
||||||
|
a_valley.lineIdx = lineIdx;
|
||||||
|
a_valley.gap_start = a_line[preEdge].pt3D.y;
|
||||||
|
a_valley.gap_width = width;
|
||||||
|
a_valley.gap_depth = height;
|
||||||
|
valleys.push_back(a_valley);
|
||||||
|
|
||||||
|
buff[preEdge].peakState = USED;
|
||||||
|
buff[postEdge].peakState = USED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 支持栅格数据(要求输入栅格数据) */
|
/* 支持栅格数据(要求输入栅格数据) */
|
||||||
//提取扫描线上的V型Valley
|
//提取扫描线上的V型Valley
|
||||||
void wd_getLineVFlaws(
|
void wd_getLineVFlaws(
|
||||||
std::vector<SVzNL3DPosition>& a_line,
|
std::vector<SVzNL3DPosition>& a_line,
|
||||||
const int lineIdx,
|
const int lineIdx,
|
||||||
const SWD_valleyParam valleyParam,
|
const SWD_valleyParam valleyParam,
|
||||||
|
const EWD_FlawType detectFlawType,
|
||||||
std::vector< SSG_basicFeatureGap>& valleys)
|
std::vector< SSG_basicFeatureGap>& valleys)
|
||||||
{
|
{
|
||||||
if (lineIdx == 286)
|
if (lineIdx == 286)
|
||||||
@ -10004,7 +10184,11 @@ void wd_getLineVFlaws(
|
|||||||
//使用窄窗口
|
//使用窄窗口
|
||||||
//凹陷:二阶导为极值,在极值的两边有一负一正的一阶导极值。
|
//凹陷:二阶导为极值,在极值的两边有一负一正的一阶导极值。
|
||||||
//float innerPara_max_valley_width = 20.0; //内部参数。控制最大凹陷检测宽度,用于过滤虚假凹陷
|
//float innerPara_max_valley_width = 20.0; //内部参数。控制最大凹陷检测宽度,用于过滤虚假凹陷
|
||||||
_valleyDetect(a_line, lineIdx, startId, endId, deriv_1_peaks, deriv_2_peaks, deriv_1_narrow, deriv_2_narrow, valleys, valleyParam);
|
if(keWD_FlawType_Depression == detectFlawType)
|
||||||
|
_depressionDetect(a_line, lineIdx, startId, endId, deriv_1_peaks, deriv_2_peaks, deriv_1_narrow, deriv_2_narrow, valleys, valleyParam);
|
||||||
|
else if (keWD_FlawType_Protrusion == detectFlawType)
|
||||||
|
_protrusionDetect(a_line, lineIdx, startId, endId, deriv_1_peaks, deriv_2_peaks, deriv_1_narrow, deriv_2_narrow, valleys, valleyParam);
|
||||||
|
//else if (keSG_FlawType_Dep_Prot == detectFlawType)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
//version 1.0.0 :焊缝(平缝)识别检测算法初始发布
|
//version 1.0.0 :焊缝(平缝)识别检测算法初始发布
|
||||||
//version 1.1.0 :焊缝(平缝)识别修正回归测试中发现的bug
|
//version 1.1.0 :焊缝(平缝)识别修正回归测试中发现的bug
|
||||||
std::string m_strVersion = "weldSeamAlgo_1.1.0";
|
//version 1.2.0 :焊缝(平缝)识别添加博清模拟数据中的凸起焊缝,通过参数选择识别类型(不支持自动识别)
|
||||||
|
std::string m_strVersion = "weldSeamAlgo_1.2.0";
|
||||||
|
|
||||||
const char* wd_weldSeamAlgoVersion(void)
|
const char* wd_weldSeamAlgoVersion(void)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user