生活随笔
收集整理的這篇文章主要介紹了
深度图的实时平滑
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
from: http://blog.csdn.net/jiaojialulu/article/details/53192887?locationNum=12&fps=1
深度圖的實時平滑
一、背景
英文原文,使用的是第一代kinect
youtube上的演示效果
二、深度數據存在的問題
下圖是我簡單處理后的深度圖:
藍色表示采到深度值為0的點,而其他點用顏色來標識,顏色越深表示離相機越近。數據中的噪聲表現為藍色斑點在畫面上不斷出現和消失。一些噪點是由于紅外在遇到物體表面時發生散射造成的,另一些是由于離得kinect較近的物體的遮擋。
另一個限制深度數據的地方在于kinect的工作范圍(0.8m-4m)。在這個范圍之外的物體就會表現為無數據,即深度值為0。
三、解決辦法
作者提出了像素濾波器和加權移動平均兩種方法,并且能在實時的要求下達到深度圖平滑的效果。
3.1 像素濾波器
3.1.1 原理及步驟
第一步是將深度數據幀轉換為我們方便處理的形式,比如UINT16[]。
UINT16 *depthData =
new UINT16[
424 *
512];
m_pDepthFrame->CopyFrameDataToArray(nDepthBufferSize,
reinterpret_cast<UINT16*>(depthData));
下面就是對一幀上的每個像素搜索,找到深度值為0的位置,我們希望除去這樣的像素,但是又不會影響精度和數據的其他特性。那么應該如何去做呢?
我們先把深度值為0的像素定為候選濾波對象,然后看看它究竟是否符合我們濾去它的標準。我們利用它周圍的一些像素對應的深度值來定義這個標準。我們以候選濾波像素為中心定義一個一個兩“層”的濾波器,同時用它來尋找這個濾波器框內其他深度值非零的像素。濾波器將這些深度值做一個分布,并關注每層框內這種像素的數量。然后將每層內非零像素個數與一個閾值比較,進而決定這個候選像素是否應該被濾波。如果任意層內非零像素的數目超過了閾值,就要將所有非零像素深度值對應的統計眾數(數目最多一個深度值)應用到候選濾波像素上,使其深度值不為0。濾波器如下圖所示:
下圖主要表明了采用眾數,即濾波器框內頻數最高的一個深度值來作為候選像素的深度值,要比直接采用框內所有深度值的平均要更加符合實際(我覺得如果改成內層的眾數更好)。
原文使用的是C#,我這里改為C++:
unsigned
short* smoothDepthArray = (unsigned
short*)i_result.data;
int widthBound =
512 -
1;
int heightBound =
424 -
1;
int innerBandThreshold =
3;
int outerBandThreshold =
7;
for (
int depthArrayRowIndex =
0; depthArrayRowIndex<
424;depthArrayRowIndex++){
for (
int depthArrayColumnIndex =
0; depthArrayColumnIndex <
512; depthArrayColumnIndex++){
int depthIndex = depthArrayColumnIndex + (depthArrayRowIndex *
512);
if (depthArray[depthIndex] ==
0){
int x = depthIndex %
512;
int y = (depthIndex - x) /
512;unsigned
short filterCollection[
24][
2] = {
0};
int innerBandCount =
0;
int outerBandCount =
0;
for (
int yi = -
2; yi <
3; yi++){
for (
int xi = -
2; xi <
3; xi++){
if (xi !=
0 || yi !=
0){
int xSearch = x + xi;
int ySearch = y + yi;
if (xSearch >=
0 && xSearch <= widthBound &&ySearch >=
0 && ySearch <= heightBound){
int index = xSearch + (ySearch *
512);
if (depthArray[
index] !=
0){
for (
int i =
0; i <
24; i++){
if (filterCollection[i][
0] == depthArray[
index]){filterCollection[i][
1]++;
break;}
else if (filterCollection[i][
0] ==
0){filterCollection[i][
0] = depthArray[
index];filterCollection[i][
1]++;
break;}}
if (yi !=
2 && yi != -
2 && xi !=
2 && xi != -
2)innerBandCount++;
elseouterBandCount++;}}}}}
if (innerBandCount >= innerBandThreshold || outerBandCount >= outerBandThreshold){
short frequency =
0;
short depth =
0;
for (
int i =
0; i <
24; i++){
if (filterCollection[i][
0] ==
0)
break;
if (filterCollection[i][
1] > frequency){depth = filterCollection[i][
0];frequency = filterCollection[i][
1];}}smoothDepthArray[depthIndex] = depth;}
else{smoothDepthArray[depthIndex] =
0;}}
else{smoothDepthArray[depthIndex] = depthArray[depthIndex];}}}
3.1.2 濾波效果
我這里再次把原圖貼上,左圖是濾波后的效果圖:可以看到物體邊緣散亂的深度值為0的點已經減少了不少。
3.1.3 代碼
因為只是為了理論上了解像素濾波器平滑的機制,因此我選擇靜態的讀取kinect采集的原始圖片,然后進行平滑。
代碼下載鏈接
請自行配制環境–kinect 2.0SDK和OpenCV。
下一節將繼續講解平滑中的加權移動機制
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的深度图的实时平滑的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。