include头文件中有slamBase.h

# pragma once
// 各种头文件
// C++标准库
#include <fstream>
#include <vector>
using namespace std; // OpenCV
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> //PCL
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h> // 类型定义
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloud; // 相机内参结构
struct CAMERA_INTRINSIC_PARAMETERS
{
double cx, cy, fx, fy, scale;
}; // 函数接口
// image2PonitCloud 将rgb图和深度图转换为点云
PointCloud::Ptr image2PointCloud( cv::Mat& rgb, cv::Mat& depth, CAMERA_INTRINSIC_PARAMETERS& camera ); // point2dTo3d 将单个点从图像坐标转换为空间坐标
// input: 3维点Point3f (u,v,d)
cv::Point3f point2dTo3d( cv::Point3f& point, CAMERA_INTRINSIC_PARAMETERS& camera );

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

src中源程序slamBase.cpp

#include "slamBase.h"

//传入rgb, depth, 和相机内参
PointCloud::Ptr image2PointCloud( cv::Mat& rgb, cv::Mat& depth, CAMERA_INTRINSIC_PARAMETERS& camera )
{
PointCloud::Ptr cloud ( new PointCloud );
for (int m = ; m < depth.rows; m++)
for (int n=; n < depth.cols; n++)
{
// 获取深度图中(m,n)处的值
ushort d = depth.ptr<ushort>(m)[n];
// d 可能没有值,若如此,跳过此点
if (d == )
continue;
// d 存在值,则向点云增加一个点
PointT p; // 计算这个点的空间坐标
p.z = double(d) / camera.scale;
p.x = (n - camera.cx) * p.z / camera.fx;
p.y = (m - camera.cy) * p.z / camera.fy; // 从rgb图像中获取它的颜色
// rgb是三通道的BGR格式图,所以按下面的顺序获取颜色
p.b = rgb.ptr<uchar>(m)[n*];
p.g = rgb.ptr<uchar>(m)[n*+];
p.r = rgb.ptr<uchar>(m)[n*+]; // 把p加入到点云中
cloud->points.push_back( p );
}
// 设置并保存点云
cloud->height = ;
cloud->width = cloud->points.size();
cloud->is_dense = false; return cloud;
} //像素坐标转为3维点
cv::Point3f point2dTo3d( cv::Point3f& point, CAMERA_INTRINSIC_PARAMETERS& camera )
{
cv::Point3f p; // 3D 点
p.z = double( point.z ) / camera.scale; //point.z d
p.x = ( point.x - camera.cx) * p.z / camera.fx; //point.x u
p.y = ( point.y - camera.cy) * p.z / camera.fy; //point.y v
return p;
}

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

# 增加PCL库的依赖
FIND_PACKAGE( PCL REQUIRED COMPONENTS common io ) list(REMOVE_ITEM PCL_LIBRARIES "vtkproj4") # use this in Ubuntu 16.04 # 增加opencv的依赖
FIND_PACKAGE( OpenCV REQUIRED )
INCLUDE_DIRECTORIES( ${OpenCV_INCLUDE_DIRS} ) # 添加头文件和库文件
ADD_DEFINITIONS( ${PCL_DEFINITIONS} )
INCLUDE_DIRECTORIES( ${PCL_INCLUDE_DIRS} )
LINK_LIBRARIES( ${PCL_LIBRARY_DIRS} ) #把slamBase.cpp编译成 slamBase 库,并把该库里调到的OpenCV和PCL的部分,和相应的库链接起来
ADD_LIBRARY( slambase slamBase.cpp ) # 实现文件 slamBase.cpp
TARGET_LINK_LIBRARIES( slambase
${OpenCV_LIBS}
${PCL_LIBRARIES} ) ADD_EXECUTABLE( detectFeatures detectFeatures.cpp ) # 可执行程序 detectFeatures.cpp
TARGET_LINK_LIBRARIES( detectFeatures
slambase
${OpenCV_LIBS}
${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} ) 使用到上诉的库

#include<iostream>
#include "slamBase.h" //
using namespace std; // OpenCV 特征检测模块
#include <opencv2/features2d/features2d.hpp>
// #include <opencv2/nonfree/nonfree.hpp> // use this if you want to use SIFT or SURF
#include <opencv2/calib3d/calib3d.hpp> int main( int argc, char** argv )
{
// 声明并从data文件夹里读取两个rgb与深度图
cv::Mat rgb1 = cv::imread( "./data/rgb20.png");
cv::Mat rgb2 = cv::imread( "./data/rgb21.png");
cv::Mat depth1 = cv::imread( "./data/depth20.png", -);
cv::Mat depth2 = cv::imread( "./data/depth21.png", -); // 声明特征提取器与描述子提取器
cv::Ptr<cv::FeatureDetector> detector;
cv::Ptr<cv::DescriptorExtractor> descriptor; // 构建提取器,默认两者都为 ORB // 如果使用 sift, surf ,之前要初始化nonfree模块
// cv::initModule_nonfree();
// _detector = cv::FeatureDetector::create( "SIFT" );
// _descriptor = cv::DescriptorExtractor::create( "SIFT" ); detector = cv::ORB::create();
descriptor = cv::ORB::create(); vector< cv::KeyPoint > kp1, kp2; //关键点
detector->detect( rgb1, kp1 ); //提取关键点
detector->detect( rgb2, kp2 ); cout<<"Key points of two images: "<<kp1.size()<<", "<<kp2.size()<<endl; // 可视化, 显示关键点
cv::Mat imgShow;
cv::drawKeypoints( rgb1, kp1, imgShow, cv::Scalar::all(-), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
cv::namedWindow("Keypoints",);
cv::imshow( "keypoints", imgShow );
cv::imwrite( "./data/keypoints.png", imgShow );
cv::waitKey(); //暂停等待一个按键 // 计算描述子
cv::Mat desp1, desp2;
descriptor->compute( rgb1, kp1, desp1 );
descriptor->compute( rgb2, kp2, desp2 ); // 匹配描述子
vector< cv::DMatch > matches;
cv::BFMatcher matcher;
matcher.match( desp1, desp2, matches );
cout<<"Find total "<<matches.size()<<" matches."<<endl; // 可视化:显示匹配的特征
cv::Mat imgMatches;
cv::drawMatches( rgb1, kp1, rgb2, kp2, matches, imgMatches );
cv::namedWindow("matches",);
cv::imshow( "matches", imgMatches );
cv::imwrite( "./data/matches.png", imgMatches );
cv::waitKey( ); // 筛选匹配,把距离太大的去掉
// 这里使用的准则是去掉大于四倍最小距离的匹配
vector< cv::DMatch > goodMatches;
double minDis = ;
for ( size_t i=; i<matches.size(); i++ )
{
if ( matches[i].distance < minDis )
minDis = matches[i].distance;
}
cout<<"min dis = "<<minDis<<endl; for ( size_t i=; i<matches.size(); i++ )
{
if (matches[i].distance < *minDis)
goodMatches.push_back( matches[i] );
} // 显示 good matches
cout<<"good matches="<<goodMatches.size()<<endl;
cv::drawMatches( rgb1, kp1, rgb2, kp2, goodMatches, imgMatches );
cv::namedWindow("good matches",);
cv::imshow( "good matches", imgMatches );
cv::imwrite( "./data/good_matches.png", imgMatches );
cv::waitKey(); // 计算图像间的运动关系
// 关键函数:cv::solvePnPRansac()
// 为调用此函数准备必要的参数 // 第一个帧的三维点
vector<cv::Point3f> pts_obj;
// 第二个帧的图像点
vector< cv::Point2f > pts_img; // 相机内参,使用到结构
CAMERA_INTRINSIC_PARAMETERS C;
C.cx = 682.3;
C.cy = 254.9;
C.fx = 979.8;
C.fy = 942.8;
C.scale = 1000.0; for (size_t i=; i<goodMatches.size(); i++)
{
// query 是第一个, train 是第二个
cv::Point2f p = kp1[goodMatches[i].queryIdx].pt;
// 获取d是要小心!x是向右的,y是向下的,所以y才是行,x是列!
ushort d = depth1.ptr<ushort>( int(p.y) )[ int(p.x) ];
if (d == )
continue;
pts_img.push_back( cv::Point2f( kp2[goodMatches[i].trainIdx].pt ) ); // 将(u,v,d)转成(x,y,z)
cv::Point3f pt ( p.x, p.y, d ); // 深度值/scale = z
cv::Point3f pd = point2dTo3d( pt, C );
pts_obj.push_back( pd );
}
//使用到结构
double camera_matrix_data[][] = {
{C.fx, , C.cx},
{, C.fy, C.cy},
{, , }
}; // 构建相机矩阵
cv::Mat cameraMatrix( , , CV_64F, camera_matrix_data );
cv::Mat rvec, tvec, inliers;
// 求解pnp
cv::solvePnPRansac( pts_obj, pts_img, cameraMatrix, cv::Mat(), rvec, tvec, false, , 1.0, 0.95, inliers ,cv::SOLVEPNP_ITERATIVE);
// 求旋转向量和平移向量,旋转矩阵
cout<<"inliers: "<<inliers.rows<<endl;
cout<<"R="<<rvec<<endl;
cout<<"t="<<tvec<<endl;
//旋转矩阵
cv::Mat R;
cv::Rodrigues(rvec,R);
cout<<"R_matrix="<<R<<endl;

// 画出inliers匹配
vector< cv::DMatch > matchesShow;
for (size_t i=; i<inliers.rows; i++)
{
matchesShow.push_back( goodMatches[inliers.ptr<int>(i)[]] );
}
cv::drawMatches( rgb1, kp1, rgb2, kp2, matchesShow, imgMatches );
cv::namedWindow("inlier matches",);
cv::imshow( "inlier matches", imgMatches );
cv::imwrite( "./data/inliers.png", imgMatches );
cv::waitKey( ); return ;
}

使用到结构,和将旋转向量转为旋转矩阵的函数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

CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
PROJECT( slam ) SET(CMAKE_CXX_COMPILER "g++")
SET( CMAKE_BUILD_TYPE Debug )
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #可执行文件输出的文件夹
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) #库函数编译输出位置 INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/include ) #头文件
LINK_DIRECTORIES( ${PROJECT_SOURCE_DIR}/lib) #使用编译好的库文件libslamBase.a 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. 用 PHP-GTK2 做 Win32 GUI 程序

    PHP通常是做为服务器端脚本执行,如果告诉你PHP可以编写普通的GUI程序,你应该很感兴趣.下面介绍的PHP-GTK就是PHP的GUI扩展.GTK是一个业界标准的图形库,具有良好的移植性.如果你用过l ...

  2. C语言字符串操作函数实现

    1.字符串反转 – strRev void strRev(char *str) { assert(NULL != str);   int length=strlen(str); ; while(end ...

  3. Windows系统文件mshtml.dll

    今天,在vista 32bit,sp 2,IE7的机器上跑开发的软件产品,打开IE,被测系统总是崩溃,换了一台机器,同样的配置环境,却没有重现. 同事的分析很详细,学习了 I tried this c ...

  4. 2018.08.15 bzoj3747: [POI2015]Kinoman(线段树)

    传送门 简单题. 先不管时间复杂度看看怎么做. 对于一段区间[l,r],如果从右端加入一个数a[r+1],对这个区间有什么影响?显然如果区间中已经有了a[r+1]这个数就会产生-a[i+1]的影响,否 ...

  5. java redis基本操作

    package com.redis; import java.util.ArrayList;import java.util.Iterator;import java.util.List;import ...

  6. UVa 12174 Shuffle (滑动窗口)

    题意:你正在使用的音乐播放器有一个所谓的乱序播放功能,即随机打乱歌曲的播放顺序.假设一共有s首歌, 则一开始会给这s首歌随机排序,全部播放完毕后再重新随机排序.继续播放,依次类推.注意,当s首歌播放完 ...

  7. (二)spring-mvc-showcase 和 swagger-springmvc 的恩恩怨怨

    1. 搜索 spring showcase 就可以找到这篇 http://spring.io/blog/2010/07/22/spring-mvc-3-showcase 就是教你如何使用spring ...

  8. nexus 参考文档

    参考文档: http://books.sonatype.com/nexus-book/reference/index.html E:\e\nexus\nexus-2.12.0-01\conf\nexu ...

  9. iPhone 物理尺寸与分辨率

    //    iPhone  物理尺寸(pt:Point)   分辨率(px) //    4S        320*480(3.5英寸)     640*960 //    5,5c,5S   32 ...

  10. 制作一个导航卫星绕地球转动的3D Flash动画

    为便于了解卫星发射以及绕地球运转的过程,制作此动画.