#include #include "SG_baseDataType.h" #include "SG_baseAlgo_Export.h" #include "boxCarMeasure_Export.h" #include //扫描线处理,进行垂直方向的特征提取和生长 void sg_boxCarMeasure_lineProc(SVzNL3DLaserLine* a_line, int lineIdx, int* errCode, std::vector& all_vLineFeatures, std::vector>& noisePts, const SG_boxCarMeasureParam measureParam) { SSG_lineFeature a_line_features; a_line_features.lineIdx = lineIdx; //滤波,滤除异常点 std::vector filterData; std::vector lineNoisePts; sg_lineDataRemoveOutlier(a_line->p3DPosition, a_line->nPositionCnt, measureParam.filterParam, filterData, lineNoisePts); noisePts.push_back(lineNoisePts); sg_getLineRigthAngleFeature( filterData.data(), filterData.size(), lineIdx, measureParam.templatePara_HF, measureParam.templatePara_FH, measureParam.templatePara_HR, measureParam.templatePara_RH, &a_line_features); //if ((a_line_features.features.size() > 0) || (a_line_features.endings.size() > 0)) all_vLineFeatures.push_back(a_line_features); //空行也加入,保证能按行号索引 return; } typedef struct { SSG_featureTree* hTree; SSG_featureTree* head_vTree; SSG_featureTree* tail_vTree; int head_vTree_linkType; //1-head, 2-tail int tail_vTree_linkType; //1-head, 2-tail }boxCarEdge; SSG_featureTree* _findNeighbouringTree( SVzNL3DPoint seedPt, std::vector&trees, double neighbourDistTh, double lenTh, int* vTree_linkType) { for (int i = 0, i_max = trees.size(); i < i_max; i++) { SSG_featureTree* a_tree = &trees[i]; SVzNL3DPoint headPt = a_tree->treeNodes[0].jumpPos; SVzNL3DPoint tailPt = a_tree->treeNodes.back().jumpPos; double treeLen = sqrt(pow(tailPt.x - headPt.x, 2) + pow(tailPt.y - headPt.y, 2) + pow(tailPt.z - headPt.z, 2)); if (treeLen > lenTh) { double dist_head = sqrt(pow(seedPt.x - headPt.x, 2) + pow(seedPt.y - headPt.y, 2) + pow(seedPt.z - headPt.z, 2)); double dist_tail = sqrt(pow(seedPt.x - tailPt.x, 2) + pow(seedPt.y - tailPt.y, 2) + pow(seedPt.z - tailPt.z, 2)); if (dist_head < neighbourDistTh) { *vTree_linkType = 1; //head link return a_tree; } else if (dist_tail < neighbourDistTh) { *vTree_linkType = 2; //tail link return a_tree; } } } *vTree_linkType = 0; return NULL; } void _getBoxCarDimensionInfo(boxCarEdge* carEdges, SSG_boxCarDimension* dimen) { if ((carEdges->head_vTree_linkType == 0) || (carEdges->tail_vTree_linkType == 0)) return; //计算端点 SVzNL3DPoint hTree_firstNode = carEdges->hTree->treeNodes[0].jumpPos; SVzNL3DPoint htree_head = { hTree_firstNode.y, hTree_firstNode.x, hTree_firstNode.z }; //htree的坐标与vtree坐标的xy是相反的 SVzNL3DPoint hTree_lastNode = carEdges->hTree->treeNodes.back().jumpPos; SVzNL3DPoint htree_tail = { hTree_lastNode.y, hTree_lastNode.x, hTree_lastNode.z }; //htree的坐标与vtree坐标的xy是相反的 SVzNL3DPoint link_ending_0, link_ending_1; SVzNL3DPoint endings[4]; if (carEdges->head_vTree_linkType == 1) //head link { link_ending_0 = carEdges->head_vTree->treeNodes[0].jumpPos; endings[0] = carEdges->head_vTree->treeNodes.back().jumpPos; } else //tail link { link_ending_0 = carEdges->head_vTree->treeNodes.back().jumpPos; endings[0] = carEdges->head_vTree->treeNodes[0].jumpPos; } if (carEdges->tail_vTree_linkType == 1) //head link { link_ending_1 = carEdges->tail_vTree->treeNodes[0].jumpPos; endings[3] = carEdges->tail_vTree->treeNodes.back().jumpPos; } else //tail link { link_ending_1 = carEdges->tail_vTree->treeNodes.back().jumpPos; endings[3] = carEdges->tail_vTree->treeNodes[0].jumpPos; } dimen->endings[0] = endings[0]; dimen->endings[1] = { htree_head.x, link_ending_0.y, (htree_head.z + link_ending_0.z) / 2 }; dimen->endings[2] = { htree_tail.x, link_ending_1.y, (htree_tail.z + link_ending_1.z) / 2 }; dimen->endings[3] = endings[3]; double len_1 = sqrt(pow(dimen->endings[0].x - dimen->endings[1].x, 2) + pow(dimen->endings[0].y - dimen->endings[1].y, 2)); double len_2 = sqrt(pow(dimen->endings[2].x - dimen->endings[3].x, 2) + pow(dimen->endings[2].y - dimen->endings[3].y, 2)); double w = sqrt(pow(dimen->endings[1].x - dimen->endings[2].x, 2) + pow(dimen->endings[1].y - dimen->endings[2].y, 2)); dimen->L = len_1 < len_2 ? len_2 : len_1; dimen->W = w; double angle = atan((dimen->endings[0].y - dimen->endings[1].y) /(dimen->endings[0].x - dimen->endings[1].x)); dimen->angle = angle * 180.0 / PI; return; } ///数据输入必须是grid格式,以进行水平方向和垂直方向的处理 ///(1)寻找直角点 ///(2)对LINE_FEATURE_RIGHT_ANGLE_HF和LINE_FEATURE_RIGHT_ANGLE_RH两种直角点进行生长 ///(3) 确定尺寸 SSG_boxCarDimension sg_getBoxCarDimension( SVzNL3DLaserLine* laser3DPoints, int lineNum, std::vector& all_vLineFeatures, std::vector>& noisePts, const SG_boxCarMeasureParam measureParam) { //噪声去除 for (int i = 0; i < noisePts.size(); i++) { std::vector& lineNoise = noisePts[i]; for (int j = 0; j < lineNoise.size(); j++) { int ptIdx = lineNoise[j]; laser3DPoints[i].p3DPosition[ptIdx].pt3D.z = 0; } } int hLineNum = laser3DPoints->nPositionCnt; //Grid格式,所有扫描线的点数是一样的 //生成水平扫描数据 std::vector> hLines; hLines.resize(hLineNum); for (int i = 0; i < hLineNum; i++) hLines[i].resize(lineNum); for (int line = 0; line < lineNum; line++) { for (int j = 0; j < hLineNum; j++) { hLines[j][line] = laser3DPoints[line].p3DPosition[j]; hLines[j][line].pt3D.x = laser3DPoints[line].p3DPosition[j].pt3D.y; hLines[j][line].pt3D.y = laser3DPoints[line].p3DPosition[j].pt3D.x; } } std::vector all_hLineFeatures; std::vector> all_hLineNoises; //逐行提取特征 for (int hLine = 0; hLine < hLineNum; hLine++) { if (hLine == 520) int kkk = 1; //滤波,滤除异常点 std::vector filterData; std::vector lineNoise; sg_lineDataRemoveOutlier(( SVzNL3DPosition*)hLines[hLine].data(), (int)hLines[hLine].size(), measureParam.filterParam, filterData, lineNoise); all_hLineNoises.push_back(lineNoise); std::vector smoothData; sg_lineDataSmoothing(filterData, 5, smoothData); SSG_lineFeature a_hLine_featrues; a_hLine_featrues.lineIdx = hLine; sg_getLineRigthAngleFeature( smoothData.data(), smoothData.size(), hLine, measureParam.templatePara_HF, measureParam.templatePara_FH, measureParam.templatePara_HR, measureParam.templatePara_RH, &a_hLine_featrues); //if ((a_hLine_featrues.features.size() > 0) || (a_hLine_featrues.endings.size() > 0)) all_hLineFeatures.push_back(a_hLine_featrues);//空行也加入,保证能按行号索引 } //噪声去除 for (int i = 0; i < all_hLineNoises.size(); i++) { if (i == 105) int kkk = 1; std::vector& lineNoise = all_hLineNoises[i]; for (int j = 0; j < lineNoise.size(); j++) { int lineIdx = lineNoise[j]; laser3DPoints[lineIdx].p3DPosition[i].pt3D.z = 0; } } //迭代处理一次,防止由于行处理时smooth将一些点无效,面垂直处理的feature点正好落在这些无效点上 for (int i = 0; i < lineNum; i++) { //逐行检查 if (i == 175) int kkk = 1; SSG_lineFeature& a_line = all_vLineFeatures[i]; if (a_line.features.size() > 0) { bool reDoFlag = false; for (int j = 0, j_max = a_line.features.size(); j < j_max; j++) { SSG_basicFeature1D& a_feature = a_line.features[j]; if (laser3DPoints[a_feature.jumpPos2D.x].p3DPosition[a_feature.jumpPos2D.y].pt3D.z < 1e-4) { reDoFlag = true; break; } } if (true == reDoFlag) { SSG_lineFeature a_line_features; sg_getLineRigthAngleFeature( laser3DPoints[i].p3DPosition, laser3DPoints[i].nPositionCnt, i, measureParam.templatePara_HF, measureParam.templatePara_FH, measureParam.templatePara_HR, measureParam.templatePara_RH, &a_line_features); all_vLineFeatures[i].features.clear(); all_vLineFeatures[i].features.insert(all_vLineFeatures[i].features.end(), a_line_features.features.begin(), a_line_features.features.end()); all_vLineFeatures[i].endings.clear(); all_vLineFeatures[i].endings.insert(all_vLineFeatures[i].endings.end(), a_line_features.endings.begin(), a_line_features.endings.end()); } } } //垂直方向特征生长(相机扫描方向) std::vector all_v_trees; sg_getFeatureGrowingTrees( all_vLineFeatures, all_v_trees, measureParam.growParam); //水平方向特征生长 std::vector all_h_trees; sg_getFeatureGrowingTrees( all_hLineFeatures, all_h_trees, measureParam.growParam); //过滤出合适的Tree:只有LINE_FEATURE_RIGHT_ANGLE_HF和LINE_FEATURE_RIGHT_ANGLE_RH的tree是符合要求的tree std::vector vld_v_trees; for (int i = 0, i_max = all_v_trees.size(); i < i_max; i++) { if ((LINE_FEATURE_RIGHT_ANGLE_HF == all_v_trees[i].treeType) || (LINE_FEATURE_RIGHT_ANGLE_RH == all_v_trees[i].treeType)) vld_v_trees.push_back(all_v_trees[i]); } std::vector vld_h_trees; for (int i = 0, i_max = all_h_trees.size(); i < i_max; i++) { if ((LINE_FEATURE_RIGHT_ANGLE_HF == all_h_trees[i].treeType) || (LINE_FEATURE_RIGHT_ANGLE_RH == all_h_trees[i].treeType)) vld_h_trees.push_back(all_h_trees[i]); } //在搜索h_trees中搜索两端均与v_trees邻接的生长树 double neighbourDistTh = 400.0; std::vector< boxCarEdge> validBoxCarEdges; for (int i = 0, i_max = vld_h_trees.size(); i < i_max; i++) { SSG_featureTree* a_hTree = &vld_h_trees[i]; //取出头尾,htree的坐标与vtree坐标的xy是相反的 SVzNL3DPoint hTree_firstNode = a_hTree->treeNodes[0].jumpPos; SVzNL3DPoint htree_head = { hTree_firstNode.y, hTree_firstNode.x, hTree_firstNode.z }; //htree的坐标与vtree坐标的xy是相反的 SVzNL3DPoint hTree_lastNode = a_hTree->treeNodes.back().jumpPos; SVzNL3DPoint htree_tail = { hTree_lastNode.y, hTree_lastNode.x, hTree_lastNode.z }; //htree的坐标与vtree坐标的xy是相反的 double hTreeLen = sqrt(pow(htree_tail.x - htree_head.x, 2) + pow(htree_tail.y - htree_head.y, 2) + pow(htree_tail.z - htree_head.z, 2)); int vTree_linkType_0 = 0; SSG_featureTree* head_link = _findNeighbouringTree(htree_head, vld_v_trees, neighbourDistTh, hTreeLen, &vTree_linkType_0); int vTree_linkType_1 = 0; SSG_featureTree* tail_link = _findNeighbouringTree(htree_tail, vld_v_trees, neighbourDistTh, hTreeLen, &vTree_linkType_1); if ((NULL == head_link) || (NULL == tail_link)) continue; boxCarEdge car_edge = { a_hTree , head_link , tail_link, vTree_linkType_0, vTree_linkType_1 }; validBoxCarEdges.push_back(car_edge); } if (validBoxCarEdges.size() == 0) { SSG_boxCarDimension result_null; memset(&result_null, 0, sizeof(SSG_boxCarDimension)); return result_null; } //取出最长的组合 int maxLen = -1; int max_idx = 0; for (int i = 0, i_max = validBoxCarEdges.size(); i < i_max; i++) { int sum_len = abs(validBoxCarEdges[i].hTree->eLineIdx - validBoxCarEdges[i].hTree->sLineIdx) + abs(validBoxCarEdges[i].head_vTree->eLineIdx - validBoxCarEdges[i].head_vTree->sLineIdx) + abs(validBoxCarEdges[i].tail_vTree->eLineIdx - validBoxCarEdges[i].tail_vTree->sLineIdx); if (maxLen < 0) { maxLen = sum_len; max_idx = i; } else if (maxLen < sum_len) { maxLen = sum_len; max_idx = i; } } //用于标注 std::vector v_trees; std::vector h_trees; #if 1 v_trees.push_back(*validBoxCarEdges[max_idx].head_vTree); v_trees.push_back(*validBoxCarEdges[max_idx].tail_vTree); h_trees.push_back(*validBoxCarEdges[max_idx].hTree); #else v_trees.insert(v_trees.end(), all_v_trees.begin(), all_v_trees.end()); h_trees.insert(h_trees.end(), all_h_trees.begin(), all_h_trees.end()); #endif //获取车厢信息 SSG_boxCarDimension result_dimen; memset(&result_dimen, 0, sizeof(SSG_boxCarDimension)); _getBoxCarDimensionInfo(&validBoxCarEdges[max_idx], &result_dimen); std::vector allTreesInfo; //不包含边界 //标注:垂直 SSG_treeInfo a_nullTree; memset(&a_nullTree, 0, sizeof(SSG_treeInfo)); allTreesInfo.push_back(a_nullTree); //保持存储位置与treeIdx相同位置,方便索引 int hvTreeIdx = 1; for (int i = 0, i_max = v_trees.size(); i < i_max; i++) { if (i == 22) int kkk = 1; SSG_featureTree* a_vTree = &v_trees[i]; //记录Tree的信息 SSG_treeInfo a_treeInfo; a_treeInfo.vTreeFlag = 1; a_treeInfo.treeIdx = hvTreeIdx; a_treeInfo.treeType = a_vTree->treeType; a_treeInfo.sLineIdx = a_vTree->sLineIdx; a_treeInfo.eLineIdx = a_vTree->eLineIdx; a_treeInfo.roi = a_vTree->roi; allTreesInfo.push_back(a_treeInfo); //在原始点云上标记,同时有Mask上标记 for (int j = 0, j_max = a_vTree->treeNodes.size(); j < j_max; j++) { SSG_basicFeature1D* a_feature = &a_vTree->treeNodes[j]; laser3DPoints[a_feature->jumpPos2D.x].p3DPosition[a_feature->jumpPos2D.y].nPointIdx = a_feature->featureType; laser3DPoints[a_feature->jumpPos2D.x].p3DPosition[a_feature->jumpPos2D.y].nPointIdx &= 0xffff; laser3DPoints[a_feature->jumpPos2D.x].p3DPosition[a_feature->jumpPos2D.y].nPointIdx += hvTreeIdx << 16; } hvTreeIdx++; } int hTreeStart = hvTreeIdx; ////标注:水平特征 for (int i = 0, i_max = h_trees.size(); i < i_max; i++) { if (i == 9) int kkk = 1; SSG_featureTree* a_hTree = &h_trees[i]; //记录Tree的信息 SSG_treeInfo a_treeInfo; a_treeInfo.vTreeFlag = 0; a_treeInfo.treeIdx = hvTreeIdx; a_treeInfo.treeType = a_hTree->treeType; a_treeInfo.sLineIdx = a_hTree->sLineIdx; a_treeInfo.eLineIdx = a_hTree->eLineIdx; a_treeInfo.roi.left = a_hTree->roi.top; //水平扫描xy是交换的 a_treeInfo.roi.right = a_hTree->roi.bottom; a_treeInfo.roi.top = a_hTree->roi.left; a_treeInfo.roi.bottom = a_hTree->roi.right; allTreesInfo.push_back(a_treeInfo); //在原始点云上标记,同时有Mask上标记 for (int j = 0, j_max = a_hTree->treeNodes.size(); j < j_max; j++) { SSG_basicFeature1D* a_feature = &a_hTree->treeNodes[j]; laser3DPoints[a_feature->jumpPos2D.y].p3DPosition[a_feature->jumpPos2D.x].nPointIdx += a_feature->featureType << 4; laser3DPoints[a_feature->jumpPos2D.y].p3DPosition[a_feature->jumpPos2D.x].nPointIdx &= 0xffff; laser3DPoints[a_feature->jumpPos2D.y].p3DPosition[a_feature->jumpPos2D.x].nPointIdx += hvTreeIdx << 16; } hvTreeIdx++; } int hvTreeSize = hvTreeIdx; //统计VTree中LINE_FEATURE_RIGHT_ANGLE_HF和LINE_FEATURE_RIGHT_ANGLE_RH的数量 std::vector vscan_HF_trees; std::vector vscan_RH_trees; for (int i = 0; i < v_trees.size(); i++) { if (LINE_FEATURE_RIGHT_ANGLE_HF == v_trees[i].treeType) vscan_HF_trees.push_back(i); else if (LINE_FEATURE_RIGHT_ANGLE_RH == v_trees[i].treeType) vscan_RH_trees.push_back(i); } //统计HTree中LINE_FEATURE_RIGHT_ANGLE_RH的数量 std::vector hscan_HF_trees; std::vector hscan_RH_trees; for (int i = 0; i < h_trees.size(); i++) { if (LINE_FEATURE_RIGHT_ANGLE_HF == h_trees[i].treeType) hscan_HF_trees.push_back(i); else if (LINE_FEATURE_RIGHT_ANGLE_RH == h_trees[i].treeType) hscan_RH_trees.push_back(i); } return result_dimen; }