个人博客:http://www.chenjianqu.com/

原文链接:http://www.chenjianqu.com/show-80.html

本文是读高翔大佬的<视觉SLAM14讲>的笔记,准备开始入坑了。。。

针孔相机模型

大部分常见的相机都可以抽象为针孔模型:

其中P点是三维空间中的一点,P’点是P在图片上的投影点,O是相机坐标系的原点,O’是物理成像平面的原点。可得Z/f=X/X’=Y/Y’,即:X’=f*X/Z,Y’=f*Y/Z,其中[X,Y,Z]是P点在相机坐标系的坐标。

像素坐标系o-u-v在物理成像平面上。原点位于图像的左上角,u轴向右与x轴平行,v轴向下与y轴平行。像素坐标系与物理成像坐标系之间相差一个缩放和一个原点的平移。设像素坐标在u轴上缩放了α倍,在v轴上缩放了b倍,同时原点平移了[cx,cy],则P’的物理坐标与像素坐标的关系为:u=α*X'+cx, v=β*Y'+cy。代入X'和Y',并把α*f合并为fx,β*f合并为fy,得:

其中,f的单位为米,α, β的单位为像素/米,所以fx, fy和cx, cy的单位为像素。写成矩阵形式:

或:

其中K称为相机的内参数矩阵(Camera Intrinsics)。内参通常在出厂后是固定的,有时需要自己确定内参,也就是标定

点P在世界坐标系中的坐标为Pw,在相机坐标系中的坐标为P,P是Pw根据相机当前位姿从世界坐标系变换到相机坐标系下的结果。相机的位姿由相机相对于世界坐标的旋转矩阵R平移向量t来描述,则有:

T是R和t构成的齐次坐标,先与Pw相乘,再与K相乘。该公式描述了P点的世界坐标到像素坐标的投影关系,其中相机的位姿R,t又被称为外参数(Camera Extrinsics)

换个角度,也可以先把P点从世界坐标系投影到相机坐标系,再投影到像素坐标系。其中投影到相机坐标系的时候,可以去掉坐标的最后一维,也就是深度维,把该维度置为1。得到P点在相机归一化平面上的投影:

归一化坐标可看成相机前方z = 1 处的平面上的一个点,这个 z = 1 平面也称为归一化平面。归一化坐标再左乘内参就得到了像素坐标,所以可以把像素坐标 [u, v]看成对归一化平面上的点进行量化测量的结果,即像素坐标系也可以放在归一化平面上。

从该过程可知,空间点的深度信息在投影过程中被丢失了,单目视觉中没法得到像素点的深度值。如下所示:

双目相机模型

双目相机一般由水平放置的左眼相机和右眼相机组成,可以把两个相机都看作针孔相机。因为是水平放置的,意味着两个相机的光圈中心都位于x轴上,两者之间的距离称为双目相机的基线(Baseline)。双目相机的成像模型如下:

根据三角形的相似性,有:

z是相机坐标系中P点的z维数值(即P点的深度),f是相机的焦距,uL和uR是像素坐标系(这里把成像平面放在相机前面,等价与放在后面的情况)的坐标值,d为左右图的横坐标之差,称为视差(Disparity)

由z=fb/d可知,根据视差,可以估计像素与相机之间的距离。视差与距离成反比:视差越大,距离越近。由于视差最小为一个像素,于是双目的深度存在一个理论上的最大值,由 fb 确定。当基线越长时,双目能测到的最大距离就会越远。

虽然由视差计算深度的公式很简洁,但视差d本身的计算却比较困难,需要确切地知道左眼图像某个像素出现在右眼图像的哪一个位置(即对应关系)。常用的计算视差的算法有SAD,GC,SGBM,DP,BM等,比较如下

SGBM

semi-global matching(SGM)是一种用于计算双目视觉中视差(disparity)的半全局匹配算法,在OpenCV中的实现为semi-global block matching(SGBM)。https://blog.csdn.net/A_L_A_N/article/details/81490043

OpenCV实例

因此跟Anaconda冲突了,PCL死活编译不过,因此这里运行高博给的代码,他是用Pangolin显示点云:

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(imagebinoculartest)
# 添加c++ 11标准支持
set( CMAKE_CXX_FLAGS "-std=c++11" )find_package( OpenCV 3 REQUIRED )
find_package( Pangolin )
include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories("/usr/include/eigen3")
include_directories( ${Pangolin_INCLUDE_DIRS} )add_executable(imagebinoculartest main.cpp)
target_link_libraries(imagebinoculartest ${OpenCV_LIBS})
target_link_libraries( imagebinoculartest ${Pangolin_LIBRARIES} )
install(TARGETS imagebinoculartest RUNTIME DESTINATION bin)

main.cpp

#include <iostream>
#include <chrono>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <Eigen/Core>
#include<opencv2/calib3d/calib3d.hpp>
#include <pangolin/pangolin.h>
using namespace std;
using namespace Eigen;
using namespace cv;//高博用pangolin中显示点云
void showPointCloud(const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud);
int main ( int argc, char** argv )
{double fx = 718.856, fy = 718.856, cx = 607.1928, cy = 185.2157;// 内参double b = 0.573;// 基线cout << "OpenCV version : " << CV_VERSION << endl;Mat leftImg=imread("left.png",0);Mat rightImg=imread("right.png",0);imshow ( "leftImg", leftImg);imshow ( "rightImg", rightImg);waitKey ( 0 );//OpenCV实现的SGBM立体匹配算法Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,//minDisparity 最小视差96, //numDisparities 视差搜索范围,值必需为16的整数倍。最大搜索边界=最小视差+视差搜索范围9, //blockSize 块大小//8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;8 * 9 * 9, //P1 控制视差变化平滑性的参数。P1、P2的值越大,视差越平滑。P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。//32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize32 * 9 * 9, //P21, //disp12MaxDiff 左右一致性检测最大容许误差阈值。63, //preFilterCap,预处理时映射参数10, //uniquenessRatio 唯一性检测参数,100, //speckleWindowSize 视差连通区域像素点个数的大小。对于每一个视差点,当其连通区域的像素点个数小于speckleWindowSize时,认为该视差值无效,是噪点。32//speckleRange 视差连通条件,在计算一个视差点的连通区域时,当下一个像素点视差变化绝对值大于speckleRange就认为下一个视差像素点和当前视差像素点是不连通的。);Mat disparity_sgbm, disparity;sgbm->compute(leftImg, rightImg, disparity_sgbm); //计算视差图disparity_sgbm.convertTo(disparity, CV_32F, 1.0 / 16.0f);//得到视差图cv::imshow("disparity", disparity / 96.0);cv::waitKey(0);// 生成点云vector<Vector4d, Eigen::aligned_allocator<Vector4d>> pointcloud;// 如果机器慢,把后面的v++和u++改成v+=2, u+=2for (int v = 0; v < leftImg.rows; v++)for (int u = 0; u < leftImg.cols; u++) {if (disparity.at<float>(v, u) <= 0.0 || disparity.at<float>(v, u) >= 96.0) continue;Vector4d point(0, 0, 0, leftImg.at<uchar>(v, u) / 255.0); // 前三维为xyz,第四维为颜色// 根据双目模型计算 point 的位置double x = (u - cx) / fx;double y = (v - cy) / fy;double depth = fx * b/(disparity.at<float>(v, u));point[0] = x * depth;point[1] = y * depth;point[2] = depth;pointcloud.push_back(point);}cv::imshow("disparity", disparity / 96.0);cv::waitKey(0);// 画出点云showPointCloud(pointcloud);return 0;
}void showPointCloud(const vector<Vector4d, Eigen::aligned_allocator<Vector4d>> &pointcloud)
{pangolin::CreateWindowAndBind("Point Cloud Viewer", 1024, 768);glEnable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);pangolin::OpenGlRenderState s_cam(pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0));pangolin::View &d_cam = pangolin::CreateDisplay().SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f).SetHandler(new pangolin::Handler3D(s_cam));while (pangolin::ShouldQuit() == false) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);d_cam.Activate(s_cam);glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glPointSize(2);glBegin(GL_POINTS);for (auto &p: pointcloud) {glColor3f(p[3], p[3], p[3]);glVertex3d(p[0], p[1], p[2]);}glEnd();pangolin::FinishFrame();usleep(5000);   // sleep 5 ms}return;
}

原始左右两图:

SGBM计算得到的视差图:

根据视差图得到的点云图:

参考文献

[0]高翔.视觉SLAM 14讲

相机模型和双目立体匹配相关推荐

  1. 相机模型和双目立体匹配完成一个基于KITTI立体相机采集图片的立体图像匹配程序,生成视差图像和3D点云图像

    机模型和双目立体匹配完成一个基于KITTI立体相机采集图片的立体图像匹配程序,生成视差图像和3D点云图像 一.针孔相机模型 二.双目相机模型 三.OpenCV实例实现用Pangolin生成视差图像和3 ...

  2. 视觉SLAM笔记(21) 双目相机模型

    视觉SLAM笔记(21) 双目相机模型 1. 深度确定 2. 景物差异 3. 成像原理 4. 计算困难 1. 深度确定 针孔相机模型描述了单个相机的成像模型 然而,仅根据一个像素,是无法确定这个空间点 ...

  3. 几种相机模型:针孔相机模型、双目相机模型、RGB-D相机——SLAM学习笔记5

    几种相机模型:针孔相机模型.双目相机模型.RGB-D相机 针孔相机模型 双目相机模型 RGB-D相机模型 针孔相机模型 针孔相机是最简单的相机,很多相机也可以看作是针孔相机来进行处理.如图1所示,空间 ...

  4. 相机模型:单目、双目、深度相机模型及相机畸变

    针孔模型 坐标系 首先定义名词: 光轴:各坐标系的Z轴方向 光心:光轴的中心点 主点:光轴同图像平面的交点 焦距:光心到图像平面的距离 相机通常存在四个相关的坐标系:世界坐标系.相机坐标系.像素坐标系 ...

  5. 视觉SLAM——针孔相机模型 相机标定原理 双目相机模型 深度相机对比

    前言 本博客为主要学习<视觉SLAM十四讲>第5讲.<机器人学的状态估计>第6章6.4.1透视相机.<多视图几何>第5章摄像头模型等SLAM内容的总结与整理. 主要 ...

  6. 真实场景的双目立体匹配(Stereo Matching)获取深度图详解

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 双目立体匹配一直是双目视觉的研究热点,双目相机拍摄同一场景的左.右 ...

  7. 双目立体匹配修炼之路

    文章目录 前言 一.双目立体匹配是什么? 1.双目视觉: 2. 视差: 3."对极约束"概念: 4. 对极几何(Epipolar Geometry) 5. 如何计算得到深度呢? 二 ...

  8. 双目立体匹配流程详解

    原文链接 https://www.cnblogs.com/riddick/p/8486223.html 真实场景的双目立体匹配(Stereo Matching)获取深度图详解 双目立体匹配一直是双目视 ...

  9. 相机标定和双目相机标定标定原理推导及效果展示

    文章目录 前言 一.相机标定 1.相机的四个坐标系 2.相机的畸变 二.张正友标定法 1.求解内参矩阵与外参矩阵的积 2.求解内参矩阵 3.求解外参矩阵 4.标定相机的畸变参数 5.双目标定 6.极线 ...

最新文章

  1. C# WinForm中 让控件全屏显示的实现代码
  2. vmware linux系统 ip,修改虚拟机上Linux系统的IP地址
  3. “隐忍”多年的“水果大王”百果园要寻求资本协助了?
  4. NYOJ 562 盒子游戏
  5. XP屏幕上下翻转的现象及解决
  6. wordList04
  7. 15.IDA-查看XREF列表(Ctrl+x)
  8. nullnullProcessing Bitmaps Off the UI Thread 处理来自UI线程的位图
  9. 安装linux后win7引导程序,在Ubuntu系统下装Win7并引导双系统
  10. Altium AD20批量修改丝印大小、更改丝印字体、丝印显示中文、更改位号丝印 相对元件的位置
  11. 【Qt串口调试助手】1.0 - 400行代码撸一个Qt5串口调试助手框架
  12. DigitalRealty公司在达拉斯新建一个数据中心
  13. centos7挂载大于10T及以上硬盘
  14. coreldraw x5 选择工具快捷键_CorelDRAW X5实用教程:X5版本常用快捷键
  15. linux格式化只读u盘,linux下FAT32格式u盘只读的问题及解决方法
  16. 论团队协作的一个小故事
  17. html打开方式怎么没有反应,为什么我点开启程序没反应
  18. 第三届蓝桥杯B组 C/C++取球游戏
  19. Unity 射线与碰撞范围检测【踩坑记录】
  20. 消息队列的消费幂等性如何保证

热门文章

  1. 初中物理凸透镜成像动态图_初中物理:凸透镜成像、望远镜与显微镜的区别
  2. java两个数最大公约数和最小公倍数,java求两个数的最大公约数和最小公倍数
  3. c语言定义的几种易错的说明
  4. Linux服务之SSH
  5. HTTP----HTTP2.0新特性
  6. 2.9 while循环
  7. 安装Win7系统时使用diskpart命令将GPT分区转换为MBR分区
  8. SQL:查询重复出现记录
  9. Oracle中的单行函数
  10. Spoken English Practice (I'm having whatever you're having)