include头文件中有slamBase.h

  1. # pragma once
  2. // 各种头文件
  3. // C++标准库
  4. #include <fstream>
  5. #include <vector>
  6. using namespace std;
  7.  
  8. // OpenCV
  9. #include <opencv2/core/core.hpp>
  10. #include <opencv2/highgui/highgui.hpp>
  11.  
  12. //PCL
  13. #include <pcl/io/pcd_io.h>
  14. #include <pcl/point_types.h>
  15.  
  16. // 类型定义
  17. typedef pcl::PointXYZRGBA PointT;
  18. typedef pcl::PointCloud<PointT> PointCloud;
  19.  
  20. // 相机内参结构
  21. struct CAMERA_INTRINSIC_PARAMETERS
  22. {
  23. double cx, cy, fx, fy, scale;
  24. };
  25.  
  26. // 函数接口
  27. // image2PonitCloud 将rgb图和深度图转换为点云
  28. PointCloud::Ptr image2PointCloud( cv::Mat& rgb, cv::Mat& depth, CAMERA_INTRINSIC_PARAMETERS& camera );
  29.  
  30. // point2dTo3d 将单个点从图像坐标转换为空间坐标
  31. // input: 3维点Point3f (u,v,d)
  32. cv::Point3f point2dTo3d( cv::Point3f& point, CAMERA_INTRINSIC_PARAMETERS& camera );

其中有三个部分,相机内参结构,rgb图和深度图转点云,2维像素点转3维空间点坐标(头文件中函数原型)。

src中源程序slamBase.cpp

  1. #include "slamBase.h"
  2.  
  3. //传入rgb, depth, 和相机内参
  4. PointCloud::Ptr image2PointCloud( cv::Mat& rgb, cv::Mat& depth, CAMERA_INTRINSIC_PARAMETERS& camera )
  5. {
  6. PointCloud::Ptr cloud ( new PointCloud );
  7. for (int m = ; m < depth.rows; m++)
  8. for (int n=; n < depth.cols; n++)
  9. {
  10. // 获取深度图中(m,n)处的值
  11. ushort d = depth.ptr<ushort>(m)[n];
  12. // d 可能没有值,若如此,跳过此点
  13. if (d == )
  14. continue;
  15. // d 存在值,则向点云增加一个点
  16. PointT p;
  17.  
  18. // 计算这个点的空间坐标
  19. p.z = double(d) / camera.scale;
  20. p.x = (n - camera.cx) * p.z / camera.fx;
  21. p.y = (m - camera.cy) * p.z / camera.fy;
  22.  
  23. // 从rgb图像中获取它的颜色
  24. // rgb是三通道的BGR格式图,所以按下面的顺序获取颜色
  25. p.b = rgb.ptr<uchar>(m)[n*];
  26. p.g = rgb.ptr<uchar>(m)[n*+];
  27. p.r = rgb.ptr<uchar>(m)[n*+];
  28.  
  29. // 把p加入到点云中
  30. cloud->points.push_back( p );
  31. }
  32. // 设置并保存点云
  33. cloud->height = ;
  34. cloud->width = cloud->points.size();
  35. cloud->is_dense = false;
  36.  
  37. return cloud;
  38. }
  39.  
  40. //像素坐标转为3维点
  41. cv::Point3f point2dTo3d( cv::Point3f& point, CAMERA_INTRINSIC_PARAMETERS& camera )
  42. {
  43. cv::Point3f p; // 3D 点
  44. p.z = double( point.z ) / camera.scale; //point.z d
  45. p.x = ( point.x - camera.cx) * p.z / camera.fx; //point.x u
  46. p.y = ( point.y - camera.cy) * p.z / camera.fy; //point.y v
  47. return p;
  48. }

和实现程序slamBase.cpp在同一文件夹下的CMakeLists.txt

  1. # 增加PCL库的依赖
  2. FIND_PACKAGE( PCL REQUIRED COMPONENTS common io )
  3.  
  4. list(REMOVE_ITEM PCL_LIBRARIES "vtkproj4") # use this in Ubuntu 16.04
  5.  
  6. # 增加opencv的依赖
  7. FIND_PACKAGE( OpenCV REQUIRED )
  8. INCLUDE_DIRECTORIES( ${OpenCV_INCLUDE_DIRS} )
  9.  
  10. # 添加头文件和库文件
  11. ADD_DEFINITIONS( ${PCL_DEFINITIONS} )
  12. INCLUDE_DIRECTORIES( ${PCL_INCLUDE_DIRS} )
  13. LINK_LIBRARIES( ${PCL_LIBRARY_DIRS} )
  14.  
  15. #把slamBase.cpp编译成 slamBase 库,并把该库里调到的OpenCV和PCL的部分,和相应的库链接起来
  16. ADD_LIBRARY( slambase slamBase.cpp ) # 实现文件 slamBase.cpp
  17. TARGET_LINK_LIBRARIES( slambase
  18. ${OpenCV_LIBS}
  19. ${PCL_LIBRARIES} )
  20.  
  21. ADD_EXECUTABLE( detectFeatures detectFeatures.cpp ) # 可执行程序 detectFeatures.cpp
  22. TARGET_LINK_LIBRARIES( detectFeatures
  23. slambase
  24. ${OpenCV_LIBS}
  25. ${PCL_LIBRARIES} )

库函数:ADD_LIBRARY( slambase slamBase.cpp )        TARGET_LINK_LIBRARIES( slambase ${OpenCV_LIBS} ${PCL_LIBRARIES} )

可执行程序:ADD_EXECUTABLE( detectFeatures detectFeatures.cpp )     TARGET_LINK_LIBRARIES( detectFeatures slambase ${OpenCV_LIBS} ${PCL_LIBRARIES} ) 使用到上诉的库

  1. #include<iostream>
  2. #include "slamBase.h" //
  3. using namespace std;
  4.  
  5. // OpenCV 特征检测模块
  6. #include <opencv2/features2d/features2d.hpp>
  7. // #include <opencv2/nonfree/nonfree.hpp> // use this if you want to use SIFT or SURF
  8. #include <opencv2/calib3d/calib3d.hpp>
  9.  
  10. int main( int argc, char** argv )
  11. {
  12. // 声明并从data文件夹里读取两个rgb与深度图
  13. cv::Mat rgb1 = cv::imread( "./data/rgb20.png");
  14. cv::Mat rgb2 = cv::imread( "./data/rgb21.png");
  15. cv::Mat depth1 = cv::imread( "./data/depth20.png", -);
  16. cv::Mat depth2 = cv::imread( "./data/depth21.png", -);
  17.  
  18. // 声明特征提取器与描述子提取器
  19. cv::Ptr<cv::FeatureDetector> detector;
  20. cv::Ptr<cv::DescriptorExtractor> descriptor;
  21.  
  22. // 构建提取器,默认两者都为 ORB
  23.  
  24. // 如果使用 sift, surf ,之前要初始化nonfree模块
  25. // cv::initModule_nonfree();
  26. // _detector = cv::FeatureDetector::create( "SIFT" );
  27. // _descriptor = cv::DescriptorExtractor::create( "SIFT" );
  28.  
  29. detector = cv::ORB::create();
  30. descriptor = cv::ORB::create();
  31.  
  32. vector< cv::KeyPoint > kp1, kp2; //关键点
  33. detector->detect( rgb1, kp1 ); //提取关键点
  34. detector->detect( rgb2, kp2 );
  35.  
  36. cout<<"Key points of two images: "<<kp1.size()<<", "<<kp2.size()<<endl;
  37.  
  38. // 可视化, 显示关键点
  39. cv::Mat imgShow;
  40. cv::drawKeypoints( rgb1, kp1, imgShow, cv::Scalar::all(-), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
  41. cv::namedWindow("Keypoints",);
  42. cv::imshow( "keypoints", imgShow );
  43. cv::imwrite( "./data/keypoints.png", imgShow );
  44. cv::waitKey(); //暂停等待一个按键
  45.  
  46. // 计算描述子
  47. cv::Mat desp1, desp2;
  48. descriptor->compute( rgb1, kp1, desp1 );
  49. descriptor->compute( rgb2, kp2, desp2 );
  50.  
  51. // 匹配描述子
  52. vector< cv::DMatch > matches;
  53. cv::BFMatcher matcher;
  54. matcher.match( desp1, desp2, matches );
  55. cout<<"Find total "<<matches.size()<<" matches."<<endl;
  56.  
  57. // 可视化:显示匹配的特征
  58. cv::Mat imgMatches;
  59. cv::drawMatches( rgb1, kp1, rgb2, kp2, matches, imgMatches );
  60. cv::namedWindow("matches",);
  61. cv::imshow( "matches", imgMatches );
  62. cv::imwrite( "./data/matches.png", imgMatches );
  63. cv::waitKey( );
  64.  
  65. // 筛选匹配,把距离太大的去掉
  66. // 这里使用的准则是去掉大于四倍最小距离的匹配
  67. vector< cv::DMatch > goodMatches;
  68. double minDis = ;
  69. for ( size_t i=; i<matches.size(); i++ )
  70. {
  71. if ( matches[i].distance < minDis )
  72. minDis = matches[i].distance;
  73. }
  74. cout<<"min dis = "<<minDis<<endl;
  75.  
  76. for ( size_t i=; i<matches.size(); i++ )
  77. {
  78. if (matches[i].distance < *minDis)
  79. goodMatches.push_back( matches[i] );
  80. }
  81.  
  82. // 显示 good matches
  83. cout<<"good matches="<<goodMatches.size()<<endl;
  84. cv::drawMatches( rgb1, kp1, rgb2, kp2, goodMatches, imgMatches );
  85. cv::namedWindow("good matches",);
  86. cv::imshow( "good matches", imgMatches );
  87. cv::imwrite( "./data/good_matches.png", imgMatches );
  88. cv::waitKey();
  89.  
  90. // 计算图像间的运动关系
  91. // 关键函数:cv::solvePnPRansac()
  92. // 为调用此函数准备必要的参数
  93.  
  94. // 第一个帧的三维点
  95. vector<cv::Point3f> pts_obj;
  96. // 第二个帧的图像点
  97. vector< cv::Point2f > pts_img;
  98.  
  99. // 相机内参,使用到结构
  100. CAMERA_INTRINSIC_PARAMETERS C;
  101. C.cx = 682.3;
  102. C.cy = 254.9;
  103. C.fx = 979.8;
  104. C.fy = 942.8;
  105. C.scale = 1000.0;
  106.  
  107. for (size_t i=; i<goodMatches.size(); i++)
  108. {
  109. // query 是第一个, train 是第二个
  110. cv::Point2f p = kp1[goodMatches[i].queryIdx].pt;
  111. // 获取d是要小心!x是向右的,y是向下的,所以y才是行,x是列!
  112. ushort d = depth1.ptr<ushort>( int(p.y) )[ int(p.x) ];
  113. if (d == )
  114. continue;
  115. pts_img.push_back( cv::Point2f( kp2[goodMatches[i].trainIdx].pt ) );
  116.  
  117. // 将(u,v,d)转成(x,y,z)
  118. cv::Point3f pt ( p.x, p.y, d ); // 深度值/scale = z
  119. cv::Point3f pd = point2dTo3d( pt, C );
  120. pts_obj.push_back( pd );
  121. }
  122. //使用到结构
  123. double camera_matrix_data[][] = {
  124. {C.fx, , C.cx},
  125. {, C.fy, C.cy},
  126. {, , }
  127. };
  128.  
  129. // 构建相机矩阵
  130. cv::Mat cameraMatrix( , , CV_64F, camera_matrix_data );
  131. cv::Mat rvec, tvec, inliers;
  132. // 求解pnp
  133. cv::solvePnPRansac( pts_obj, pts_img, cameraMatrix, cv::Mat(), rvec, tvec, false, , 1.0, 0.95, inliers ,cv::SOLVEPNP_ITERATIVE);
  134. // 求旋转向量和平移向量,旋转矩阵
  135. cout<<"inliers: "<<inliers.rows<<endl;
  136. cout<<"R="<<rvec<<endl;
  137. cout<<"t="<<tvec<<endl;
    //旋转矩阵
    cv::Mat R;
    cv::Rodrigues(rvec,R);
    cout<<"R_matrix="<<R<<endl;

  138. // 画出inliers匹配
  139. vector< cv::DMatch > matchesShow;
  140. for (size_t i=; i<inliers.rows; i++)
  141. {
  142. matchesShow.push_back( goodMatches[inliers.ptr<int>(i)[]] );
  143. }
  144. cv::drawMatches( rgb1, kp1, rgb2, kp2, matchesShow, imgMatches );
  145. cv::namedWindow("inlier matches",);
  146. cv::imshow( "inlier matches", imgMatches );
  147. cv::imwrite( "./data/inliers.png", imgMatches );
  148. cv::waitKey( );
  149.  
  150. return ;
  151. }

使用到结构,和将旋转向量转为旋转矩阵的函数cv::Rodrigues()

OpenCV会利用一种“随机采样一致性”(Random Sample Consensus)的思路(见https://en.wikipedia.org/wiki/RANSAC

cv::solvePnPRansac()函数   https://blog.csdn.net/jay463261929/article/details/53818611

和src,include文件同一文件夹下的CMakeLists.txt

  1. CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
  2. PROJECT( slam )
  3.  
  4. SET(CMAKE_CXX_COMPILER "g++")
  5. SET( CMAKE_BUILD_TYPE Debug )
  6. SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #可执行文件输出的文件夹
  7. SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) #库函数编译输出位置
  8.  
  9. INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/include ) #头文件
  10. LINK_DIRECTORIES( ${PROJECT_SOURCE_DIR}/lib) #使用编译好的库文件libslamBase.a
  11.  
  12. ADD_SUBDIRECTORY( ${PROJECT_SOURCE_DIR}/src ) #可执行程序

注意:当lib 文件下已经有编译好的库库文件libslamBase.a,可以将第一个CMakeLists.txt中ADD_LIBRARY( slambase slamBase.cpp )  TARGET_LINK_LIBRARIES( slambase ${OpenCV_LIBS} ${PCL_LIBRARIES} )去掉,因为slamBase.cpp已经被编译。

将第二个CMakeLists.txt中SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) 去掉。

(2)特征点匹配,并求旋转矩阵R和位移向量t的更多相关文章

  1. c++ 知道旋转前后矩阵向量值 求旋转矩阵c++/c#代码 知道两个向量求他们的旋转矩阵

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12115244.html 知道旋转前后矩阵向量值 如何去求旋转矩阵R 的c++/c#代码??? ...

  2. 第二篇 特征点匹配以及openvslam中的相关实现详解

    配置文件 在进入正题之前先做一些铺垫,在openvslam中,配置文件是必须要正确的以.yaml格式提供,通常需要指明使用的相机模型,ORB特征检测参数,跟踪参数等. #==============# ...

  3. 容斥原理应用(求1~r中有多少个数与n互素)

    问题:求1~r中有多少个数与n互素. 对于这个问题由容斥原理,我们有3种写法,其实效率差不多.分别是:dfs,队列数组,位运算. 先说说位运算吧: 用二进制1,0来表示第几个素因子是否被用到,如m=3 ...

  4. OpenCV使用FLANN进行特征点匹配

    使用FLANN进行特征点匹配 目标 在本教程中我们将涉及以下内容: 使用 FlannBasedMatcher 接口以及函数 FLANN 实现快速高效匹配( 快速最近邻逼近搜索函数库(Fast Appr ...

  5. sift、surf、orb 特征提取及最优特征点匹配

    目录 sift sift特征简介 sift特征提取步骤 surf surf特征简介 surf特征提取步骤 orb orb特征简介 orb特征提取算法 代码实现 特征提取 特征匹配 附录 sift si ...

  6. OpenCvSharp 通过特征点匹配图片

    现在的手游基本都是重复操作,一个动作要等好久,结束之后继续另一个动作.很麻烦,所以动起了自己写一个游戏辅助的心思. 这个辅助本身没什么难度,就是通过不断的截图,然后从这个截图中找出预先截好的能代表相应 ...

  7. opencv 增强现实(二):特征点匹配

    import cv2 as cv import numpy as np # def draw_keypoints(img, keypoints): # for kp in keypoints: # x ...

  8. 机器学习入门-数值特征-数据四分位特征 1.quantile(用于求给定分数位的数值) 2.plt.axvline(用于画出竖线) 3.pd.pcut(对特征进行分位数切分,生成新的特征)

    函数说明: 1.  .quantile(cut_list) 对DataFrame类型直接使用,用于求出给定列表中分数的数值,这里用来求出4分位出的数值 2.  plt.axvline()  # 用于画 ...

  9. (分解质因数模板)求 1~r 内与 n 互素的元素个数

    void Solve(LL n){ ///分解质因数保存结果于p p.clear(); ; i*i<=n; i++) ){ p.push_back(i); ) n/=i; } ) p.push_ ...

随机推荐

  1. 如何用Mockplus快速做一个手风琴菜单?

    手风琴菜单是一种比较常用的菜单形式,利用原型工具来做这种菜单通常要用到中继器.即使是功能强大的Axure,想实现该效果也比较麻烦.但如果你对Mockplus有所了解,你一定知道,利用Mockplus的 ...

  2. app怎么测试性能

    性能测试一般来说 都是代码能力相对薄弱的测试人员 进阶的一个方向:但是当你成为一个真正的全栈人才的时候你就不得不学习代码: APP 或者安卓手机 或者iOS  一本测试他的性能的话都是采用:手机安装一 ...

  3. Kendo UI中TreeView 放入tabstrip中,大数据量时超过边框的解决方案。

    参考http://www.kendoui.com/forums/ui/tabstrip/tabstip-with-treeview-treeview-breaking-out-of-tabstrip. ...

  4. 使用delphi 开发多层应用(二十四)KbmMW 的消息方式和创建WIB节点

    KbmMW 中支持基于UDP的消息广播,也支持TCP/IP hub/spoke 方式,还有 基于UDP或者TCP/IP 的点对点的消息传输. 1.基于UDP的消息广播

  5. 2018.08.27 rollcall(非旋treap)

    描述 初始有一个空集,依次插入N个数Ai.有M次询问Bj,表示询问第Bj个数加入集合后的排名为j的数是多少 输入 第一行是两个整数N,M 接下来一行有N个整数,Ai 接下来一行有M个整数Bj,保证数据 ...

  6. Spring Cloud基础教程视频教程

    视频课程包含: Spring Cloud基础视频教程24G 目录 获取方式: 关注公众微信号:博涵大数据 或者扫描下面的二维码关注获取. 关注后在公众平台上回复"SpringCloud基础& ...

  7. IntelliJ IDEA 2017版 编译器使用学习笔记(一) (图文详尽版);IDE快捷键使用;IDE多行代码同时编写

    IntellJ是一款强大的编译器,那么它有很多实用的功能 一.鼠标点击减少效率,快捷键实现各种跳转 (1)项目之间的跳转 快捷键位置: 操作:首先要有两个项目,然后,在不同窗口打开:如图: 然后使用快 ...

  8. LA 3708 && POJ 3154 Graveyard (思维)

    题意:在周长为10000的圆上等距分布着n个雕塑,现在又加入m个,现在让m+n个等距分布,那就得移动一些原有的雕塑,问你移动的最少总距离是多少. 析:首先我们可以知道,至少有一个雕塑是可以不用移动的, ...

  9. wordpaster更新说明

    官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/wordpaster/index.aspx 在线演示:FCKEditor2x示例 ...

  10. struts2和JSON的数据交互

    一.实验环境 1.struts2基本包 2.json-plugin 在struts2的lib下可以找到. 3.web.xml 加入struts2 <filter> <filter-n ...