[关闭]
@zhuqingzhang 2019-06-26T03:17:56.000000Z 字数 15216 阅读 1627

Rtabmap 中点云的后续处理

1、主要用到的变量的结构

a. Signature.h(片段)

主要是通过Signature这一个类来获取生成的点云地图以及我们所需要的各种信息。我们通过解包.db文件,可以获得一个由Signature组成的vector,实际上,每个Signature对应了一帧图像数据。

  1. namespace rtabmap
  2. {
  3. class RTABMAP_EXP Signature
  4. {
  5. ...
  6. private:
  7. int _id; ///signature的id,也对应的是图像的id。
  8. int _mapId;
  9. double _stamp; ///对应的时间戳
  10. std::map<int, Link> _links; // id, transform
  11. std::map<int, Link> _landmarks;
  12. int _weight;
  13. std::string _label;
  14. bool _saved; // If it's saved to bd
  15. bool _modified;
  16. bool _linksModified; // Optimization when updating signatures in database
  17. // Contains all words (Some can be duplicates -> if a word appears 2
  18. // times in the signature, it will be 2 times in this list)
  19. // Words match with the CvSeq keypoints and descriptors
  20. std::multimap<int, cv::KeyPoint> _words; // word <id, keypoint> /// 包含着每张图片的关键点
  21. std::multimap<int, cv::Point3f> _words3; // word <id, point> // in base_link frame (localTransform applied)) ///包含着每张图片的关键点对应的在车身坐标系下的3d点
  22. std::multimap<int, cv::Mat> _wordsDescriptors; ///包含着每个特征点对应的描述子
  23. std::map<int, int> _wordsChanged; // <oldId, newId>
  24. bool _enabled;
  25. int _invalidWordsCount;
  26. Transform _pose; ///bask_link的位姿。
  27. Transform _groundTruthPose;
  28. std::vector<float> _velocity;
  29. SensorData _sensorData; ///从中获得相机的信息,包括原始的图像信息。
  30. };
  31. }

b. SensorData.h(片段)

SensorData包含着各种传感器的数据信息。对于我们来说,主要是相机的信息。

  1. namespace rtabmap
  2. {
  3. class RTABMAP_EXP SensorData
  4. {
  5. int _id; ///传感器数据的id,这个id和Signature中的id是相同的。
  6. double _stamp;
  7. cv::Mat _imageCompressed; // compressed image
  8. cv::Mat _depthOrRightCompressed; // compressed image
  9. LaserScan _laserScanCompressed; // compressed data
  10. cv::Mat _imageRaw; // CV_8UC1 or CV_8UC3 ///主要通过该变量获得相机得到的原始图片。注:并不是所有的Signature中的SensorData的_imageRaw都有数据。_imageRaw只保留关键帧的图像。在程序中每三帧为一个关键帧图像。
  11. cv::Mat _depthOrRightRaw; // depth CV_16UC1 or CV_32FC1, right image CV_8UC1 ///如果传入的是RGB-D数据,则通过这个变量来获得深度图片的数据。如果传入的是双目图像,则通过该变量来获得右目图像
  12. LaserScan _laserScanRaw;
  13. std::vector<CameraModel> _cameraModels;
  14. StereoCameraModel _stereoCameraModel; ///通过该变量来获得相机的内外参数。
  15. // user data
  16. cv::Mat _userDataCompressed; // compressed data
  17. cv::Mat _userDataRaw;
  18. // occupancy grid
  19. cv::Mat _groundCellsCompressed;
  20. cv::Mat _obstacleCellsCompressed;
  21. cv::Mat _emptyCellsCompressed;
  22. cv::Mat _groundCellsRaw;
  23. cv::Mat _obstacleCellsRaw;
  24. cv::Mat _emptyCellsRaw;
  25. float _cellSize;
  26. cv::Point3f _viewPoint;
  27. // environmental sensors
  28. EnvSensors _envSensors;
  29. // landmarks
  30. Landmarks _landmarks;
  31. // features 注:此处的keypoints,descriptor, keypoints3D都是空的。不能通过这个变量来获得相关信息。但是可以通过Signature中的变量获得相关信息。
  32. std::vector<cv::KeyPoint> _keypoints;
  33. std::vector<cv::Point3f> _keypoints3D;
  34. cv::Mat _descriptors;
  35. Transform groundTruth_;
  36. Transform globalPose_;
  37. cv::Mat globalPoseCovariance_; // 6x6 double
  38. GPS gps_;
  39. IMU imu_;
  40. };
  41. }

2.从.db文件中获得点云

  1. int main(int argc, char * argv[])
  2. {
  3. if(argc < 2)
  4. {
  5. showUsage();
  6. }
  7. std::string dbPath = argv[argc-1];
  8. // Get parameters
  9. ParametersMap parameters;
  10. DBDriver * driver = DBDriver::create();
  11. if(driver->openConnection(dbPath)) ///载入.db数据
  12. {
  13. cout<<"loading database..."<<endl;
  14. parameters = driver->getLastParameters();
  15. driver->closeConnection(false);
  16. }
  17. else
  18. {
  19. UERROR("Cannot open database %s!", dbPath.c_str());
  20. }
  21. delete driver;
  22. cout<<"database is successfully loaded!"<<endl;
  23. // Get the global optimized map
  24. Rtabmap rtabmap;
  25. cout<<"initial rtabmap..."<<endl;
  26. rtabmap.init(parameters, dbPath);
  27. cout<<"initial finished..."<<endl;
  28. std::map<int, Signature> nodes;
  29. std::map<int, Transform> optimizedPoses;
  30. std::multimap<int, Link> links;
  31. std::map<int,double> stamps;
  32. //rtabmap.get3DMap(nodes, optimizedPoses, links, true, true);
  33. cout<<"getting3D map..."<<endl;
  34. rtabmap.get3DMap(nodes, optimizedPoses, links, false, true); //获取各个数据,存在nodes中。optimizedPoses里有每一张图片对应的base_linke的位姿。第四个参数表示是否进行全局优化。由于我们传入了参考轨迹,优化后的效果会不好,所以不进行全局优化。
  35. ofstream file,file_2;
  36. file.open("poses.txt");
  37. file_2.open("image_id.txt");
  38. ifstream ifile;
  39. int decimation=2;
  40. int tmpNoNaN_index=0;
  41. double count_line_point=0;
  42. map<int,pcl::PointCloud<pcl::PointXYZRGB>::Ptr> index_cloud_tmpNoNaN;
  43. map<int,vector<int>> index_map;
  44. vector<cloudpoint_line> clouds_lines_infos; //save final info;
  45. cout<<"indeces number: "<<optimizedPoses.size()<<endl;
  46. pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
  47. pcl::PointCloud<pcl::PointXYZRGB>::Ptr line_cloudpoints(new pcl::PointCloud<pcl::PointXYZRGB>);
  48. for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter) //对每一帧数据进行遍历
  49. {
  50. Signature node = nodes.find(iter->first)->second; //获得当前帧的Signaure数据。(Signaure的数据内容见前边第一部分的说明)
  51. stamps.insert(make_pair(iter->first,node.getStamp()));
  52. // uncompress data
  53. node.sensorData().uncompressData();
  54. cout<<"processing index "<<node.id()<<"("<<iter->first<<")/"<<optimizedPoses.size()<<endl;
  55. pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp = util3d::cloudRGBFromSensorData(
  56. node.sensorData(),
  57. decimation, // image decimation before creating the clouds
  58. 20.0f, // maximum depth of the cloud
  59. 0.0f);
  60. //通过该函数获得当前帧对应的点云数据。注意,此时得到的tmp点云是带结构的点云,其高度和宽度为图像的高度和宽度。temp中位于(u,v)出的点就对应于原始图像中位于(u,v)处的点。
  61. pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmpNoNaN(new pcl::PointCloud<pcl::PointXYZRGB>);
  62. std::vector<int> index;
  63. pcl::removeNaNFromPointCloud(*tmp, *tmpNoNaN, index); //移除点云数据中包含值为无穷的点,并存放在tmpNoNaN中。注意,此时tmpNoNaN中的点云数据已经是无结构的点云,其高度为1。所以我们如果需要通过tmpNoNaN找到图像中的像素坐标,需要有一个索引。这个索引存放在index中。有如下对应关系: tmpNoNaN->points[i]=tmp->points[index[i]];
  64. if(!tmpNoNaN->empty())
  65. {
  66. index_cloud_tmpNoNaN.insert(make_pair(tmpNoNaN_index,tmpNoNaN));
  67. index_map.insert(make_pair(tmpNoNaN_index,index));
  68. *cloud += *util3d::transformPointCloud(tmpNoNaN, iter->second); // transform the point cloud to its pose,将每一帧的点云叠加在一起,得到最终的点云。
  69. }
  70. }
  71. if(cloud->size())
  72. {
  73. //存储点云
  74. printf("Voxel grid filtering of the assembled cloud (voxel=%f, %d points)\n", 0.01f, (int)cloud->size());
  75. cloud = util3d::voxelize(cloud, 0.01f);
  76. printf("Saving rtabmap_cloud.pcd... done! (%d points)\n", (int)cloud->size());
  77. //pcl::io::savePCDFile("rtabmap_cloud.pcd", *cloud);
  78. pcl::io::savePLYFile("kitti_00_clouds.ply", *cloud); // to save in PLY format
  79. }
  80. else
  81. {
  82. printf("Saving rtabmap_cloud.ply... failed! The cloud is empty.\n");
  83. }
  84. rtabmap.close(false);
  85. return 0;
  86. }

3.将点云中的点与车道线一一对应

此程序是在2.中的程序的基础上扩展而成的。需要注意的是,在通过util3d::cloudRGBFromSensorData得到的点云tmp是带结构的点云。点云的宽度和高度与图像对应。所以可以将图像中的(u,v)位置的像素与点云中(u,v)位置的像素相对应。但是最终生成的点云cloud是无结构的点云。其高度为1,相当于用一个vector存放了所有的点云。所以需要一个index将tmp中的id信息与最终的cloud的id信息相对应。具体的程序如下:

  1. /*定义了两个结构体*/
  2. //用于存放每个车道线像素点的信息
  3. typedef struct line_info{
  4. int line_id_; 该车道线像素点对应的车道线的id
  5. int line_type_; 该车道线像素点对应的车道线的类型
  6. int line_color_id_; 该车道线像素点对应的车道线的颜色id
  7. int b_; 该车道线像素点的BGR
  8. int g_;
  9. int r_;
  10. int u_; 该车道线像素点对应的图像中的uv坐标
  11. int v_;
  12. }Line_Info;
  13. //用于存放车道线和点云的对应关系
  14. typedef struct cloud_with_line{
  15. Line_Info line_info_; //某条车道线上的某个像素点的信息
  16. int cloud_id_; //该像素点在整个点云中的id
  17. int image_id_; //该像素点是在哪一张图片上的
  18. int cloud_begin_id_; //该张图像所生成的这一帧点云数据在整个点云中的起始id和终止id
  19. int cloud_end_id_;
  20. }cloudpoint_line;
  21. /**咱们直接从大的for循环开始介绍**/
  22. int tmpNoNaN_index=0; //用来记录tmpNoNaN的数量。仅当tmpNoNaN不为空的时候tmpNoNaN_index++
  23. for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
  24. {
  25. Signature node = nodes.find(iter->first)->second; //获得当前帧的Signaure数据
  26. stamps.insert(make_pair(iter->first,node.getStamp()));
  27. // uncompress data
  28. node.sensorData().uncompressData();
  29. cout<<"processing index "<<node.id()<<"("<<iter->first<<")/"<<optimizedPoses.size()<<endl;
  30. pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp = util3d::cloudRGBFromSensorData(
  31. node.sensorData(),
  32. decimation, // image decimation before creating the clouds
  33. 20.0f, // maximum depth of the cloud
  34. 0.0f);
  35. //获得当前帧对应的图像所生成的带结构的点云。并不是每个node都有图像的。所以该函数生成的点云也只对应于关键帧生成点云。
  36. pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmpNoNaN(new pcl::PointCloud<pcl::PointXYZRGB>);
  37. std::vector<int> index;
  38. pcl::removeNaNFromPointCloud(*tmp, *tmpNoNaN, index); //滤除无效的点,获得无结构的当前帧点云。有结构点云tmp和无结构点云tmpNoNaN的对应关系为: tmpNoNaN->points[i]=tmp->points[index[i]];
  39. if(!tmpNoNaN->empty())
  40. {
  41. index_cloud_tmpNoNaN.insert(make_pair(tmpNoNaN_index,tmpNoNaN)); //用于存储tmpNoNaN_index和tmpNoNaN。后续通过tmpNoNaN_index来获得tmpNoNaN
  42. index_map.insert(make_pair(tmpNoNaN_index,index)); //用于存储tmpNoNaN_index和index。
  43. //有了以上两个map映射,就可以通过tmpNoNaN_index找到对应的index和tmpNoNaN,从而通过tmpNoNaN->points[i]=tmp->points[index[i]]这一对应关系获得tmpNoNaN中的每个点云在图上中的像素点位置。
  44. *cloud += *util3d::transformPointCloud(tmpNoNaN, iter->second); // transform the point cloud to its pose //将每一帧点云累加起来,得到最终的点云。
  45. }
  46. Transform pose_signature=node.getPose(); //通过signature来获取位姿
  47. Transform pose_optimize=iter->second; //通过optimizedPoses来获取位姿
  48. Eigen::Quaternionf q_s = pose_signature.getQuaternionf();
  49. Eigen::Quaternionf q_o = pose_optimize.getQuaternionf();
  50. //signature's poses without optimize.
  51. file<<"signature"<<" "<<to_string(pose_signature.x())<<" "<<to_string(pose_signature.y())<<" "<<to_string(pose_signature.z())<<" "
  52. <<to_string(q_s.x())<<" "<<to_string(q_s.y())<<" "<<to_string(q_s.z())<<" "<<to_string(q_s.w())<<endl;
  53. file<<"optimize"<<" "<<to_string(pose_optimize.x())<<" "<<to_string(pose_optimize.y())<<" "<<to_string(pose_optimize.z())<<" "
  54. <<to_string(q_o.x())<<" "<<to_string(q_o.y())<<" "<<to_string(q_o.z())<<" "<<to_string(q_o.w())<<endl; //将两种位姿输出做比较:当optimizedPoses是未进行优化的位姿时,这两种位姿是相同的
  55. SensorData data=node.sensorData(); //获得传感器数据,包括左右目图像。
  56. StereoCameraModel model=data.stereoCameraModel(); //获得双目相机的模型,包括内外参数
  57. // cout<<"local_transform: "<<endl<<model.left().localTransform()<<endl;
  58. if(!data.imageRaw().empty()) //并不是每个node都存储图片,node仅存储关键帧的图像。
  59. {
  60. pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_temp(new pcl::PointCloud<pcl::PointXYZRGB>);
  61. cloud_temp=cloud;
  62. cout<<"cloud_temp's size: "<<cloud_temp->width<<"*"<<cloud_temp->height<<endl;
  63. cv::Mat outimage,outimage_;
  64. outimage=cv::Mat::zeros(data.imageRaw().rows,data.imageRaw().cols,data.imageRaw().type());
  65. file_2<<"signature_id: "<<node.id()<<" "<<"sensordata_id: "<<data.id()<<endl; //signature的id和sensordata的id是完全相同的,两者都是从1开始累计。而我们本身的图像名称是从0开始的。所以说,node.id()=image_name_id+1;
  66. cout<<"image_id: "<<data.id()<<endl;
  67. //imshow("image",data.imageRaw());
  68. cv::Mat line_image;
  69. string input=std::to_string((data.id()-1)); //用input来表示图像的名称。
  70. while(input.size()<10) //用0来填充,保证名称是10位的。
  71. {
  72. input="0"+input;
  73. }
  74. string line_image_name=line_image_dir+input+".png"; //分割出的车道线的图像名称。车道线图像名称和输入的原始双目图像的名称是一一对应的。
  75. string line_info_name=info_dir+input+".txt"; //对应的车道线的信息
  76. line_image=cv::imread(line_image_name); //读入车道线图像
  77. if(line_image.empty()) //因为有的image_name_id对应的图像是没有车道线的,所以此时不存在该图像,则continue进行下一次循环。
  78. {
  79. cout<<"the image "<<data.id()-1<<" doesn't exist..."<<endl;
  80. tmpNoNaN_index++; //别忘了给tmpNoNaN_index加一。
  81. continue;
  82. }
  83. ifile.open(line_info_name.data()); //读入当前图像对应的车道线的信息
  84. if(!ifile.is_open())
  85. {
  86. cout<<"cannot open the line_info_file..."<<endl;
  87. tmpNoNaN_index++;
  88. continue;
  89. }
  90. string str,result;
  91. Line_Info lineinfo;
  92. vector<Line_Info> lineinfos; //用于存放一帧图片中的所有车道线的信息
  93. lineinfos.clear();
  94. while (getline(ifile,str)) {
  95. int count=0;
  96. stringstream line;
  97. line<<str;
  98. while(line>>result)
  99. {
  100. count++;
  101. }
  102. if(count!=6) //由于一些文件的车道线信息元素不全,所以需要进行判断。当车道线信息不全时,不考虑该条车道线。
  103. {
  104. continue;
  105. }
  106. line.clear();
  107. line<<str;
  108. //cout<<"line: "<<str<<endl;
  109. line>>result;
  110. lineinfo.line_id_=atoi(result.c_str());
  111. // cout<<"line_id_:"<<lineinfo.line_id_<<" ";
  112. line>>result;
  113. lineinfo.line_type_=atoi(result.c_str());
  114. //cout<<"line_type_:"<<lineinfo.line_type_<<" ";
  115. line>>result;
  116. lineinfo.line_color_id_=atoi(result.c_str());
  117. // cout<<"line_color_id_:"<<lineinfo.line_color_id_<<" ";
  118. line>>result;
  119. lineinfo.b_=atoi(result.c_str());
  120. // cout<<"b_:"<<lineinfo.b_<<" ";
  121. line>>result;
  122. lineinfo.g_=atoi(result.c_str());
  123. // cout<<"g_:"<<lineinfo.g_<<" ";
  124. line>>result;
  125. lineinfo.r_=atoi(result.c_str());
  126. // cout<<"r_:"<<lineinfo.r_<<endl;
  127. lineinfos.push_back(lineinfo); // 将当前图片的每条车道线信息放入lineinfos中
  128. }
  129. ifile.close();
  130. cloudpoint_line cloud_line_info; //用前边定义的结构体来存储点云和车道线中像素点的对应关系
  131. int start=0;
  132. for(int i=0;i<tmpNoNaN_index;i++)
  133. {
  134. start+=index_cloud_tmpNoNaN[i]->width; //计算当前帧的点云在整体点云中的起始id
  135. }
  136. cout<<"start: "<<start<<endl;
  137. cout<<"tmpNoNan_index: "<<tmpNoNaN_index<<endl;
  138. cout<<"end: "<<start+index_cloud_tmpNoNaN[tmpNoNaN_index]->width-1<<endl; //当前帧点云在整体点云中的终止id。
  139. //遍历车道线图像中的每一个像素点
  140. for(int v=0;v<line_image.rows;v++)
  141. {
  142. for(int u=0;u<line_image.cols;u++)
  143. {
  144. //获得当前点的BGR信息
  145. int b=line_image.data[v*line_image.step+u*line_image.channels()];
  146. int g=line_image.data[v*line_image.step+u*line_image.channels()+1];
  147. int r=line_image.data[v*line_image.step+u*line_image.channels()+2];
  148. //当BGR中有不为零的,说明该出位置有车道线
  149. if(b!=0||r!=0||g!=0)
  150. {
  151. //遍历该帧对应的所有车道线信息,通过BGR信息来查找这个位置的像素对应的是哪一条车道线
  152. for(int i=0;i<lineinfos.size();i++)
  153. {
  154. //当BGR的信息都对应上了,就说明该像素点对应的车道线是lineinfo[i]对应的车道线
  155. if(b==lineinfos[i].b_&&g==lineinfos[i].g_&&r==lineinfos[i].r_)
  156. {
  157. lineinfos[i].u_=u; //存储像素点位置
  158. lineinfos[i].v_=v;
  159. //已经获得了Line_Info结构体所需要的所有的数据,将其放入cloudpoint_line结构体中
  160. cloud_line_info.line_info_=lineinfos[i];
  161. cloud_line_info.image_id_=data.id()-1; //注意图像的id要比data.id小1.
  162. cloud_line_info.cloud_begin_id_=start;
  163. cloud_line_info.cloud_end_id_=start+index_cloud_tmpNoNaN[tmpNoNaN_index]->width-1;
  164. //通过uv像素坐标推测其id。(0,0)的id对应0,(0,1)的id对应1,以此类推
  165. int id=v/(decimation)*(line_image.cols/decimation)+u/decimation;
  166. int mark=0;
  167. for(int index_id=0;index_id<index.size();index_id++)
  168. {
  169. //通过index来找到在tmpNoNaN中的id。
  170. if(index[index_id]==id)
  171. {
  172. cloud_line_info.cloud_id_=start+index_id; //得到在整体cloud中的id
  173. count_line_point++;
  174. mark=1;
  175. break;
  176. }
  177. }
  178. if(mark==0)
  179. {
  180. //uv对应的点在tmpNoNaN中并没有对应的点,标记为-1
  181. cloud_line_info.cloud_id_=-1; //the line point has no corresponding pointclouds.
  182. }
  183. // cout<<"insert the cloud_line_info into the final container..."<<endl;
  184. clouds_lines_infos.push_back(cloud_line_info);
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. }
  191. //将从整体点云中分割出每一帧点云,并反投影到图片中
  192. // for(int i=start,j=0;i<(start+(int)index_cloud_tmpNoNaN[tmpNoNaN_index]->width);i++,j++)
  193. // {
  194. // int id=index_map[tmpNoNaN_index][j]; //correspond to unfiltered pointclouds id
  195. // int h=id/(outimage.cols/decimation)*decimation;
  196. // int w=id%(outimage.cols/decimation)*decimation;
  197. //// cout<<"i: "<<i<<" "<<"id: "<<id<<endl;
  198. //// cout<<"h,w: "<<h<<","<<w<<endl;
  199. //// outimage_.at<cv::Vec3b>(h,w)[0]=tmp->points[id].b;
  200. //// outimage_.at<cv::Vec3b>(h,w)[1]=tmp->points[id].g;
  201. //// outimage_.at<cv::Vec3b>(h,w)[2]=tmp->points[id].r;
  202. // outimage.at<cv::Vec3b>(h,w)[0]=cloud_temp->points[i].b;
  203. // outimage.at<cv::Vec3b>(h,w)[1]=cloud_temp->points[i].g;
  204. // outimage.at<cv::Vec3b>(h,w)[2]=cloud_temp->points[i].r;
  205. // }
  206. cout<<"get line_clouds..."<<endl;
  207. //遍历clouds_lines_info,获得所有的车道线信息
  208. for(int i=0;i<clouds_lines_infos.size();i++)
  209. {
  210. if(clouds_lines_infos[i].image_id_==(data.id()-1))
  211. {
  212. int r=clouds_lines_infos[i].line_info_.r_;
  213. int b=clouds_lines_infos[i].line_info_.b_;
  214. int g=clouds_lines_infos[i].line_info_.g_;
  215. int u=clouds_lines_infos[i].line_info_.u_;
  216. int v=clouds_lines_infos[i].line_info_.v_;
  217. // outimage.at<cv::Vec3b>(v,u)[0]=b;
  218. // outimage.at<cv::Vec3b>(v,u)[1]=g;
  219. // outimage.at<cv::Vec3b>(v,u)[2]=r;
  220. pcl::PointXYZRGB point,point_info;
  221. int point_id;
  222. point_id=clouds_lines_infos[i].cloud_id_;
  223. if(point_id!=-1)
  224. {
  225. point=cloud->points[point_id];
  226. point.r=r;
  227. point.b=b;
  228. point.g=g;
  229. line_cloudpoints->push_back(point);//存储每个车道线点云
  230. }
  231. }
  232. }
  233. tmpNoNaN_index++; //别忘了进行++操作
  234. // 可视化每一步生成的车道线点云
  235. // pcl::visualization::CloudViewer viewer_ply("viewer_ply");
  236. // viewer_ply.showCloud(line_cloudpoints);
  237. // while(!viewer_ply.wasStopped())
  238. // {
  239. // }
  240. //get keypoints
  241. // multimap<int,cv::KeyPoint> words=node.getWords();
  242. // vector<cv::KeyPoint> kps;
  243. /* if(words.empty())
  244. cout<<"words are empty..."<<endl;
  245. else {
  246. for (auto it = words.begin(); it != words.end(); it = words.upper_bound(it->first)){
  247. std::cout <<"key = " << it->first <<std::endl;
  248. std::pair<std::multimap<int,cv::KeyPoint>::iterator,std::multimap<int,cv::KeyPoint>::iterator> lu = words.equal_range(it->first);
  249. for (auto i = lu.first; i != lu.second; i++){
  250. std::cout << i->first << " = " << i->second.pt << std::endl;
  251. kps.push_back(it->second);
  252. }
  253. }
  254. cout<<"key points size: "<<kps.size()<<endl;
  255. cv::drawKeypoints(data.imageRaw(),kps,outimage);
  256. cv::imshow("keypoint",outimage);
  257. cv::waitKey(0);
  258. }*/
  259. // cv::imshow("outimage",outimage);
  260. //// cv::imshow("outimage_",outimage_);
  261. // cv::imshow("image_raw",data.imageRaw());
  262. // cv::waitKey(0);
  263. }
  264. }
  265. file.close();
  266. file_2.close();
  267. cout<<"finish cloud_process..."<<endl;
  268. cout<<"line_cloudpoints size: "<<to_string(line_cloudpoints->points.size())<<" "<<to_string(count_line_point)<<endl;
  269. pcl::io::savePLYFile("line_cloudpoints.ply", *line_cloudpoints); //存储车道线点云
  270. pcl::visualization::CloudViewer viewer_ply("viewer_ply"); // 可视化车道线点云
  271. viewer_ply.showCloud(line_cloudpoints);
  272. while(!viewer_ply.wasStopped())
  273. {
  274. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注