最近在做機器視覺方面的一點工作,用Kinect作sensor獲取深度數據、顏色、手勢識別等。非常感激CNBlog上的兩篇博文:(1)獨釣寒江的http://www.cnblogs.com/yangecnu/archive/2012/03/30/KinectSDK_Geting_Started.html 從中學到了不少關於在WPF平台上使用C#,利用微軟Kinect SDK開發自己的應用程序的知識,給了我很大的幫助,在此表示感謝!
但是博主獨釣寒江的博文中,針對深度圖像濾波,只簡要說了取反和用Bgr32表示深度圖像,效果不是很理想。
后來,發現了另一篇博文(2)何文西的http://www.cnblogs.com/TravelingLight/archive/2012/05/25/2517680.html介紹了國外的一篇文章,上面介紹了外國作者自己開發的兩種濾波方法:像素濾波法,加權移動平均法。效果很好!可惜只有代碼片段無法試驗,而且濾波算法不是特別容易理解。實在可惜!
前幾天偶然跟蹤並找到了作者的源代碼http://kinectdepthsmoothing.codeplex.com/,下載來看。運行發現,程序要求:VS2012以上、Kinect SDK 1.7以上版本,而根據獨釣寒江的博文指導,其中的代碼用的是SDK 1.0,進一步發現其中的一些API函數,數據類型都不相同,再者,Kinectdepthsmoothing中xaml代碼用的是后台創建,而獨釣寒江的博文中xaml用的是布局式,而我對xaml又不懂,如何把這兩個程序結合起來呢?
由於獨釣寒江的博文給出的程序中,有大量的功能實現,比如保存圖像、鼠標單擊顯示像素深度值、彩色渲染、人體尺寸獲取,游戲者索引等等,而外國朋友的kinectdepthsmoothing程序只有濾波和保存圖像,那么考慮把濾波模塊移植到獨釣寒江的程序中,並且不改變原來的布局式界面。在移植的過程中,主要解決了以下幾個類型不兼容的問題:
a) 將short[] pixelData類型改成DepthImagePixel[] pixelData,這里注意:SDK 1.8版本中,private DepthImagePixel[] depthPixels;其中獲取深度數據為
1 short depth=depthPixels[i].Depth;
而SKD 1.0版本中,short[] pixelData獲取深度數據的方式為
1 Int32 depth = this.depthPixels[pIndex] >> DepthImageFrame.PlayerIndexBitmaskWidth;
需要進行移位操作。而且兩種方式的depth類型不一樣,一個是short16位,一個是Int32位。
b) 用三通道Bgr32格式的colorBitmap存儲深度圖像,而不是Gray16格式的depthBitmap。除了深度數組的格式不一樣之外,外國朋友的程序中,有這樣幾行代碼值得關注,
1 //獲得當前幀最大和最小可用的深度值 2 short minDepth = (short)lastDepthFrame.MinDepth; 3 short maxDepth = (short)lastDepthFrame.MaxDepth;
以及
1 //在這里將depthPixels數組中的深度值,逐元素,轉換並存儲到colorPixles中 2 3 //最后,將colorPixels寫入colorBitmap中 4 5 int colorPixelIndex = 0; 6 7 for (int i = 0; i < depthPixels.Length; i++) 8 9 { 10 11 //獲取該元素(點)的深度值 12 13 short depth = depthPixels[i].Depth; 14 15 byte intensity = (byte)255; 16 17 int newMax = depth - minDepth; 18 19 if (newMax > 0) 20 21 {intensity = (byte)(255 - (255 * newMax / (3150))); } 22 23 this.colorPixels[colorPixelIndex++] = intensity;//blue 24 25 this.colorPixels[colorPixelIndex++] = intensity;//green 26 27 this.colorPixels[colorPixelIndex++] = intensity;//red 28 29 ++colorPixelIndex; 30 }
最后將數據寫入colorBitmap時,代碼為
this.colorBitmap.WritePixels( new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight), this.colorPixels, this.colorBitmap.PixelWidth * sizeof(int), 0);
使用了 this.colorBitmap.PixelWidth這個寫法,而不是獨釣寒江博主的程序中,使用depthStream.FrameHeight創建圖像的矩形區域this.depthRect = new Int32Rect(0, 0, depthStream.FrameWidth, depthStream.FrameHeight);
c) 此外,初始化變量(數據容器depthPixels和colorPixels)時,要注意colorPixels的大小
1 this.depthPixels = new DepthImagePixel[depthStream.FramePixelDataLength]; 2 this.colorPixels = new byte[depthStream.FramePixelDataLength * sizeof(int)];
總之,將兩個程序結合起來,要注意兩個方面,一是界面的形式,布局還是后台創建,二是,.cs程序中由於使用的SDK版本不同,有很多API和數據類型不一致的地方,需要修改。由於正在做后續的實驗,比如加入了自己的利用深度數據進行邊緣檢測的代碼,還有很多想法沒有實現,暫時寫到這里吧。到時候會將完整代碼上傳到網絡上,供大家參考!謝謝。
下篇文章將介紹基於深度值的目標分割,並附上完整代碼。