跳轉到內容

RGB+D 影片處理

25% developed
來自華夏公益教科書,開放的書籍,開放的世界

什麼是 RGB+D 影片?

[編輯 | 編輯原始碼]
  • 2.5D 資料
  • 3D 感知(立體聲、結構光、TOF、雷射掃描器,...)

向量、矩陣和標量

 * vector (lowercase Gothic alphabets): v, p, m = [m1, m2, ..., mk]', ...
 * matrix (uppercase Gothic alphabets): R, A, ...
 * scalar (Italic alphabets: s, t, X, Y, Z, ...

索引

   v(1)   // the 1st element of the vector v
   R(1,2) // the 1st row and 2nd col of the matrix R
   A(:,1) // the 1st vector _ from A = [v1, v2, ..., vN]

一些保留符號

hp: a homogeneous representation of a 2D point, hp = [u, v, 1]'
hx: a homogeneous representation of a 3D point, hx = [X, Y, Z, 1]'
p: a 2D point, p = [u, v]'
x: a 3D point, x = [X, Y, Z]'
H: (3x3) planar homography matrix
P: (3x4) projective projection matrix

座標變換

o<W>: the origin of the world frame
o<C>: the origin of the camera frame
o<O>: the origin of the object frame
(e.g., x<C> represents a 3D point in the camera frame)
R: (3x3) rotation matrix
t: (3x1) translation vector
T<n, m>: transformation from m to n coordinate system (e.g., o<C> = T<C, W> o<W>)
  • 除非我們指定,否則我們使用(第一個)相機座標系作為世界參考系。
  • 除了以上符號外,我們將遵循 MATLAB 的符號。

座標變換

[編輯 | 編輯原始碼]

當您取一個 3D 點,,該點的每個值 x(j) 都是相對於特定座標系表示的(例如,感測器座標系)。點 X 也可以在不同的座標系中表示(例如,房間的一個角),。為了區分兩組值,我們可以寫出符號以及相應的座標系:,其中 是相對於感測器座標系的點,而 是相對於角落座標系的相同點。兩個座標系之間存在一個剛性運動,該運動由一個 (3×3) 旋轉矩陣 和一個 (3×1) 平移向量 表達:。在齊次座標系中,剛性運動可以寫成。請注意,我們放置了源座標系(角落)和目標系統(感測器)的符號。一系列變換表示為,其中.

校準

[edit | edit source]

為什麼要校準?

總體流程

 a) RGB camera ---- RGB image --(1)-- Rectified RGB image --(3)-- Registered RGB image (w.r.t. IR image)
 b) IR camera ---- IR image --(2)--  Rectified IR image
 c) projector --(internal calibration + IR image)-- Depth image --(4)-- Rectified Depth image --(5)-- 3D points                         
  • 問題 1: (1), (2), (4) - 徑向畸變
  • 方法

http://www.ros.org/wiki/kinect_calibration/technical

http://nicolas.burrus.name/index.php/Research/KinectCalibration


  • 問題 2: (3) - RGB 影像到 IR 影像的配準
  • 方法:平面單應性


  • 問題 3: (5) - 3D 重建
  • 方法:三角測量
  • 全部合一

http://www.ee.oulu.fi/~dherrera/kinect/

幾何基元和不確定性

[edit | edit source]

2D 空間中的點和線

[編輯 | 編輯原始碼]

幾何實體

[編輯 | 編輯原始碼]
  • 當 x 和 s*x 代表相同的幾何實體時,實體 x 是齊次的。
  • 點:歐幾里得空間中的二維點 xx = [x1, x2]' 在二維投影空間中表示為 x = [x1, x2, 1]'。
  • 線:二維直線表示為 l = [a b c]'。

二維幾何關係

[編輯 | 編輯原始碼]
  • 直線和直線上一點的點積為 0:x' * l == 0。
二維歐幾里得空間中的直線方程為 a*x + b*y + c == 0。我們可以將其改寫為 [a b c] * [x y 1]' == 0,這就是點積。因此,在投影空間中,dot(x,l) == x' * l == 0。
  • 兩條直線的叉積給出交點:x = cross(l,m)。
兩條直線(l 和 m)的交點是一個點。交點 x 位於直線 l 上:dot(x,l) = 0。此外,點 x 位於直線 m 上:dot(x,m) = 0。因此,l 和 m 的叉積給出交點 x。
  • 兩點的叉積給出直線:l = cross(x, y)。
相似性
[編輯 | 編輯原始碼]
  • 兩點:|| x - y ||
  • 兩條直線:|| l x m ||
  • 兩條線段

三維空間中的點、線、平面和圓錐曲線

[編輯 | 編輯原始碼]
  • 三維直線:兩點 X、Y 構成一條直線。
普呂克矩陣定義為 U(4x4) = X Y' - Y X'。從 U 中,直線定義為 L := [ U(4,1) U(4,2) U(4,3) U(2,3) U(3,1) U(1,2) ]'。
直線 L 由 [方向向量 U1 | 法向量 U2] 部分組成。U1 代表向量 Y - X。U2 代表 X 和 Y 的叉積。顯然,dot(U1,U2) = 0。
  • 兩條直線的交點是一個點。如果兩條直線 L、M 相交,dot(L,M) = 0。
  • 兩平面的交點形成一條直線。
  • 經過平面 K 的直線 L 形成一個點。
  • ...

剛體運動

[編輯 | 編輯原始碼]
尤拉角、軸角、沙西定理
關於自由形狀精確配準的剛體變換表示
  • 三維座標變換
  • 對齊(參見:ICP)

三維投影變換

[編輯 | 編輯原始碼]
TP:三維空間的投影變換(15dof),TP = [TA t; v' s]
TA:三維空間的仿射變換(12dof),TP = [TA t; 0' 1]
TS:三維空間的相似變換(7dof),TP = [s*R t; 0' 1]
TE:三維空間的歐幾里得變換(6dof),TP = [R t; 0' 1]


不確定性和幾何約束

[編輯 | 編輯原始碼]

幾何實體的不確定性

[編輯 | 編輯原始碼]
  • 點的 uncertainty?
  • 直線的 uncertainty?
  • 方向的 uncertainty?
  • 平面的 uncertainty?

示例:三角形

[編輯 | 編輯原始碼]
三角形的三個角

假設你用量角器測量三角形的三個角。從第一次試驗中,你得到了值 [30.5, 60.0, 90.1] 度。這些值並不完美,因為它們的總和不等於 180 度!因此,你決定測量 10 次並將它們取平均值。但是,你仍然不確定平均值的總和是否會等於 180 度。

圖 XXX 顯示了三角形中三個角之間的關係。

方法
1) Define a manifold M (e.g. Figure XXX)
2) Measure a set of values p = [a(i), b(i), c(i)] for N times
3) Compute the mean m and the covariance matrix S
4) Project p and S onto the manifold M: q, H
output:
  angles <-- q
  variance <-- f(H)

對多個觀測值取平均值

[編輯 | 編輯原始碼]

當你在 N 個感測器的外部標定中觀察到多個剛體變換時,你可以使用“對偶四元數”來計算“平均”剛體變換。

演算法
* input: {R(i), t(i)} % a set of R, t
* output: R*, t*      % optimal R, t
Procedure:
* convert all R(i), t(i) to DQ(i) % Dual Quaternions
* find the mean DQ* from {DQ(i)}
* convert DQ* to R*, t*
對偶四元數
[編輯 | 編輯原始碼]

"類似於單位長度四元數可以表示三維空間中的旋轉,單位長度對偶四元數可以表示三維空間中的剛體運動。這個事實被用於理論運動學以及在三維計算機圖形學、機器人技術和計算機視覺中的應用。"維基百科

L. Kavan, S. Collins, C. O'Sullivan, J. Zara (2006) 對偶四元數用於剛體變換混合,技術報告,都柏林三一學院。
帶有良好文件的 Matlab 工具箱
在流形上工作
[編輯 | 編輯原始碼]

http://stat.fsu.edu/~anuj/CVPR_Tutorial/ShortCourse.htm 形狀分析和活動識別的微分幾何方法

多個檢視的配準

[編輯 | 編輯原始碼]

僅點雲

[編輯 | 編輯原始碼]

點配準問題 (1) 查詢點到點的對應關係,(2) 估計它們之間的變換。以前的方法可以分為三類:ICP(迭代最近點)、軟分配方法和機率方法。

ICP 可能會陷入區域性最小值,並且對初始化和接受匹配的閾值敏感。因此,最近點策略被連續最佳化框架內的軟分配取代。但是,在存在異常值的情況下,收斂性不能得到保證。點到點的分配問題可以被轉化為估計(高斯)混合模型的引數。--> EM-ICP

  • ICP、EM-ICP
  • 張量
  • 初始化

原始碼

[編輯 | 編輯原始碼]

RGB 2D 特徵 + 深度值

[編輯 | 編輯原始碼]

由於我們同時擁有 RGB 和深度圖,因此可以透過簡單的 3D 特徵匹配來完成兩個檢視的配準。給定兩組對應的 3D 特徵描述符,X = [x1, x2, ..., xn] 和 Y = [y1, y2, ..., yn],X 和 Y 之間的剛體運動,Y = T X,可以直接計算。在存在異常值的情況下,魯棒估計方法(如 RANSAC)可以提供精確的結果。

虛擬碼:計算剛性運動
* input: X, Y
* output: R, t

Solution = [];
For i=1:N
  randomly select 5 corresponding points from X, Y: s1 = {X(j), X(k), X(l)} and s2 = {Y(j), Y(k), Y(l)}
  estimate T' = (R', t') using s1, s2
  compute Y^ = T' X
  store the number of inliers, m(i), to Solution: S(i) = (R'(i), t'(i), m(i))
Endfor
Answer = arg max(i) (S(i).m(i))

2D、2.5D 和 3D 特徵

[編輯 | 編輯原始碼]

曲率估計:HK 分割

[編輯 | 編輯原始碼]
  • 參見 HK 分割
  • 存在噪聲深度圖時的曲率估計

2.5D 特徵

[編輯 | 編輯原始碼]
  • 在深度圖上使用 2D 影像特徵

我們可以在 2.5D 深度圖上使用 2D 影像特徵(例如,SIFT、ORB、SURF、LBP)。關鍵區別之一是影像的尺度。由於我們知道範圍圖中的絕對尺度,因此可以將搜尋空間限制為僅檢測物理上有意義的特徵。

3D 特徵

[編輯 | 編輯原始碼]
  • 最大值、自旋影像
  • 使用 LKT 在深度影片中跟蹤特徵?

如何獲得精確的配準?

[編輯 | 編輯原始碼]
  • 深度感測器應經過校準。
  • 我們對 2D 特徵的位置和深度值的誤差進行建模。
  • 如果我們有一個已知的相機矩陣 K,最小化影像空間中的重新投影誤差可以提供一個準確的估計。
  • SIM(表面穿透度量)[Queirolo 2010]
  • RGB 值和深度資訊可以融合。

多感測器系統

[編輯 | 編輯原始碼]
  • 人臉檢測
  • 人臉識別(OpenNI2 中介軟體)[1]
  • 人臉建模(OpenNI2 應用程式)[2]
  • 面部特徵檢測:眼睛、鼻尖、嘴巴、耳朵
  • 3D 人臉姿態跟蹤
  • 微軟釋出的人臉跟蹤 SDK Kinect Windows[3]

等等。

[編輯 | 編輯原始碼]
[編輯 | 編輯原始碼]

網格表示

[編輯 | 編輯原始碼]
  • 從 2.5D
  • 從 3D

3D 物體識別

[編輯 | 編輯原始碼]

[物體識別 - M. Bennamoun 和 G.J. Mamic] 中的特徵匹配方法

1. 假設和檢驗

2. 匹配關係結構

3. 姿態聚類

4. 幾何雜湊

5. 解釋樹

6. 配準和距離變換

用於識別的索引

[編輯 | 編輯原始碼]
  • 幾何雜湊

引數模型擬合

[編輯 | 編輯原始碼]

線性代數

[編輯 | 編輯原始碼]

向量和矩陣操作、偽逆、秩、特徵值分解、奇異值分解、最小二乘法、齊次系統

最佳化

[編輯 | 編輯原始碼]

梯度下降法、牛頓法、列文伯格-馬夸特法 (http://www.ics.forth.gr/~lourakis/levmar/)、單純形法

機率與統計

[編輯 | 編輯原始碼]

協方差矩陣、貝葉斯機率

  • 卡爾曼濾波、擴充套件卡爾曼濾波
  • 粒子濾波

計算幾何

[編輯 | 編輯原始碼]

表面切線、法線、面積、三角形網格、沃羅諾伊圖、表面曲率、法線和主曲率

安裝:Primesense、Kinect 和華碩相機及庫

[編輯 | 編輯原始碼]
  • OpenNI 和 Prime Sensor

http://www.openni.org/Downloads/OpenNIModules.aspx,選擇與您的作業系統匹配的版本。

嘗試此操作:http://structure.io/openni

您需要

  1. OpenNI 二進位制檔案
  2. 適用於 Prime Sensor 模組的 OpenNI 相容硬體二進位制檔案穩定版本

下載並安裝二進位制檔案後,您現在可以使用 OpenNI 庫與 OpenCV 結合編寫精彩的程式碼。

  • 在您的工作環境(Visual Studio)中進行配置

在專案的“屬性”中,您需要新增

  1. DIRECTORY_OF_OPENNI\Include 到您的“附加包含目錄”
  2. DIRECTORY_OF_OPENNI\Lib 到您的“附加庫目錄”
  3. 在連結器部分,在輸入節點下,選擇附加依賴項並新增 OpenNI2.lib。(應該在 DIRECTORY_OF_OPENNI\Lib\OpenNI2.lib 中)
  4. 確保您將附加包含目錄和庫目錄新增到您的釋出和除錯配置中。根據您的 OpenNI2 版本選擇 win32 或 x64。
  5. 您的程式碼檔案應包含 OpenNI.h

供您參考,請檢視 http://www.openni.org/openni-programmers-guide/

簡單的 Openni

[edit | edit source]

https://code.google.com/p/simple-openni/wiki/Installation#Windows

如何從深度感測器讀取單個 3D 點?(OpenNI 2)

[edit | edit source]

成功安裝 OpenNI2 後,您應該能夠執行 DIRECTORY_OF_OPENNI\Samples/Bin 中的示例程式。

以下程式碼是獲取單個點的深度資訊的關鍵程式碼(對於初始化,您可以參考“SimpleViewer”示例程式碼)

openni::VideoFrameRef depthFrame;
const openni::DepthPixel* pDepth = (const openni::DepthPixel*) depthFrame.getData;
int width = depthFrame.getWidth();
int height = depthFrame.getHeight();
for (int i = 0; i < height; ++i)
    for (int j = 0; j < width; ++j, ++pDepth)
    if(i == height/2 && j == width/2 && *pDepth != 0 )//The if sentence depends on which point you want, this is the center point for example
    {} //assign the value to a 3D point structure

在 OpenCV 影像中顯示來自 OpenNI 輸入的深度圖 (C++) (OpenNI 1)

[edit | edit source]
/* Display depth map */
// Matthias Hernandez: 07/27/2011 - University of Southern California
// m31hernandez@gmail.com
// display the depthMap from openNI input in the openCV image ‘out’
void displayDepthMap(IplImage *out, const XnDepthPixel* pDepthMap, XnDepthPixel max_depth, XnDepthPixel min_depth) {
    uchar *data = (uchar *)out->imageData;
    int step = out->widthStep;
    int channels = out->nChannels;
    float normalize = (float)(max_depth-min_depth)/255.0f;

    int index=0;
    for (int i=0; i<MAX_I; i++) {
   	 if (pDepthMap[i] < min_depth || pDepthMap[i] > max_depth) {
   		 for (int k=0; k<channels; k++)
   			 data[index++] = 0;
   	 } else {
   		 if (normalize != 0) {
   			 for (int k=0; k<channels; k++)
   				 data[index++] = (int)(255-(float)(pDepthMap[i]-min_depth)/normalize);
   		 }
   		 else
   			 for (int k=0; k<channels; k++)
   				 data[index++] = 255;
   	 }    
    }
    
}

顯示來自 OpenNI 輸入的 RGB 影像 (C) (OpenNI 1)

[edit | edit source]
/* Display image map */
// Matthias Hernandez: 07/27/2011 - University of Southern California
// m31hernandez@gmail.com
// display the image map from openNI input in the openCV image ‘out’
void displayImageMap(IplImage *out, const XnUInt8* pImageMap) {
    uchar *data = (uchar *)out->imageData;
    int step = out->widthStep;
    int channels = out->nChannels;    

    for (int i=0; i<MAX3_HR; i+=3) {
   	 data[i+2]    = pImageMap[i];
   	 data[i+1]    = pImageMap[i+1];
   	 data[i]   	 = pImageMap[i+2];
    }
}

從投影到真實世界的轉換 (C) (OpenNI 2)

[edit | edit source]
#define XtoZ 1.114880018171494f
#define YtoZ 0.836160013628620f
#define MIN_DEPTH 450
#define MAX_DEPTH 800

void convertP2RW(float *pDepth, float *pReal, int x, int y, int w, int h) {
        int max_i = w * h;

	int i1 = (y * w + x),
		i2 = i1 + max_i,
		i3 = i2 + max_i;

	float Z = pDepth[i1];

    if (Z > MIN_DEPTH && Z < MAX_DEPTH){
        float X_rw = ( (float)x /(float)w -0.5f)*Z*XtoZ;
        float Y_rw = (0.5f-(float)y / (float)h)*Z*YtoZ;

		pReal[i1] = X_rw;
		pReal[i2] = Y_rw;
		pReal[i3] = Z;
	} else {
		pReal[i1] = 0.0f;
		pReal[i2] = 0.0f;
		pReal[i3] = 0.0f;
	}
}

// Of Course, the inverse function is 

void convertRW2P(float *pReal, float *pDepth,int x, int y, int w, int h) {
	 int max_i = w * h;

	int i1 = (y * w + x),
	i2 = i1 + max_i,
	i3 = i2 + max_i;

	float xR = pReal[i1];
	float yR = pReal[i2];
	float zR = pReal[i3];

	int ixi = (xR/zR/XtoZ + 0.5f)*(float)w + 0.5f;  // x
	int iyi = (-yR/zR/YtoZ + 0.5f)*(float)h + 0.5f; // y

	pDepth[i1] = zR;
}

校準的理念(使用絕對圓錐的影像)

[edit | edit source]
  x = P (H inv(H)) X
  H: a projective transformation

無窮遠平面和絕對圓錐

PAI:在 H 下固定

AC:在 H 下固定

ADQ:在 H 下固定(單個方程)

 Q = H Q H’
 PAI is the null-vector of ADQ (Q a = 0)

DIAC(絕對圓錐的雙重影像)= ADQ 的影像(參見 IAC(絕對圓錐的影像))

W* = K K'(K:校準矩陣)透過 Cholesky 因式分解。

如何從深度相機讀取紅外流

[edit | edit source]

http://stomatobot.com/primesense-3dsensor-ir-stream/?goback=.gde_2642596_member_242724626

參考資料

[edit | edit source]

深度感測器

[edit | edit source]

PrimeSense www.primesense.com

Kinect - Xbox.com www.xbox.com/KINECT

Xtion PRO LIVE http://www.asus.com/Multimedia/Motion_Sensor/Xtion_PRO_LIVE/

softkinetic http://www.softkinetic.com/

velodynelidar.com http://velodynelidar.com/lidar/lidar.aspx

Leap 簡介 http://www.youtube.com/watch?v=_d6KuiuteIA

Mesa Imaging http://mesa-imaging.ch/

工具

[edit | edit source]

http://www.danielgm.net/cc/ CloudCompare - 3D 點雲和網格處理軟體

http://www.cs.unc.edu/~isenburg/lastools/ LAStools:用於快速轉換、過濾、檢視、網格化和壓縮 LiDAR 的屢獲殊榮的軟體

問答

[edit | edit source]
  • {在此處提出您的問題...}
華夏公益教科書