日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深度图的实时平滑

發布時間:2025/7/25 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度图的实时平滑 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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));
  • 1
  • 2

下面就是對一幀上的每個像素搜索,找到深度值為0的位置,我們希望除去這樣的像素,但是又不會影響精度和數據的其他特性。那么應該如何去做呢?
我們先把深度值為0的像素定為候選濾波對象,然后看看它究竟是否符合我們濾去它的標準。我們利用它周圍的一些像素對應的深度值來定義這個標準。我們以候選濾波像素為中心定義一個一個兩“層”的濾波器,同時用它來尋找這個濾波器框內其他深度值非零的像素。濾波器將這些深度值做一個分布,并關注每層框內這種像素的數量。然后將每層內非零像素個數與一個閾值比較,進而決定這個候選像素是否應該被濾波。如果任意層內非零像素的數目超過了閾值,就要將所有非零像素深度值對應的統計眾數(數目最多一個深度值)應用到候選濾波像素上,使其深度值不為0。濾波器如下圖所示:

下圖主要表明了采用眾數,即濾波器框內頻數最高的一個深度值來作為候選像素的深度值,要比直接采用框內所有深度值的平均要更加符合實際(我覺得如果改成內層的眾數更好)。

原文使用的是C#,我這里改為C++:

// 濾波后深度圖的緩存unsigned short* smoothDepthArray = (unsigned short*)i_result.data;// 我們用這兩個值來確定索引在正確的范圍內int widthBound = 512 - 1;int heightBound = 424 - 1;// 內(8個像素)外(16個像素)層閾值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);// 我們認為深度值為0的像素即為候選像素if (depthArray[depthIndex] == 0){// 通過像素索引,我們可以計算得到像素的橫縱坐標int x = depthIndex % 512;int y = (depthIndex - x) / 512;// filter collection 用來計算濾波器內每個深度值對應的頻度,在后面// 我們將通過這個數值來確定給候選像素一個什么深度值。unsigned short filterCollection[24][2] = {0};// 內外層框內非零像素數量計數器,在后面用來確定候選像素是否濾波int innerBandCount = 0;int outerBandCount = 0;// 下面的循環將會對以候選像素為中心的5 X 5的像素陣列進行遍歷。這里定義了兩個邊界。如果在// 這個陣列內的像素為非零,那么我們將記錄這個深度值,并將其所在邊界的計數器加一,如果計數器// 高過設定的閾值,那么我們將取濾波器內統計的深度值的眾數(頻度最高的那個深度值)應用于候選// 像素上for (int yi = -2; yi < 3; yi++){for (int xi = -2; xi < 3; xi++){// yi和xi為操作像素相對于候選像素的平移量// 我們不要xi = 0&&yi = 0的情況,因為此時操作的就是候選像素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]){// 如果在 filter collection中已經記錄過了這個深度// 將這個深度對應的頻度加一filterCollection[i][1]++;break;}else if (filterCollection[i][0] == 0){// 如果filter collection中沒有記錄這個深度// 那么記錄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位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的深度图的实时平滑的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。