概述

  • 特征点的投影模型为 \(p=\frac{1}{Z} KP\),\(P\)为世界坐标系下某点的坐标(\(Z\)为z方向的坐标),\(p\)为对应图像特征点。\(K\)为内参,在标定好的相机下,\(K\)已知
  • 根据对极几何约束,假设\(p_{2}\)为相机位姿运动\(R\),\(t\)后与前一帧的特征点\(p_{1}\)匹配的特征点,则有
    \[s_1p_1 = KP\]
    \[s_2p_2 = K(RP+t)\]
  • 参考视觉slam14讲的推导,这里可以得到对极约束
    \[{p}_2^T{K^{ - T}}{t^ \wedge }RK{H^{ - 1}}{p_1} = 0\]
    可以通过8点法求解本质矩阵进而得到\(R\),\(t\)
  • 每两帧之间的位姿递推误差积累很快,因此直接递推的位姿是不太稳定的。
  • \(t\)的缩放尺寸不确定,因此不能获得绝对位置

测试代码

主要基于视觉slam14讲的代码,稍微改动的测试,尽管能够求解姿态但是并不十分准确,后续考虑使用双目相机实现定位功能

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <iostream>
#include "opencv2/features2d/features2d.hpp"
#include <vector>
#include <time.h>
#include <opencv2/calib3d/calib3d.hpp>
#include <Windows.h>
//#include "stdafx.h"using namespace cv;
using namespace std;void find_feature_matches(const Mat& img_1, const Mat& img_2,std::vector<KeyPoint>& keypoints_1,std::vector<KeyPoint>& keypoints_2,std::vector< DMatch >& matches);void pose_estimation_2d2d(std::vector<KeyPoint> keypoints_1,std::vector<KeyPoint> keypoints_2,std::vector< DMatch > matches,Mat& R, Mat& t);// 像素坐标转相机归一化坐标
Point2d pixel2cam(const Point2d& p, const Mat& K);int main()
{VideoCapture cap1;//VideoCapture cap2;cap1.open(1);//白色摄像头//cap2.open(2);//黑色摄像头//if (!cap1.isOpened()||!cap2.isOpened())if (!cap1.isOpened()){return -1;}//将摄像头从640*480改成320*240,速度从200ms提升至50ms//cap1.set(CV_CAP_PROP_FRAME_WIDTH, 320);//cap1.set(CV_CAP_PROP_FRAME_HEIGHT, 240);//cap2.set(CV_CAP_PROP_FRAME_WIDTH, 320);//cap2.set(CV_CAP_PROP_FRAME_HEIGHT, 240);//namedWindow("Video", 1);//namedWindow("Video", 2);//namedWindow("pts", 3);//Mat frame;Mat img_1;Mat img_2;while (1){cap1 >> img_1;Sleep(10);cap1 >> img_2;if (!img_1.data || !img_2.data){cout << "error reading images " << endl;return -1;}vector<KeyPoint> keypoints_1, keypoints_2;vector<DMatch> matches;find_feature_matches(img_1, img_2, keypoints_1, keypoints_2, matches);//cout << "一共找到了" << matches.size() << "组匹配点" << endl;//-- 估计两张图像间运动Mat R, t;pose_estimation_2d2d(keypoints_1, keypoints_2, matches, R, t);//cout << "R:" << endl << R << endl;//cout << "t:" << endl << t << endl;-- 验证E=t^R*scale//Mat t_x = (Mat_<double>(3, 3) <<//  0, -t.at<double>(2, 0), t.at<double>(1, 0),//  t.at<double>(2, 0), 0, -t.at<double>(0, 0),//  -t.at<double>(1.0), t.at<double>(0, 0), 0);//cout << "t^R=" << endl << t_x*R << endl;-- 验证对极约束//Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);//for (DMatch m : matches)//{//  Point2d pt1 = pixel2cam(keypoints_1[m.queryIdx].pt, K);//  Mat y1 = (Mat_<double>(3, 1) << pt1.x, pt1.y, 1);//  Point2d pt2 = pixel2cam(keypoints_2[m.trainIdx].pt, K);//  Mat y2 = (Mat_<double>(3, 1) << pt2.x, pt2.y, 1);//  Mat d = y2.t() * t_x * R * y1;//  cout << "epipolar constraint = " << d << endl;//}waitKey(1);}cap1.release();//cap2.release();return 0;
}void find_feature_matches(const Mat& img_1, const Mat& img_2,std::vector<KeyPoint>& keypoints_1,std::vector<KeyPoint>& keypoints_2,std::vector< DMatch >& matches)
{//-- 初始化Mat descriptors_1, descriptors_2;// used in OpenCV3 Ptr<FeatureDetector> detector = ORB::create();Ptr<DescriptorExtractor> descriptor = ORB::create();// use this if you are in OpenCV2 // Ptr<FeatureDetector> detector = FeatureDetector::create ( "ORB" );// Ptr<DescriptorExtractor> descriptor = DescriptorExtractor::create ( "ORB" );Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");//-- 第一步:检测 Oriented FAST 角点位置detector->detect(img_1, keypoints_1);detector->detect(img_2, keypoints_2);//-- 第二步:根据角点位置计算 BRIEF 描述子descriptor->compute(img_1, keypoints_1, descriptors_1);descriptor->compute(img_2, keypoints_2, descriptors_2);//-- 第三步:对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离vector<DMatch> match;//BFMatcher matcher ( NORM_HAMMING );matcher->match(descriptors_1, descriptors_2, match);//-- 第四步:匹配点对筛选double min_dist = match[0].distance, max_dist = match[0].distance;//找出所有匹配之间的最小距离和最大距离, 即是最相似的和最不相似的两组点之间的距离for (int i = 0; i < descriptors_1.rows; i++){double dist = match[i].distance;if (dist < min_dist) min_dist = dist;if (dist > max_dist) max_dist = dist;}//printf("-- Max dist : %f \n", max_dist);//printf("-- Min dist : %f \n", min_dist);//当描述子之间的距离大于两倍的最小距离时,即认为匹配有误.但有时候最小距离会非常小,设置一个经验值30作为下限.for (int i = 0; i < descriptors_1.rows; i++){if (match[i].distance <= max(2 * min_dist, 30.0)){matches.push_back(match[i]);}}
}Point2d pixel2cam(const Point2d& p, const Mat& K)
{return Point2d((p.x - K.at<double>(0, 2)) / K.at<double>(0, 0),(p.y - K.at<double>(1, 2)) / K.at<double>(1, 1));
}void pose_estimation_2d2d(std::vector<KeyPoint> keypoints_1,std::vector<KeyPoint> keypoints_2,std::vector< DMatch > matches,Mat& R, Mat& t)
{// 相机内参,需要标定得到/*1225.22831056496  36.6177252813478    342.7841696131240   1178.20016318321    187.2907550112760   0   1*//*1296.76842892674  46.6256354215592    409.7179331436720   1210.08953016730    69.83892431592290   0   1*///Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);Mat K = (Mat_<double>(3, 3) << 1296.76842892674, 46.6256354215592, 409.717933143672, 0, 1210.08953016730, 69.8389243159229, 0, 0, 1);//-- 把匹配点转换为vector<Point2f>的形式vector<Point2f> points1;vector<Point2f> points2;for (int i = 0; i < (int)matches.size(); i++){points1.push_back(keypoints_1[matches[i].queryIdx].pt);points2.push_back(keypoints_2[matches[i].trainIdx].pt);}//-- 计算基础矩阵Mat fundamental_matrix;fundamental_matrix = findFundamentalMat(points1, points2, CV_FM_8POINT);//cout << "fundamental_matrix is " << endl << fundamental_matrix << endl;//-- 计算本质矩阵Point2d principal_point(409.717933143672, 69.8389243159229);    //相机光心, 标定值double focal_length = 1296.76842892674;         //相机焦距, 标定值Mat essential_matrix;essential_matrix = findEssentialMat(points1, points2, focal_length, principal_point);//cout << "essential_matrix is " << endl << essential_matrix << endl;//-- 计算单应矩阵Mat homography_matrix;homography_matrix = findHomography(points1, points2, RANSAC, 3);//cout << "homography_matrix is " << endl << homography_matrix << endl;//-- 从本质矩阵中恢复旋转和平移信息.recoverPose(essential_matrix, points1, points2, R, t, focal_length, principal_point);//cout << "R is " << endl << R << endl;//cout << "t is " << endl << t << endl;cout << R << endl;
}

转载于:https://www.cnblogs.com/RegressionWorldLine/p/7554709.html

视觉里程计02 基于特征匹配的位姿估计相关推荐

  1. 求解视觉里程计(基于特征点法)

    目录 1 视觉里程计(VO) 2 基于特征点法的视觉里程计算法 2.1 特征点 2.2 ORB特征点的提取与匹配 2.2.1 关键点与描述子 灰度质心法 特征描述子计算 2.2.2 特征点匹配 2.3 ...

  2. 视觉里程计——基于特征点的位姿估计

    slam系统分为前端和后端,其中前端也叫视觉里程计,视觉里程计根据相邻图像的信息进行粗略的位姿估计,为后端提供较好的初始值,发展至今,视觉里程计的算法主要分为两大类:特征点法与直接法:其中特征点法具有 ...

  3. svo: semi-direct visual odometry 半直接视觉里程计 fast角点匹配 光流匹配 单应变换求位姿 直接法求解位姿 高斯均匀分布混合深度滤波

    svo: semi-direct visual odometry 半直接视觉里程计 本博文github地址 svo代码注释 SVO代码分析 较细致 svo: semi-direct visual od ...

  4. 视觉SLAM14讲——视觉里程计1(特征点法)

    前面说过视觉SLAM系统分为前端和后端两个内容,前端也叫做视觉里程计.视觉里程计的主要作用是根据相邻的两张图像的信息粗略的估计出相机运动,给后端一个较好的初始值.视觉里程计的两大算法为:特征点法和直接 ...

  5. 视觉SLAM的二维和三维点的特征匹配,位姿估计的方法总结

    对于视觉,单目经常拿到的数据点是二维,当然也有像双目.kinetic这样的深度相机拿到3d坐标,对于激光一般都是拿到的三维点云坐标.那么对于一些已经提取到的特征点,如何进行匹配,从而估计出传感器的运动 ...

  6. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-特征点法和特征提取和匹配实践

    专栏系列文章如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习 ...

  7. 【视觉SLAM十四讲】视觉里程计—特征点法

    本文为视觉 SLAM 学习笔记,讲解视觉里程计中的特征点法. 本讲内容概要 图像特征的意义,在单幅及多幅图像中提取特征点. 对极几何的原理,利用对极几何的约束恢复图像间相机的三维运动 PnP 问题,利 ...

  8. SLAM前端中的视觉里程计和回环检测

    1. 通常的惯例是把 VSLAM 分为前端和后端.前端为视觉里程计和回环检测,相当于是对图像数据进行关联:后端是对前端输出的结果进行优化,利用滤波或非线性优化理论,得到最优的位姿估计和全局一致性地图. ...

  9. 去掉左边0_SLAM从0到1——11. 视觉里程计VO内容框架

    「本文是之前学习VO 部分整理的思维导图,笔记写入之后均折叠了起来,正文中采用markdown格式展开,可看到笔记内容」 放上来的目的其实是方便自己查阅笔记,同样给有需要的同学提供一点思路. 整体上的 ...

最新文章

  1. python os.chdir函数
  2. map中只有一个值 获取_小学数学,为什么一个三角形中最多只有一个直角或一个钝角...
  3. 年轻人也太禁不起诱惑了吧?
  4. [渝粤教育] 武汉交通职业学院 现代物流管理概论 参考 资料
  5. 搞清axis的含义,这一篇就够了!
  6. 58 到家数据库 30 条军规解读
  7. Scrapy框架学习(二)
  8. (day 52 - 二叉搜索树) 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
  9. 华为网关服务器型号,02311CWM CN21ITGC SP212 I350-T4 华为服务器四口千兆网卡
  10. VirtualBox NAT网络实现 PXE 启动
  11. 晶体二极管和晶体三极管
  12. JavaScript实现涂鸦笔
  13. 为何中国移动的上网速度最慢,无阻它成为最大运营商?
  14. Linux终端分类及tty设置分辨率与字体
  15. spring boot V部落 V人事项目
  16. HTML代码实现符号及商标
  17. 在中断函数和MAIN函数中同时调用同一个函数的有趣现象
  18. 【5GNR物理层】-NR物理层概述
  19. 51单片机 时间控制的不同时段交通灯控制设计(简单版)
  20. 电影主题网站设计——仿360影视网站(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设

热门文章

  1. linux服务器证书安装教程,linux服务器使用certbot免费安装ssl证书
  2. java simpleentry_使用Java流生成对象
  3. macbook交叉编译linux,mac交叉编译到Linux报错
  4. 倒计时 妙味课堂_jQuery实现倒计时(倒计时年月日可自己输入)
  5. python 字符串 变量_Python检查变量是字符串
  6. Openpyxl:读取/写入Excel文件的Python模块
  7. 使用Mongo Shell和Java驱动程序的MongoDB Map Reduce示例
  8. python ide_Python id()
  9. C++基础:什么是数据库?如何创建一个表?
  10. 开课吧:为什么指针被誉为C语言灵魂?