机器视觉中,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. Fizz Buzz 问题

    要求: 给你一个整数n. 从 1 到 n 按照下面的规则打印每个数: 如果这个数被3整除,打印fizz. 如果这个数被5整除,打印buzz. 如果这个数能同时被3和5整除,打印fizz buzz. 示 ...

  2. 剑指offer-面试题1:赋值运算符函数

    如下为类型CMyString的声明,请为该类型添加赋值运算符函数. 解析:给一个类进行运算符重载. 关键部分代码: CMyString& CMyString::operator =(const ...

  3. 使用libcurl作为Http client

    产品通过HTTP协议为外部提供接口服务,常规情况是客户通过HTTP协议请求服务,服务结束后通过HTTP协议将服务记录POST到请求方. 用原生C实现了一个简单的HTTP Client,只有简单的功能: ...

  4. annotation注释简单介绍

    元数据的作用 如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类: l         编写文档:通过代码里标识的元数据生成文档. l         ...

  5. TS 基础数据类型

    1.基础数据类型 Boolean布尔值   Number数字 String字符串  Array数组 Tuple元组  Enum枚举   Any    void Boolean布尔值:true/fals ...

  6. 2017.7.12 Python的6种内建序列及操作

    数据结构是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合,这些数据元素可以是数字或者字符,甚至可以是其他数据结构. 在Python中,最基本的数据结构是序列(sequence).序列中的 ...

  7. C++学习(二)之Visual Studio写system语句 生成可执行文件

    system命令 1.首先先介绍一些system命令 windows+tab  //切换窗口 windows+R  //调出命令窗口 命令: 输入 calc  打开计算机 输入 cmd 打开命令窗口 ...

  8. 线程---同步(synchronized)

    实现线程同步的一种方式介绍: 思路: 首先,需要被协调的类,先实现线程,并重写run方法 然后,在被协调的类中私有化控制器,控制器实例化,由构造器带入. 其次,由控制器对象具体负责调用. 举例:循环输 ...

  9. oracle Awr报告

    Select DBID,INSTANCE_NUMBER,SNAP_ID,TO_CHAR(END_INTERVAL_TIME,'YYYY-MM-DD HH24:MM:SS') AS END_TIME,T ...

  10. UBUNTU 安装教程

    玩过linux,只是博主觉得现在的很多服务器都是linux系统的,而自己属于那种前端也搞,后台也搞,对框架搭建也感兴趣,但是很多生产上的框架和工具都是安装在服务器上的,而且有不少大公司都要求熟悉在li ...