#include #include "SG_baseDataType.h" #include "SG_baseAlgo_Export.h" #include "SG_sieveNodeDetection_Export.h" #include #include #define ALGO_USE_PATTERN_MATCH 0 void sg_lineDataR(SVzNL3DLaserLine* a_line, const double* camPoseR, double groundH) { lineDataRT(a_line, camPoseR, groundH); } #if 0 //扫描线处理,进行垂直方向的特征提取和生长 void sg_sieveNodeDetection_lineProc( SVzNL3DLaserLine* a_line, int lineIdx, int* errCode, std::vector>& all_vLineFeatures, std::vector>& noisePts, const SSG_sieveNodeDetectionParam sieveDetectParam) { std::vector< SSG_featureSemiCircle> a_line_features; //滤波,滤除异常点 std::vector filterData; std::vector lineNoisePts; sg_lineDataRemoveOutlier(a_line->p3DPosition, a_line->nPositionCnt, sieveDetectParam.filterParam, filterData, lineNoisePts); noisePts.push_back(lineNoisePts); sg_getLineUpperSemiCircleFeature( filterData.data(), filterData.size(), lineIdx, sieveDetectParam.sieveDiameter, sieveDetectParam.slopeParam, a_line_features); all_vLineFeatures.push_back(a_line_features); //空行也加入,保证能按行号索引 return; } #endif int _checkFeatureSplit( SSG_featureSemiCircle& a_feaurue, std::vector< SSG_featureSemiCircle>& chk_line_feature, double splitMinDist, double splitMaxDist) //在此距离内为有效分叉 { int split = -1; for (int i = 0, i_max = chk_line_feature.size(); i < i_max; i++) { if (i < i_max - 1) { if ((chk_line_feature[i].midPt.y < a_feaurue.midPt.y) && (chk_line_feature[i + 1].midPt.y > a_feaurue.midPt.y)) { double dist_1 = abs(chk_line_feature[i].midPt.y - a_feaurue.midPt.y); double dist_2 = abs(chk_line_feature[i+1].midPt.y - a_feaurue.midPt.y); if ((dist_1 > splitMinDist) && (dist_1 < splitMaxDist) && (dist_2 > splitMinDist)&& (dist_2 < splitMaxDist)) { split = i; break; } } } } return split; } bool compareByWidth(const SSG_featureSemiCircle& a, const SSG_featureSemiCircle& b) { return a.width < b.width; } SVzNL3DPoint _getMeanPt( std::vector& nodes, SVzNL3DLaserLine* laser3DPoints) { int nodeSize = nodes.size(); int num = 0; SVzNL3DPoint meanPt = { 0.0,0.0,0.0 }; for (int i = 0; i < nodeSize; i++) { SSG_featureSemiCircle& a_node = nodes[i]; int lineIdx = a_node.lineIdx; for (int j = a_node.startPtIdx; j <= a_node.endPtIdx; j++) { if (laser3DPoints[lineIdx].p3DPosition[j].pt3D.z > 1e-4) { num++; meanPt.x += laser3DPoints[lineIdx].p3DPosition[j].pt3D.x; meanPt.y += laser3DPoints[lineIdx].p3DPosition[j].pt3D.y; meanPt.z += laser3DPoints[lineIdx].p3DPosition[j].pt3D.z; } } } if (num > 0) { meanPt.x = meanPt.x / num; meanPt.y = meanPt.y / num; meanPt.z = meanPt.z / num; } return meanPt; } SVzNL2DPoint _getNearestScanPt( std::vector& nodes, SVzNL3DLaserLine* laser3DPoints, SVzNL3DPoint objPt) { int nodeSize = nodes.size(); SVzNL2DPoint bestPos = { -1, -1 }; double minDist = -1; for (int i = 0; i < nodeSize; i++) { SSG_featureSemiCircle& a_node = nodes[i]; int lineIdx = a_node.lineIdx; for (int j = a_node.startPtIdx; j <= a_node.endPtIdx; j++) { if (laser3DPoints[lineIdx].p3DPosition[j].pt3D.z > 1e-4) { SVzNL3DPoint& a_pt = laser3DPoints[lineIdx].p3DPosition[j].pt3D; double dist = sqrt(pow(a_pt.x - objPt.x, 2) + pow(a_pt.y - objPt.y, 2)); if (minDist < 0) { minDist = dist; bestPos = { a_node.lineIdx, j }; } else { if (minDist > dist) { minDist = dist; bestPos = { a_node.lineIdx, j }; } } } } } return bestPos; } //搜索目标在排序目标中的位置。返回的是排序目标前一位的序号,-1为最后一个 int getObjPostPos(std::vector& sortedTrees, int treeID, std::vector& trees, bool HPos) { SSG_semiCircleFeatureTree& obj_tree = trees[treeID]; for (int i = 0, i_max = sortedTrees.size(); i < i_max; i++) { int a_tree_id = sortedTrees[i]; SSG_semiCircleFeatureTree& a_tree = trees[a_tree_id]; if (((obj_tree.centerPt.x < a_tree.centerPt.x) && (true == HPos)) || ((obj_tree.centerPt.y < a_tree.centerPt.y) && (false == HPos))) { return i; } } return -1; //最后一个 } typedef struct { SVzNL2DPoint nodePos; int LT_link; int RT_link; int LB_link; int RB_link; double LT_dist; double RT_dist; double RB_dist; double LB_dist; }NodeQuadLink; int getObjPostPos(std::vector& sortedLine, int nodeID, std::vector& nodeLink, bool HPos) { SVzNL2DPoint& nodePos = nodeLink[nodeID].nodePos; for (int i = 0, i_max = sortedLine.size(); i < i_max; i++) { int a_node_id = sortedLine[i]; SVzNL2DPoint& sorting_node_pos = nodeLink[a_node_id].nodePos; if (((nodePos.x < sorting_node_pos.x) && (true == HPos)) || ((nodePos.y < sorting_node_pos.y) && (false == HPos))) { return i; } } return -1; //最后一个 } void _recursiveSorting( int nodeId, std::vector>& hSorting, std::vector< int>& nodeProcFlag, std::vector< int>& nodeSortingLineID, std::vector< NodeQuadLink>& nodeLinks, bool HPos, int* maxLineId) { std::vector processBuff; processBuff.push_back(nodeId); while (processBuff.size() > 0) { int nodeId = processBuff.front(); if (nodeProcFlag[nodeId] == 0) { int currLineId = nodeSortingLineID[nodeId]; if (*maxLineId < currLineId) *maxLineId = currLineId; std::vector& currLine = hSorting[currLineId]; //将当前Node插入currLine int nodePos = getObjPostPos(currLine, nodeId, nodeLinks, HPos); if (nodePos < 0) currLine.push_back(nodeId); else currLine.insert(currLine.begin() + nodePos, nodeId); nodeProcFlag[nodeId] = 1; //检查Link NodeQuadLink& currLink = nodeLinks[nodeId]; if ((currLink.LT_dist > 0) && (currLineId > 0)) { int linkNode = currLink.LT_link; int lineId = currLineId - 1; nodeSortingLineID[linkNode] = lineId; processBuff.push_back(linkNode); currLink.LT_dist = -1.0; nodeLinks[linkNode].RB_dist = -1.0; //取消 } if ((currLink.RT_dist > 0) && (currLineId > 0)) { int linkNode = currLink.RT_link; int lineId = currLineId - 1; nodeSortingLineID[linkNode] = lineId; processBuff.push_back(linkNode); currLink.RT_dist = -1.0; nodeLinks[linkNode].LB_dist = -1.0; //取消 } if ((currLink.LB_dist > 0) && (currLineId < hSorting.size() - 1)) { int linkNode = currLink.LB_link; int lineId = currLineId + 1; nodeSortingLineID[linkNode] = lineId; processBuff.push_back(linkNode); currLink.LB_dist = -1.0; nodeLinks[linkNode].RT_dist = -1.0; //取消 } if ((currLink.RB_dist > 0) && (currLineId < hSorting.size() - 1)) { int linkNode = currLink.RB_link; int lineId = currLineId + 1; nodeSortingLineID[linkNode] = lineId; processBuff.push_back(linkNode); currLink.RB_dist = -1.0; nodeLinks[linkNode].LT_dist = -1.0; //取消 } } processBuff.erase(processBuff.begin()); } } void _lineFillNullNode( std::vector& sortingNodes_line, std::vector< NodeQuadLink>& nodeLinks, const double lineNodeDistMean ) { for (int i = 0; i < sortingNodes_line.size() -1; i++) { SVzNL3DPosition node_1 = sortingNodes_line[i]; if (node_1.nPointIdx < 0) continue; SVzNL3DPosition node_2 = sortingNodes_line[i + 1]; double dist = sqrt(pow(node_1.pt3D.x - node_2.pt3D.x, 2) + pow(node_1.pt3D.y - node_2.pt3D.y, 2)); int n = (int)(dist / lineNodeDistMean + 0.5) - 1; if (n > 0) { //判断遗漏几个目标 double x_step = (node_2.pt3D.x - node_1.pt3D.x) / (n + 1); double y_step = (node_2.pt3D.y - node_1.pt3D.y) / (n + 1); double z_step = (node_2.pt3D.z - node_1.pt3D.z) / (n + 1); for (int m = 0; m < n; m++) { SVzNL3DPosition a_newNode; a_newNode.nPointIdx = -1; a_newNode.pt3D.x = x_step * (m + 1) + node_1.pt3D.x; a_newNode.pt3D.y = y_step * (m + 1) + node_1.pt3D.y; a_newNode.pt3D.z = z_step * (m + 1) + node_1.pt3D.z; sortingNodes_line.insert(sortingNodes_line.begin() + i + 1 + m, a_newNode); } } } } void sg_getSieveNodes( SVzNL3DLaserLine* laser3DPoints, int lineNum, const SSG_sieveNodeDetectionParam sieveDetectParam, std::vector>& nodePos) { const int hole_max_ptSize = 20; int errCode = 0; for (int i = 0; i < lineNum; i++) { if (i == 19) int kkk = 1; sg_lineDataRemoveOutlier_changeOriginData( laser3DPoints[i].p3DPosition, laser3DPoints[i].nPositionCnt, sieveDetectParam.filterParam); //将nPointIdx转义使用前清零 for (int j = 0; j < laser3DPoints[i].nPositionCnt; j++) laser3DPoints[i].p3DPosition[j].nPointIdx = 0; } //孔洞检测,对小的孔洞需要合并 int maskY = laser3DPoints[0].nPositionCnt; int maskX = lineNum; //生成孔洞标注Mask,进行目标标注 cv::Mat bwImg = cv::Mat::zeros(maskY, maskX, CV_8UC1);//rows, cols for (int i = 0; i < lineNum; i++) { for (int j = 0; j < laser3DPoints[i].nPositionCnt; j++) { if(laser3DPoints[i].p3DPosition[j].pt3D.z < 1e-4) bwImg.at(j, i) = 1; } } //孔洞目标标注 cv::Mat labImg; std::vector labelRgns; SG_TwoPassLabel(bwImg, labImg, labelRgns, 8); //将孔洞目标进行标识 cv::Mat holeMask = cv::Mat::zeros(maskY, maskX, CV_32SC1);//rows, cols for (int i = 0, i_max = labelRgns.size(); i < i_max; i++) { int rgnID = labelRgns[i].labelID; if (labelRgns[i].ptCounter < hole_max_ptSize) //孔洞 { for (int m = labelRgns[i].roi.left; m <= labelRgns[i].roi.right; m++) { for (int n = labelRgns[i].roi.top; n <= labelRgns[i].roi.bottom; n++) { if (rgnID == labImg.at(n, m)) holeMask.at(n, m) = rgnID; } } } } #if _OUTPUT_LINE_PROC_RESULT cv::Mat holeMaskImage; cv::normalize(holeMask, holeMaskImage, 0, 255, cv::NORM_MINMAX, CV_8U); cv::imwrite("holeMask.png", holeMaskImage); #endif std::vector> all_vLineFeatures; for (int i = 0; i < lineNum; i++) { std::vector< SSG_featureSemiCircle> a_line_features; sg_getLineUpperSemiCircleFeature( laser3DPoints[i].p3DPosition, laser3DPoints[i].nPositionCnt, i, sieveDetectParam.sieveDiameter, sieveDetectParam.slopeParam, a_line_features, holeMask); //将nPointIdx转义使用前清零 for (int j = 0; j < laser3DPoints[i].nPositionCnt; j++) laser3DPoints[i].p3DPosition[j].nPointIdx = 0; all_vLineFeatures.push_back(a_line_features); //空行也加入,保证能按行号索引 } //根据筛网的特点去除无效的feature。当上下两个feature在下一条扫描线被合并成一个feature时,说明上一条扫描线的两个feature是无效feature。其相邻的feature均为无效feature for (int i = 0; i < lineNum; i++) { //与前一条扫描线比较,寻找开始 std::vector< SSG_featureSemiCircle>& line_features = all_vLineFeatures[i]; if (i > 0) { std::vector< SSG_featureSemiCircle>& pre_line_features = all_vLineFeatures[i-1]; for (int j = 0, j_max = line_features.size(); j < j_max; j++) { int split = _checkFeatureSplit(line_features[j], pre_line_features, sieveDetectParam.sieveDiameter/2, sieveDetectParam.sieveHoleSize); if (split >= 0) { pre_line_features[split].flag = FEATURE_FLAG_INVLD_END; pre_line_features[split + 1].flag = FEATURE_FLAG_INVLD_END; line_features[j].flag = FEATURE_FLAG_VALID_START; } } } //与后一条扫描线比较,寻找结束 if (i < lineNum - 1) { std::vector< SSG_featureSemiCircle>& post_line_features = all_vLineFeatures[i + 1]; for (int j = 0, j_max = line_features.size(); j < j_max; j++) { int split = _checkFeatureSplit(line_features[j], post_line_features, sieveDetectParam.sieveDiameter/2, sieveDetectParam.sieveHoleSize); if (split >= 0) { post_line_features[split].flag = FEATURE_FLAG_INVLD_START; post_line_features[split + 1].flag = FEATURE_FLAG_INVLD_START; line_features[j].flag = FEATURE_FLAG_VALID_END; } } } } //feature生长。碰到无效feature生长停止。无效生长可以作为生长起点。其生长树上的所有feature均为无效feature std::vector trees; std::vector stopTrees; //停止生长的树 std::vector invalidTrees; //被移除的树,这些树可能将目标分成多个树,从而被移除。需要保存下来迭代分析 for (int i = 0; i < lineNum; i++) { //与前一条扫描线比较,寻找开始 std::vector< SSG_featureSemiCircle>& line_features = all_vLineFeatures[i]; sg_getFeatureGrowingTrees_semiCircle( line_features, i, lineNum, trees, stopTrees, invalidTrees, sieveDetectParam.growParam); } //精确确定焊接点 for (int i = 0, i_max = stopTrees.size(); i < i_max; i++) { //焊接定为为所有点的(x,y,z)的平均处(质心)。 SSG_semiCircleFeatureTree& a_tree = stopTrees[i]; a_tree.centerPt = _getMeanPt(a_tree.treeNodes, laser3DPoints); a_tree.centerPos = _getNearestScanPt(a_tree.treeNodes, laser3DPoints, a_tree.centerPt); //判断焊点是否被焊接过:以中间点的高度与左右两边的中间高度比较 } //按行排序 #if 1 // (1)量化到2D,建立2D索引实现有序搜索 SVzNL3DRangeD ROI = sg_getScanDataROI(laser3DPoints, lineNum); double scale_x = 1.0; double scale_y = 1.0; int rows = (int)((ROI.yRange.max - ROI.yRange.min) / scale_y) + 1; int cols = (int)((ROI.xRange.max - ROI.xRange.min) / scale_x) + 1; if ((rows == 0) || (cols == 0)) return; cv::Mat objMask = cv::Mat(rows, cols, CV_32SC1, -1);//rows, cols for (int i = 0, i_max = stopTrees.size(); i < i_max; i++) { SVzNL3DPoint treeCenter = laser3DPoints[stopTrees[i].centerPos.x].p3DPosition[stopTrees[i].centerPos.y].pt3D; int px = (int)((treeCenter.x - ROI.xRange.min) / scale_x); int py = (int)((treeCenter.y - ROI.yRange.min) / scale_y); objMask.at(py, px) = i; } #endif std::vector< NodeQuadLink> nodeLinks(stopTrees.size(), { {0,0},-1,-1,-1,-1, -1.0, -1.0, -1.0, -1.0}); double neighbourDistTh = sieveDetectParam.sieveHoleSize * 1.2; //以正方形为模型,边长为1,则对角线为1.414,取1.2为长度门限 for (int i = 0, i_max = stopTrees.size(); i < i_max; i++) { SSG_semiCircleFeatureTree& tree_1 = stopTrees[i]; NodeQuadLink& link_1 = nodeLinks[i]; link_1.nodePos = tree_1.centerPos; for (int j = i + 1; j < i_max; j++) { SSG_semiCircleFeatureTree& tree_2 = stopTrees[j]; NodeQuadLink& link_2 = nodeLinks[j]; double dist = sqrt(pow(tree_1.centerPt.x - tree_2.centerPt.x, 2) + pow(tree_1.centerPt.y - tree_2.centerPt.y, 2)); if (dist < neighbourDistTh) { if (tree_1.centerPt.x < tree_2.centerPt.x) //left { if (tree_1.centerPt.y < tree_2.centerPt.y) //top { //tree1:RB link is tree_2 //tree2:LT link is tree_1 if ( (link_1.RB_link >= 0) || (link_2.LT_link >= 0)) { bool currIsBest = true; //判断最佳关系 if ((link_1.RB_link >= 0) && (dist > link_1.RB_dist)) currIsBest = false; if ((link_2.LT_link >= 0) && (dist > link_2.LT_dist)) currIsBest = false; if (true == currIsBest) { if (link_1.RB_link >= 0) { nodeLinks[link_1.RB_link].LT_link = -1; nodeLinks[link_1.RB_link].LT_dist = 0; } link_1.RB_link = j; link_1.RB_dist = dist; if (link_2.LT_link >= 0) { nodeLinks[link_2.LT_link].RB_link = -1; nodeLinks[link_2.LT_link].RB_dist = 0; } link_2.LT_link = i; link_2.LT_dist = dist; } } else { link_1.RB_link = j; link_1.RB_dist = dist; link_2.LT_link = i; link_2.LT_dist = dist; } } else//bottom { //tree1:RT link is tree_2 //tree2:LB link is tree_1 if ((link_1.RT_link >= 0) || (link_2.LB_link >= 0)) { bool currIsBest = true; //判断最佳关系 if ((link_1.RT_link >= 0) && (dist > link_1.RT_dist)) currIsBest = false; if ((link_2.LB_link >= 0) && (dist > link_2.LB_dist)) currIsBest = false; if (true == currIsBest) { if (link_1.RT_link >= 0) { nodeLinks[link_1.RT_link].LB_link = -1; nodeLinks[link_1.RT_link].LB_dist = 0; } link_1.RT_link = j; link_1.RT_dist = dist; if (link_2.LB_link >= 0) { nodeLinks[link_2.LB_link].RT_link = -1; nodeLinks[link_2.LB_link].RT_dist = 0; } link_2.LB_link = i; link_2.LB_dist = dist; } } else { link_1.RT_link = j; link_1.RT_dist = dist; link_2.LB_link = i; link_2.LB_dist = dist; } } } else //right { if (tree_1.centerPt.y < tree_2.centerPt.y) //top { //tree1:LB link is tree_2 //tree2:RT link is tree_1 if ((link_1.LB_link >= 0) || (link_2.RT_link >= 0)) { bool currIsBest = true; //判断最佳关系 if ((link_1.LB_link >= 0) && (dist > link_1.LB_dist)) currIsBest = false; if ((link_2.RT_link >= 0) && (dist > link_2.RT_dist)) currIsBest = false; if (true == currIsBest) { if (link_1.LB_link >= 0) { nodeLinks[link_1.LB_link].RT_link = -1; nodeLinks[link_1.LB_link].RT_dist = 0; } link_1.LB_link = j; link_1.LB_dist = dist; if (link_2.RT_link >= 0) { nodeLinks[link_2.RT_link].LB_link = -1; nodeLinks[link_2.RT_link].LB_dist = 0; } link_2.RT_link = i; link_2.RT_dist = dist; } } else { link_1.LB_link = j; link_1.LB_dist = dist; link_2.RT_link = i; link_2.RT_dist = dist; } } else //bottom { //tree1:LT link is tree_2 //tree2:RB link is tree_1 if ((link_1.LT_link >= 0) || (link_2.RB_link >= 0)) { bool currIsBest = true; //判断最佳关系 if ((link_1.LT_link >= 0) && (dist > link_1.LT_dist)) currIsBest = false; if ((link_2.RB_link >= 0) && (dist > link_2.RB_dist)) currIsBest = false; if (true == currIsBest) { if (link_1.LT_link >= 0) { nodeLinks[link_1.LT_link].RB_link = -1; nodeLinks[link_1.LT_link].RB_dist = 0; } link_1.LT_link = j; link_1.LT_dist = dist; if (link_2.RB_link >= 0) { nodeLinks[link_2.RB_link].LT_link = -1; nodeLinks[link_2.RB_link].LT_dist = 0; } link_2.RB_link = i; link_2.RB_dist = dist; } } else { link_1.LT_link = j; link_1.LT_dist = dist; link_2.RB_link = i; link_2.RB_dist = dist; } } } } } } //(2)建立节点间的相互关系 std::vector< int> nodeSortingLineID(stopTrees.size(), -1 ); //排序后的行位置 std::vector< int> nodeProcFlag(stopTrees.size(), 0); //已经处理标志,”1“已经处理 std::vector> hSorting; hSorting.resize(stopTrees.size()); int startSortingLine = -1; //第一个检查的Node使用最中间的排序行,这样可以向上和向下添加行 int gMaxLineId = 0; for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { int nodeId = objMask.at(y, x); if (nodeId >= 0) { if (nodeProcFlag[nodeId] > 0) continue; std::vector processBuff; processBuff.push_back(nodeId); if (startSortingLine < 0) startSortingLine = 0; else { //确定行序号 startSortingLine = 0; //TBD } nodeSortingLineID[nodeId] = startSortingLine; int maxLineId = startSortingLine; _recursiveSorting( nodeId, hSorting, nodeProcFlag, nodeSortingLineID, nodeLinks, true, &maxLineId); if (gMaxLineId < maxLineId) gMaxLineId = maxLineId; } } } //计算行Node的距离均值 double lineNodeDist = 0; int lineNodeDistNum = 0; for (int i = 0, i_max = stopTrees.size(); i < i_max; i++) { NodeQuadLink& link_1 = nodeLinks[i]; if (link_1.LB_link >= 0) { if (nodeLinks[link_1.LB_link].LT_link >= 0) { int id2 = nodeLinks[link_1.LB_link].LT_link; double dist = sqrt(pow(stopTrees[i].centerPt.x - stopTrees[id2].centerPt.x, 2) + pow(stopTrees[i].centerPt.y - stopTrees[id2].centerPt.y, 2)); lineNodeDist += dist; lineNodeDistNum++; } } if (link_1.LT_link >= 0) { if (nodeLinks[link_1.LT_link].LB_link >= 0) { int id2 = nodeLinks[link_1.LT_link].LB_link; double dist = sqrt(pow(stopTrees[i].centerPt.x - stopTrees[id2].centerPt.x, 2) + pow(stopTrees[i].centerPt.y - stopTrees[id2].centerPt.y, 2)); lineNodeDist += dist; lineNodeDistNum++; } } if (link_1.RB_link >= 0) { if (nodeLinks[link_1.RB_link].RT_link >= 0) { int id2 = nodeLinks[link_1.RB_link].RT_link; double dist = sqrt(pow(stopTrees[i].centerPt.x - stopTrees[id2].centerPt.x, 2) + pow(stopTrees[i].centerPt.y - stopTrees[id2].centerPt.y, 2)); lineNodeDist += dist; lineNodeDistNum++; } } if (link_1.RT_link >= 0) { if (nodeLinks[link_1.RT_link].RB_link >= 0) { int id2 = nodeLinks[link_1.RT_link].RB_link; double dist = sqrt(pow(stopTrees[i].centerPt.x - stopTrees[id2].centerPt.x, 2) + pow(stopTrees[i].centerPt.y - stopTrees[id2].centerPt.y, 2)); lineNodeDist += dist; lineNodeDistNum++; } } } if (lineNodeDistNum > 0) lineNodeDist = lineNodeDist / lineNodeDistNum; //生成目标坐标点,遗漏点检查 std::vector> sortingNodes; for (int i = 0; i <= gMaxLineId; i++) { std::vector& a_sortingLine = hSorting[i]; std::vector sortingNodes_line; for (int j = 0, j_max = a_sortingLine.size(); j < j_max; j++) { int nodeId = a_sortingLine[j]; SVzNL3DPosition a_pt; a_pt.nPointIdx = nodeId; a_pt.pt3D = stopTrees[nodeId].centerPt; sortingNodes_line.push_back(a_pt); } //遗漏点检查 _lineFillNullNode( sortingNodes_line, nodeLinks, lineNodeDist ); sortingNodes.push_back(sortingNodes_line); } //结果数据第一行和最后一行如果不完整,不使用 if (sortingNodes.size() > 3) { if (sortingNodes[0].size() < sortingNodes[2].size()) sortingNodes.erase(sortingNodes.begin()); } //输出 for (int i = 0, i_max = sortingNodes.size(); i < i_max; i++) { std::vector& sortingNodes_line = sortingNodes[i]; if (sortingNodes_line.size() == 0) break; std::vector resultLine; for (int j = 0, j_max = sortingNodes_line.size(); j < j_max; j++) resultLine.push_back(sortingNodes_line[j].pt3D); nodePos.push_back(resultLine); } #if _OUTPUT_LINE_PROC_RESULT //输出扫描线处理结果 for (int i = 0, i_max = stopTrees.size(); i < i_max; i++) { std::vector< SSG_featureSemiCircle>& a_tree_features = stopTrees[i].treeNodes; for (int j = 0, j_max = a_tree_features.size(); j < j_max; j++) { SSG_featureSemiCircle& a_feature = a_tree_features[j]; for (int m = a_feature.startPtIdx; m <= a_feature.endPtIdx; m++) laser3DPoints[a_feature.lineIdx].p3DPosition[m].nPointIdx = 0; //1; //此处nPointIdx转义 #if 0 laser3DPoints[a_feature.lineIdx].p3DPosition[a_feature.midPtIdx].nPointIdx = 2; if(stopTrees[i].treeType == 0) laser3DPoints[stopTrees[i].centerPos.x].p3DPosition[stopTrees[i].centerPos.y].nPointIdx = 3; else laser3DPoints[stopTrees[i].centerPos.x].p3DPosition[stopTrees[i].centerPos.y].nPointIdx = 4; #endif } } #endif } //计算一个平面调平参数。 //以数据输入中ROI以内的点进行平面拟合,计算调平参数 //旋转矩阵为调平参数,即将平面法向调整为垂直向量的参数 SSG_planeCalibPara sg_getSieveBaseCalibPara( SVzNL3DLaserLine* laser3DPoints, int lineNum, std::vector& ROIs) { return sg_getPlaneCalibPara_ROIs(laser3DPoints, lineNum, ROIs); }