机器视觉中,3D相机产生的深度图像(depth image)通常需要配准(registration),以生成配准深度图像(registed depth image)。实际上配准的目的就是想让深度图和彩色图重合在一起,即是将深度图像的图像坐标系转换到彩色图像的图像坐标系下。下面我们来介绍其推导的过程。

1. 原理

为了描述方便,首先做些简单的假设。如下图所示,3D相机的左侧相机(left camera)为红外相机(即深度相机,ir camera),右侧相机(right camera)为彩色相机(color camera)。现在主流的3D相机都是这样的布局,如xtion,kiinect,orbbict。

已知彩色图像的像素表示为\((u_{R}, v_{R}, z_{R})^{\top}\),\(u_{R}, v_{R}, z_{R}\)分别表示彩色图像的横坐标,纵坐标和相机坐标系下的深度值(z方向上的值,非两点的距离);同样地,深度图像的像素为\((u_{L}, v_{L}, z_{L})^{\top}\),\(u_{L}, v_{L}, z_{L}\)分别表示深度图像的横坐标,纵坐标和相机坐标系下的深度值(z方向上的值,非两点的距离)。注意为了方便表示,本文中下标的R,L分别表示Right,Left的意思。那么深度图配准到彩色图的过程就是找到如下公式中的变换矩阵\(W^{'}\):

\(\begin{bmatrix}
u_{R}\\
v_{R}\\
1
\end{bmatrix}
=W^{'}
\begin{bmatrix}
u_{L}\\
v_{L}\\
1
\end{bmatrix}\)

实际上,变换矩阵\(W^{'}\)并不是真正要求解的矩阵,而是需要重新构造新的变换矩阵,以满足矩阵可逆性。构造过程如下:

a. 构造左侧相机的左侧相机坐标系到图像坐标系的变换

由相机原理(可参考相机标定(2)---摄像机标定原理),可知相机坐标到图像坐标的变换为:

\(z_{L}
\begin{bmatrix}
 u_{L}\\ 
 v_{L}\\ 
1
\end{bmatrix}=\begin{bmatrix}
f/dx & 0 & u_{L}^{0}&0\\ 
0 & f/dy & v_{L}^{0}&0\\
0 & 0& 1&0
\end{bmatrix}
\begin{bmatrix}
x_{L}\\ 
y_{L}\\ 
z_{L}\\ 
1
\end{bmatrix}
\)

以上变换过程等价于如下的表达

\(z_{L}
\begin{bmatrix}
u_{L}\\
v_{L}\\
1\\
1/z_{L}
\end{bmatrix}=
\underset{LR}{\underbrace{
\begin{bmatrix}
f/dx & 0 & u_{L}^{0}&0\\
0 & f/dy & v_{L}^{0}&0\\
0 & 0& 1&0 \\
0 & 0& 0&1
\end{bmatrix}
}}
\begin{bmatrix}
x_{L}\\
y_{L}\\
z_{L}\\
1
\end{bmatrix}\)

于是图像坐标系到相机坐标系的变换为:

\(\begin{bmatrix}
x_{L}\\
y_{L}\\
z_{L}\\
1
\end{bmatrix}=z_{L}*LR^{-1}*\begin{bmatrix}
u_{L}\\
v_{L}\\
1\\
1/z_{L}
\end{bmatrix}\)                             (1)

其中\(LR\)为双目相机标定的左侧相机内参矩阵,LR表示为Left Rotation之意

b. 构造右侧相机的右侧相机坐标系到图像坐标系的变换

根据a,同理地,左侧相机坐标系到图像坐标系的变换为:

\(z_{R}
\begin{bmatrix}
u_{R}\\ 
v_{R}\\ 
1\\ 
1/z_{R}
\end{bmatrix}=
\underset{RR}{\underbrace{
\begin{bmatrix}
f/dx & 0 & u_{R}^{0}&0\\ 
0 & f/dy & v_{R}^{0}&0\\
0 & 0& 1&0 \\
0 & 0& 0&1
\end{bmatrix}
}}
\begin{bmatrix}
x_{R}\\ 
y_{R}\\ 
z_{R}\\ 
1
\end{bmatrix}\)

于是图像坐标系到相机坐标系的变换为:

\(\begin{bmatrix}
x_{R}\\ 
y_{R}\\ 
z_{R}\\ 
1
\end{bmatrix}=z_{R}*RR^{-1}*\begin{bmatrix}
u_{R}\\ 
v_{R}\\ 
1\\ 
1/z_{R}
\end{bmatrix}\)                                (2)

其中\(RR\)为双目相机标定的右侧相机内参矩阵,RR表示为Right Rotation之意

c. 左侧相机坐标系到右侧相机坐标系变换

\(\begin{bmatrix}
x_{R}\\
y_{R}\\
z_{R}\\
1
\end{bmatrix}=M*\begin{bmatrix}
x_{L}\\
y_{L}\\
z_{L}\\
1
\end{bmatrix}\)                                     (3)

其中M为4x4的变换矩阵,可理解为两个相机光心的外参矩阵,平移+旋转矩阵。此矩阵为上面标定得到的外参数矩阵

d. 左侧图像坐标转换到右侧图像坐标

将(1)和(2)代入(3)得到

\(z_{R}*RR^{-1}*\begin{bmatrix}
u_{R}\\
v_{R}\\
1\\
1/z_{R}
\end{bmatrix}=
z_{L}*M*LR^{-1}*\begin{bmatrix}
u_{L}\\
v_{L}\\
1\\
1/z_{L}
\end{bmatrix}\)

两侧同时左乘RR矩阵得到

\(\begin{bmatrix}
u_{R}\\
v_{R}\\
1\\
1/z_{R}
\end{bmatrix}=
\frac{z_{L}}{z_{R}}*\underset{W}{\underbrace{RR*M*LR^{-1}}}*\begin{bmatrix}
u_{L}\\
v_{L}\\
1\\
1/z_{L}
\end{bmatrix}\)

由于\(z_{L}\approx z_{R}\),因此上述公式可以简化为:

\(\begin{bmatrix}
u_{R}\\
v_{R}\\
1\\
1/z_{R}
\end{bmatrix}=
W * \begin{bmatrix}
u_{L}\\
v_{L}\\
1\\
1/z_{L}
\end{bmatrix}\qquad \qquad \qquad \qquad (4)\)

W为计算得到的4x4变换矩阵,我们表示为

\(W = \begin{bmatrix}
r_{11} & r_{12}& r_{13}& r_{14}\\
r_{21} & r_{22}& r_{23}& r_{24}\\
r_{31} & r_{32}& r_{33}& r_{34}\\
r_{41} & r_{42}& r_{43}& r_{44}
\end{bmatrix}\)

由此将公式(4)展开,可得到左侧图像坐标转换到右侧图像坐标解析解,即

\(u_{R} = r_{11}*u_{L}+ r_{12}*v_{L}+ r_{13}+ r_{14}*\frac{1}{z_{L}}\qquad \qquad \qquad \qquad (5)\\
v_{R} = r_{21}*u_{L}+ r_{22}*v_{L}+ r_{23}+ r_{24}*\frac{1}{z_{L}}\qquad \qquad \qquad \qquad (6)\)

至此推导完毕,由此可见每个像素点的配准和原始图像的位置以及深度有着直接紧密的联系。ROS有一个包用于配准的计算,却异常的慢,按照以上的公式没有理由这么慢,看来还是知道原理实现才行。

注意:左侧右侧相机只是逻辑上的意义,即左右相机摆放的位置是可以任意的,这里描述的左侧相机可以实际摆在右侧(左侧),右侧相机可以摆在左侧(右侧)。因为外餐矩阵M可以表达出他们实际的关系。因此我们只需要知道右侧相机是彩色相机,左侧是深度相机即可。

2. 实现代码

配准代码实现如下 

void Depth2RGB(cv::Mat &src, cv::Mat &dst,const float *W)
{
double z;
uint16_t u, v,d;
uint16_t u_rgb, v_rgb;
cv::Mat newdepth(dst.rows, dst.cols, CV_16UC1, cv::Scalar());
for (v = ; v < src.rows; v++)
{
for (u = ; u < src.cols; u++)
{
d = src.at<uint16_t>(v, u);
z = (double)d;
u_rgb = (uint16_t)((W[] * (double)u + W[] * (double)v + W[] + W[] / z));//参照上述公式(5)
v_rgb = (uint16_t)((W[] * (double)u + W[] * (double)v + W[] + W[] / z));//参照上述公式(6)
if (u_rgb < && u_rgb >= newdepth.cols && v_rgb < && v_rgb >= newdepth.rows)
{
uint16_t *val = (uint16_t *)newdepth.ptr<uchar>(v_rgb)+u_rgb; *val = d;
}
}
}
dst = newdepth;
}

3. 阅读资料

[1]. Kinect深度图与摄像头RGB的标定与配

深度图像配准(Registration)原理的更多相关文章

  1. 【计算机视觉】图像配准(Image Registration)

    (Source:https://blog.sicara.com/image-registration-sift-deep-learning-3c794d794b7a)  图像配准方法概述 图像配准广泛 ...

  2. 图像配准:从SIFT到深度学习

      图像配准(Image Registration)是计算机视觉中的基本步骤.在本文中,我们首先介绍基于OpenCV的方法,然后介绍深度学习的方法. 什么是图像配准 图像配准就是找到一幅图像像素到另一 ...

  3. PCL深度图像(1)

    目前深度图像的获取方法有激光雷达深度成像法,计算机立体视觉成像,坐标测量机法,莫尔条纹法,结构光法等等,针对深度图像的研究重点主要集中在以下几个方面,深度图像的分割技术 ,深度图像的边缘检测技术 ,基 ...

  4. RGB-D(深度图像) & 图像深度

    RGB-D(深度图像)   深度图像 = 普通的RGB三通道彩色图像 + Depth Map   在3D计算机图形中,Depth Map(深度图)是包含与视点的场景对象的表面的距离有关的信息的图像或图 ...

  5. 深度学习Anchor Boxes原理与实战技术

    深度学习Anchor Boxes原理与实战技术 目标检测算法通常对输入图像中的大量区域进行采样,判断这些区域是否包含感兴趣的目标,并调整这些区域的边缘,以便更准确地预测目标的地面真实边界框.不同的模型 ...

  6. Atitti 图像处理 图像混合 图像叠加 blend 原理与实现

    Atitti 图像处理 图像混合 图像叠加 blend 原理与实现 混合模式 编辑 本词条缺少信息栏,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! 混合模式是图像处理技术中的一个技术名词,不 ...

  7. Atitit.计算机图形图像图片处理原理与概论attilax总结

    Atitit.计算机图形图像图片处理原理与概论attilax总结 计算机图形1 图像处理.分析与机器视觉(第3版)1 数字图像处理(第六版)2 图像处理基础(第2版)2 发展沿革 1963年,伊凡·苏 ...

  8. 非刚性图像配准 matlab简单示例 demons算法

    2011-05-25 17:21 非刚性图像配准 matlab简单示例 demons算法, % Clean clc; clear all; close all; % Compile the mex f ...

  9. Opencv探索之路(二十):制作一个简易手动图像配准工具

    近日在做基于sift特征点的图像配准时遇到匹配失败的情况,失败的原因在于两幅图像分辨率相差有点大,而且这两幅图是不同时间段的同一场景的图片,所以基于sift点的匹配已经找不到匹配点了.然后老师叫我尝试 ...

随机推荐

  1. hadoop day 1

    hadoop是什么? 解决的问题: 海量数据的存储(HDFS):供hbase,mapreduce进行处理 海量数据的分析(MapReduce) 资源管理调度(YARN) 搜索引擎: 爬虫系统+站内搜索 ...

  2. python学习笔记第二周

    目录 一.基础概念 1.模块 1)os模块 2)sys模块 2.pyc文件 3.数据类型 1)数字 2)布尔值 3)字符串 4.数据运算 5.运算符 6.赋值运算 7.逻辑运算 8.成员运算 9.身份 ...

  3. 【c++基础】字符数组和string相互转换

    字符数组转化成string类型char ch [] = "ABCDEFG";string str(ch);//也可string str = ch;或者char ch [] = &q ...

  4. 梯度下降法、牛顿法、高斯牛顿法、LM最优化算法

    1.梯度下降法 2.牛顿法 3.高斯牛顿法 4.LM算法

  5. day python011函数的进阶

    形参: 1.位置传参  2. 默认值传参. 3.动态传参 一   动态传参(形参的一种): 之前我们说过了了传参, 如果我们需要给⼀一个函数传参, ⽽而参数⼜又是不确定的. 或者我给⼀一个函数传很多参 ...

  6. (9)模板层 - templates(模板语言、语法、取值、过滤器、变量的使用)

    django的模板语言:DTL 模板语言的变量传入 这个是标签 {{ 变量名 }} {{ 变量名 }}   #模板语言的替换可以在模板中的任意位置生效 PS:通过 . 可以做深度查询 模板语言的过滤器 ...

  7. 《DSP using MATLAB》Problem 6.12

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  8. hdu3336 Count the string 扩展KMP

    It is well known that AekdyCoin is good at string problems as well as number theory problems. When g ...

  9. IDEA 热部署- 自动编译设置

    原文:https://www.cnblogs.com/TechSnail/p/7690829.html    &&   https://blog.csdn.net/qq_3129357 ...

  10. go build Multiple main.go file

    golang 如何编译同目录下多个main文件? 多个go 文件在相同目录编译时候会报错, 可将文件放在不同的package下,结构如下: buidtest/├── a│   └── a.go└── ...