algoLib/sourceCode/gasFillingPortPosition.cpp
jerryzeng 47e3a04bf0 HC_chanelSpaceMeasure version 1.0.0
槽道间距检测初始版本, 包含了博清工件组装的最新修改
2026-01-05 01:19:04 +08:00

369 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <vector>
#include "SG_baseDataType.h"
#include "SG_baseAlgo_Export.h"
#include "gasFillingPortPosition_Export.h"
#include <opencv2/opencv.hpp>
#include <limits>
//读版本号
//version 1.0.0 : base version release to customer
//version 1.1.0 : 改进了算法,顶面点提取更准确
std::string m_strVersion = "1.1.0";
const char* wd_gasFillingPortPositionVersion(void)
{
return m_strVersion.c_str();
}
//提取加气口中心位姿
SSG_6DOF wd_getGasFillingPortPosition(
std::vector< std::vector<SVzNL3DPosition>>& scanLines,
const SSX_gasFillingPortPara gasFillingPortPara,
const SSG_lineSegParam lineSegPara,
const SSG_outlierFilterParam filterParam,
SSG_treeGrowParam growParam,
int* errCode)
{
*errCode = 0;
SSG_6DOF resultPose;
memset(&resultPose, 0, sizeof(SSG_6DOF));
int lineNum = (int)scanLines.size();
int linePtNum = (int)scanLines[0].size();
bool isGridData = true;
//提取直线段特征
//垂直跳变特征提取
SVzNLRangeD lineLenRange;
lineLenRange.max = 1.2 * (gasFillingPortPara.outerD - gasFillingPortPara.innerD);
lineLenRange.min = 0.5 * (gasFillingPortPara.outerD - gasFillingPortPara.innerD) / 2;
std::vector<std::vector<SSG_featureSemiCircle>> lineFeatures_v_raw;
std::vector<std::vector<SSG_featureSemiCircle>> invalidFeatures_v_raw; //确定非直线特征,用于防止在水平处理时被认为是有效点
for (int line = 0; line < lineNum; line++)
{
if (line == 310)
int kkk = 1;
std::vector<SVzNL3DPosition>& lineData = scanLines[line];
if (linePtNum != (int)lineData.size())
isGridData = false;
//滤波,滤除异常点
sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], linePtNum, filterParam);
std::vector<SSG_featureSemiCircle> line_features;
std::vector<SSG_featureSemiCircle> invalid_features;
int dataSize = (int)lineData.size();
wd_surfaceLineSegment(
lineData,
line,
lineLenRange,
lineSegPara,
line_features,
invalid_features);
lineFeatures_v_raw.push_back(line_features);
invalidFeatures_v_raw.push_back(invalid_features);
}
if (false == isGridData)//数据不是网格格式
{
*errCode = SG_ERR_NOT_GRID_FORMAT;
return resultPose;
}
//生成水平扫描
std::vector<std::vector<SVzNL3DPosition>> 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<std::vector<SSG_featureSemiCircle>> lineFeatures_h_raw;
std::vector<std::vector<SSG_featureSemiCircle>> invalidFeatures_h_raw; //确定非直线特征,用于防止在垂直处理时被认为是有效点
int lineNum_h_raw = (int)hLines_raw.size();
for (int line = 0; line < lineNum_h_raw; line++)
{
if (line == 974)
int kkk = 1;
std::vector<SVzNL3DPosition>& lineData = hLines_raw[line];
//滤波,滤除异常点
int ptNum = (int)lineData.size();
sg_lineDataRemoveOutlier_changeOriginData(&lineData[0], ptNum, filterParam);
std::vector<SSG_featureSemiCircle> line_features;
std::vector<SSG_featureSemiCircle> invalid_features;
int dataSize = (int)lineData.size();
wd_surfaceLineSegment(
lineData,
line,
lineLenRange,
lineSegPara,
line_features,
invalid_features);
lineFeatures_h_raw.push_back(line_features);
invalidFeatures_h_raw.push_back(invalid_features);
}
//标注
std::vector<std::vector<SSG_featureClusteringInfo>> featureInfoMask;
std::vector<std::vector<SVzNL3DPoint>> feature3DInfo;
featureInfoMask.resize(lineNum);
feature3DInfo.resize(lineNum);
for (int i = 0; i < lineNum; i++)
{
featureInfoMask[i].resize(lineNum_h_raw);
feature3DInfo[i].resize(lineNum_h_raw);
}
//垂直标注
for (int line = 0; line < lineNum; line++)
{
if (line == 390)
int kkk = 1;
std::vector<SSG_featureSemiCircle>& a_lineJumpFeature = lineFeatures_v_raw[line];
for (int m = 0, m_max = (int)a_lineJumpFeature.size(); m < m_max; m++)
{
int px = a_lineJumpFeature[m].lineIdx;
int py = a_lineJumpFeature[m].midPtIdx;
SSG_featureClusteringInfo& a_featureInfo = featureInfoMask[px][py];
a_featureInfo.clusterID = 0;
a_featureInfo.featurType = 1;
a_featureInfo.featureIdx_v = m;
a_featureInfo.featureIdx_h = 0;
a_featureInfo.lineIdx = px;
a_featureInfo.ptIdx = py;
a_featureInfo.flag = 0;
SVzNL3DPoint& a_feature3D = feature3DInfo[px][py];
a_feature3D = a_lineJumpFeature[m].midPt;
}
}
//水平标注
for (int line = 0; line < lineNum_h_raw; line++)
{
std::vector<SSG_featureSemiCircle>& a_lineJumpFeature = lineFeatures_h_raw[line];
for (int m = 0, m_max = (int)a_lineJumpFeature.size(); m < m_max; m++)
{
int py = a_lineJumpFeature[m].lineIdx;
int px = a_lineJumpFeature[m].midPtIdx;
SSG_featureClusteringInfo& a_featureInfo = featureInfoMask[px][py];
if (a_featureInfo.featurType == 0)
{
a_featureInfo.clusterID = 0;
a_featureInfo.lineIdx = px;
a_featureInfo.ptIdx = py;
a_featureInfo.flag = 0;
}
a_featureInfo.featurType += 2;
a_featureInfo.featureIdx_h = m;
SVzNL3DPoint& a_feature3DValue = feature3DInfo[px][py];
a_feature3DValue = { a_lineJumpFeature[m].midPt.y, a_lineJumpFeature[m].midPt.x, a_lineJumpFeature[m].midPt.z };
}
}
//聚类
//采用迭代思想,回归思路进行高效聚类
std::vector<std::vector< SVzNL2DPoint>> clusters; //只记录位置
std::vector<SVzNL3DRangeD> clustersRoi3D;
int clusterID = 1;
int clusterCheckWin = 5;
for (int y = 0; y < lineNum_h_raw; y++)
{
for (int x = 0; x < lineNum; x++)
{
SSG_featureClusteringInfo& a_featureInfo = featureInfoMask[x][y];
if ( (0 == a_featureInfo.featurType) || (a_featureInfo.clusterID > 0)) //非特征或已经处理
continue;
SVzNL3DPoint& a_feature3DValue = feature3DInfo[x][y];
SVzNL3DRangeD a_clusterRoi;
a_clusterRoi.xRange.min = a_feature3DValue.x;
a_clusterRoi.xRange.max = a_feature3DValue.x;
a_clusterRoi.yRange.min = a_feature3DValue.y;
a_clusterRoi.yRange.max = a_feature3DValue.y;
a_clusterRoi.zRange.min = a_feature3DValue.z;
a_clusterRoi.zRange.max = a_feature3DValue.z;
SVzNL2DPoint a_seedPos = {x, y};
std::vector< SVzNL2DPoint> a_cluster;
a_cluster.push_back(a_seedPos);
wd_gridPointClustering(
featureInfoMask,//int记录特征标记和clusterID附加一个flag
feature3DInfo,//double,记录坐标信息
clusterCheckWin, //搜索窗口
growParam,//聚类条件
clusterID, //当前Cluster的ID
a_cluster, //result
a_clusterRoi
);
clusters.push_back(a_cluster);
clustersRoi3D.push_back(a_clusterRoi);
clusterID++;
}
}
//聚类结果分析
//取最前面的一个聚类
int clusterSize = (int)clusters.size();
int bestClusterIdx = -1;
double minZ = -1;
double wTh1 = gasFillingPortPara.innerD * 0.8;
double wTh2 = gasFillingPortPara.outerD * 1.1;
for (int i = 0; i < clusterSize; i++)
{
SVzNL3DRangeD& a_roi = clustersRoi3D[i];
double xWidth = a_roi.xRange.max - a_roi.xRange.min;
double yWidth = a_roi.yRange.max - a_roi.yRange.min;
double meanZ = (a_roi.zRange.min + a_roi.zRange.max) / 2;
if ((xWidth > wTh1) && (xWidth < wTh2) && (yWidth > wTh1) && (yWidth < wTh2))
{
if (minZ < 0)
{
minZ = meanZ;
bestClusterIdx = i;
}
else
{
if (minZ > meanZ)
{
minZ = meanZ;
bestClusterIdx = i;
}
}
}
}
if (minZ < 0)
{
*errCode = SG_ERR_NOT_GRID_FORMAT;
return resultPose;
}
std::vector< SVzNL2DPoint>& obj_cluster = clusters[bestClusterIdx];
//提取端面上的点
//首先将无效点置标志
for (int line = 0; line < lineNum; line++)
{
std::vector<SSG_featureSemiCircle>& line_invalidFeature = invalidFeatures_v_raw[line];
for (int n = 0; n < line_invalidFeature.size(); n++)
{
SSG_featureSemiCircle& a_invalidFeature = line_invalidFeature[n];
int lineIdx = a_invalidFeature.lineIdx;
for (int m = a_invalidFeature.startPtIdx; m <= a_invalidFeature.endPtIdx; m++)
{
SVzNL3DPosition& a_pt3d = scanLines[lineIdx][m];
a_pt3d.nPointIdx = 2;
}
}
}
for (int line = 0; line < lineNum_h_raw; line++)
{
std::vector<SSG_featureSemiCircle>& line_invalidFeature = invalidFeatures_h_raw[line];
for (int m = 0, m_max = (int)line_invalidFeature.size(); m < m_max; m++)
{
for (int n = 0; n < line_invalidFeature.size(); n++)
{
SSG_featureSemiCircle& a_invalidFeature = line_invalidFeature[n];
int ptIdx = a_invalidFeature.lineIdx;
for (int m = a_invalidFeature.startPtIdx; m <= a_invalidFeature.endPtIdx; m++)
{
SVzNL3DPosition& a_pt3d = scanLines[m][ptIdx];
a_pt3d.nPointIdx = 3;
}
}
}
}
//提取端面点
std::vector< cv::Point3f> planePts;
for (int i = 0, i_max = (int)obj_cluster.size(); i < i_max; i++)
{
SVzNL2DPoint a_pos = obj_cluster[i];
SSG_featureClusteringInfo& a_featureInfo = featureInfoMask[a_pos.x][a_pos.y];
int type_v = a_featureInfo.featurType & 0x01;
int type_h = a_featureInfo.featurType & 0x02;
if (type_v > 0)
{
int lineIdx = a_featureInfo.lineIdx;
int featureIdx = a_featureInfo.featureIdx_v;
SSG_featureSemiCircle& a_feature = lineFeatures_v_raw[lineIdx][featureIdx];
for (int m = a_feature.startPtIdx; m <= a_feature.endPtIdx; m++)
{
SVzNL3DPosition& a_pt3d = scanLines[lineIdx][m];
if ((a_pt3d.nPointIdx == 0) && (a_pt3d.pt3D.z > 1e-4))
{
a_pt3d.nPointIdx = 1;
cv::Point3f a_planePt = { (float)a_pt3d.pt3D.x, (float)a_pt3d.pt3D.y, (float)a_pt3d.pt3D.z };
planePts.push_back(a_planePt);
}
}
}
if (type_h > 0)
{
int ptIdx = a_featureInfo.ptIdx;
int featureIdx = a_featureInfo.featureIdx_h;
SSG_featureSemiCircle& a_feature = lineFeatures_h_raw[ptIdx][featureIdx];
for (int m = a_feature.startPtIdx; m <= a_feature.endPtIdx; m++)
{
SVzNL3DPosition& a_pt3d = scanLines[m][ptIdx];
if ( (a_pt3d.nPointIdx == 0) && (a_pt3d.pt3D.z >1e-4))
{
a_pt3d.nPointIdx = 1;
cv::Point3f a_planePt = { (float)a_pt3d.pt3D.x, (float)a_pt3d.pt3D.y, (float)a_pt3d.pt3D.z };
planePts.push_back(a_planePt);
}
}
}
}
// 拟合平面,计算法向
//计算面参数: z = Ax + By + C
//res: [0]=A, [1]= B, [2]=-1.0, [3]=C,
std::vector<double> res;
vzCaculateLaserPlane(planePts, res);
//将平面调整为水平平面
SSG_planeCalibPara calibPara = adjustPlaneToXYPlane(
res[0], res[1], res[2] //平面法向量
);
//投影
std::vector< SVzNL3DPoint> projectionPts;
double calibMeanZ = 0;
int planePtSize = (int)planePts.size();
for(int i = 0; i < planePtSize; i ++)
{
SVzNL3DPoint a_calibPt;
a_calibPt.x = (float)(planePts[i].x * calibPara.planeCalib[0] + planePts[i].y * calibPara.planeCalib[1] + planePts[i].z * calibPara.planeCalib[2]);
a_calibPt.y = (float)(planePts[i].x * calibPara.planeCalib[3] + planePts[i].y * calibPara.planeCalib[4] + planePts[i].z * calibPara.planeCalib[5]);
a_calibPt.z = (float)(planePts[i].x * calibPara.planeCalib[6] + planePts[i].y * calibPara.planeCalib[7] + planePts[i].z * calibPara.planeCalib[8]);
calibMeanZ += a_calibPt.z;
projectionPts.push_back(a_calibPt);
}
calibMeanZ = calibMeanZ / planePtSize;
//圆最小二乘拟合
SVzNL3DPoint calibCenter;
double radius = 0;
double fittingErr = fitCircleByLeastSquare(
projectionPts,
calibCenter,
radius);
calibCenter.z = calibMeanZ;
//center点旋转回去
SVzNL3DPoint center;
center.x = (float)(calibCenter.x * calibPara.invRMatrix[0] + calibCenter.y * calibPara.invRMatrix[1] + calibCenter.z * calibPara.invRMatrix[2]);
center.y = (float)(calibCenter.x * calibPara.invRMatrix[3] + calibCenter.y * calibPara.invRMatrix[4] + calibCenter.z * calibPara.invRMatrix[5]);
center.z = (float)(calibCenter.x * calibPara.invRMatrix[6] + calibCenter.y * calibPara.invRMatrix[7] + calibCenter.z * calibPara.invRMatrix[8]);
resultPose.x = center.x;
resultPose.y = center.y;
resultPose.z = center.z;
resultPose.x_roll = res[0];
resultPose.y_pitch = res[1];
resultPose.z_yaw = res[2];
return resultPose;
}