透過 OpenNI 建立 Kinect 3D Point Cloud

| | 92 Comments| 15:40
Categories:

這篇還是算延續前一篇的《透過 OpneNI 合併 Kinect 深度以及彩色影像資料》。在可以透過 OpenNI 讀取到 Kinect 的深度、色彩資訊之後,其實就可以試著用這些資訊,來重建 3D 的環境做顯示了∼不過實際上,在前面的範例中所讀到的深度資訊,都算是原始資料,而且座標軸也都是感應器二維影像的座標系統,如果要重建 3D 場景的話,這些資訊都還是需要換算的;所幸,OpenNI 在 Depth Generator 已經有提供 ConvertProjectiveToRealWorld()ConvertRealWorldToProjective() 這兩個函式,可以幫助程式開發者快速地進行座標轉換了!

而如果把直接把這些 3D 的點位附加顏色、用 OpenGL 畫出來呢,就大概會是下面影片的樣子吧∼

當然,point cloud 不見得是最好的顯示方式,有需要的話也可以重建出多邊形再畫,不過多邊形的重建已經算是另一個主題了,所以 Heresy 也不打算在這邊討論;另外,Heresy 在這篇也不會提及 OpenGL 顯示的部分,只會提供簡單的範例,示範如何建立出這些 point cloud 而已。

而為了儲存這些點的位置以及顏色資訊,這邊先定義了一個簡單的結構、SColorPoint3D

struct SColorPoint3D
{
  float  X;
  float  Y;
  float  Z;
  float  R;
  float  G;
  float  B;
 
  SColorPoint3D( XnPoint3D pos, XnRGB24Pixel color )
  {
    X = pos.X;
    Y = pos.Y;
    Z = pos.Z;
    R = (float)color.nRed / 255;
    G = (float)color.nGreen / 255;
    B = (float)color.nBlue / 255;
  }
};

這個結構只是單純的六個福點數,分別記錄這個點的位置、以及顏色;而建構子的部分,則是傳入 OpenNI 定義的結構的變數:代表位置的 XnPoint3D  以及代表 RGB 顏色的 XnRGB24Pixel

而為了方便起見,Heresy 把座標轉換的部分寫成一個函式 GeneratePointCloud(),其內容如下:

void GeneratePointCloud( xn::DepthGenerator& rDepthGen,
                         const XnDepthPixel* pDepth,
                         const XnRGB24Pixel* pImage,
                         vector<SColorPoint3D>& vPointCloud )
{
  // 1. number of point is the number of 2D image pixel
  xn::DepthMetaData mDepthMD;
  rDepthGen.GetMetaData( mDepthMD );
  unsigned int uPointNum = mDepthMD.FullXRes() * mDepthMD.FullYRes();
 
  // 2. build the data structure for convert
  XnPoint3D* pDepthPointSet = new XnPoint3D[ uPointNum ];
  unsigned int i, j, idxShift, idx;
  for( j = 0; j < mDepthMD.FullYRes();   j )
  {
    idxShift = j * mDepthMD.FullXRes();
    for( i = 0; i < mDepthMD.FullXRes();   i )
    {
      idx = idxShift   i;
      pDepthPointSet[idx].X = i;
      pDepthPointSet[idx].Y = j;
      pDepthPointSet[idx].Z = pDepth[idx];
    }
  }
 
  // 3. un-project points to real world
  XnPoint3D* p3DPointSet = new XnPoint3D[ uPointNum ];
  rDepthGen.ConvertProjectiveToRealWorld( uPointNum, pDepthPointSet, p3DPointSet );
  delete[] pDepthPointSet;
 
  // 4. build point cloud
  for( i = 0; i < uPointNum;    i )
  {
    // skip the depth 0 points
    if( p3DPointSet[i].Z == 0 )
      continue;
 
    vPointCloud.push_back( SColorPoint3D( p3DPointSet[i], pImage[i] ) );
  }
  delete[] p3DPointSet;
}

這個函示要把 xn::DepthGenerator 以及讀到的深度影像和彩色影像傳進來,用來當作資料來源;同時也傳入一個 vector<SColorPoint3D>,作為儲存轉換完成後的 3D 點位資料。

其中,深度影像的格式還是一樣用 XnDepthPixel 的 const 指標,不過在彩色影像的部分,Heresy 則是改用把 RGB 封包好的 XnRGB24Pixel,這樣可以減少一些索引值的計算;而因為這樣修改,之前讀取彩色影像的程式也要由

const XnUInt8* pImageMap = mImageGenerator.GetImageMap();

修改為

const XnRGB24Pixel* pImageMap = mImageGenerator.GetRGB24ImageMap();

而在函式內容的部分,第一段的部分主要是透過取得 depth generator 的 meta-data:xn::DepthMetaData 來做簡單的大小、索引計算;如果不想這樣用的話,其實也是可以直接用 640 x 480 這樣固定的值來做計算,不過就是要和之前在 SetMapOutputMode() 所設定的解析度一致就是了。

第二部分「build the data structure for convert」,則是將深度影像的 640 x 480 個點,都轉換為 XnPoint3D 形式的一為陣列,已準備進行之後的座標轉換。

第三部分「un-project points to real world」則就是實際進行轉換的部分了。這邊要把座標由影像的座標系統轉換到 3D 座標系統,主要是用 Depth Generator 的 ConvertProjectiveToRealWorld() 這個函式;而它的使用方法也很簡單,只要告訴他要轉換的點的數量(uPointNum)、把要轉換的點用陣列的形式傳(const XnPoint3D*)進去,並給他一塊已經 allocate 好的 XnPoint3D 陣列(p3DPointSet),就可以自動進行轉換了∼

第四部份 Heresy 則是再用一個迴圈去掃過全部的點,並把深度為 0 的點給去掉(因為這些點是代表是 Kinect 沒有辦法判定深度的部分)、並和顏色的資訊一起轉換為 SColorPoint3D 的形式,丟到 vPointCloud 裡儲存下來了。
(這個動作其實也可以在第二步的時候先做掉,但是在那邊做顏色的部分會比較麻煩就是了。)

而回到主程式的部分,本來讀取資料的程式是:

// 8. read data
eResult = mContext.WaitNoneUpdateAll();
if( eResult == XN_STATUS_OK )
{
  // 9a. get the depth map
  const XnDepthPixel*  pDepthMap = mDepthGenerator.GetDepthMap();
  // 9b. get the image map
  const XnUInt8*    pImageMap = mImageGenerator.GetImageMap();
}

前面也提過了,Heresy 這邊不打算提及用 OpenGL 顯示的部分,所以這邊為了不停地更新資料,所以改用一個無窮迴圈的形式來不停地更新資料、並進行座標轉換;而轉換後的結果,也很簡單地只輸出它的點的數目了。

// 8. read data
vector<SColorPoint3D> vPointCloud;
while( true )
{
  eResult = mContext.WaitNoneUpdateAll();
  // 9a. get the depth map
  const XnDepthPixel*  pDepthMap = mDepthGenerator.GetDepthMap();
 
  // 9b. get the image map
  const XnRGB24Pixel*  pImageMap = mImageGenerator.GetRGB24ImageMap();
 
  // 10 generate point cloud
  vPointCloud.clear();
  GeneratePointCloud( mDepthGenerator, pDepthMap, pImageMap, vPointCloud );
  cout << "Point number: " << vPointCloud.size() << endl;
}

如果是要用 OpenGL 畫出來的話,基本上就是不要使用無窮迴圈,而是在每次要畫之前,再去讀取 Kinect 的資料、並透過 GeneratePointCloud() 做轉換了∼而如果不打算重建多邊形、而是像 Heresy 直接一點一點畫出來的話,結果大概就會像上面的影片一樣了∼

92 thoughts on “透過 OpenNI 建立 Kinect 3D Point Cloud”

  1. [url=網址]http://ulpgdq.blu.livefilestore.com/y1pJhFP7vKp7QDGD5diJLhc0Pl4u1MiN6HGm75ueugxfln0YMifjraQCCKNT1Q6rCV3ldwDldljRt-Iu0MVZhHLGL6N48Y9j8x7/新文字文件 (2).txt?psid=1[/url]打不出文字來麻煩大大刪除一下上兩個發文:per:

  2. to Chen,Yuan您好,您應該是使用 Windows Live Sky Drive 的空間吧?微軟的這個空間檔案是不能直連的,他的直連網址只要過一段時間就會改變,而無法連結,所以您所提供的網址已經無法存取了。不過之前有看到您所提供的內容,基本上您的寫法應該是類似「cout << pDepthMap;」,這是直接把 pDepthMap 這個指標所指的位址輸出,基本上是用來看記憶體空間所在的位址用的。但是實際上 depth map 是一個大小是 640 x 480 的一維陣列,要取存取他的資料,一般是要用迴圈去讀裡面的每一項資料的。例如本文中 GeneratePointCloud() 裡的「2. build the data structure for convert」就是在做這件事。

  3. heresy 大大不好意思弄亂了您的Blog小弟先在此跟您道歉 (鞠躬小弟後來用 pDepthMap[] 來顯示一維陣列可是其中有點小小問題抱歉又來麻煩您heresy 大大說他是一個640*480的一維陣列所以小弟用640*480=307200出現的數字 會跟著人移近跟移遠有所變動所以從此處可以大致上認定她就是data可是當小弟印pDepthMap[307210] 卻還是有數字出現而小弟另一個疑問是 關於印出的四位數字不是三原色色碼 也對這些數字沒有頭緒是因為經過middleware轉換所以變成這樣嗎:per:有勞大大了最後 再次向您道歉及道謝 (鞠躬

  4. to Chen,Yuan您的第一個問題,關於超出陣列大小的地方依舊可以印出值,這個算是 C 本身的設計。你可以試試看,自己宣告一個大小為十陣列,然後再去讀取他的第十一項,一樣是可以讀到值的;但是實際上,這個時候你是去讀取到其他的記憶體空間裡面的值,基本上是一種不合法的存取,取到的值也沒有任何意義。而至於在合法範圍內取得的值,他是深度資訊,所以並不是三原色;他基本上就是型別為 unsigned short 的整數,用來代表它的深度。

  5. 感謝heresy 大大 大公無私且很有耐心地回答小弟在此深深向您道謝:D

  6. 尊敬的heresy大大,小弟有些問題想向您請教一下,麻煩了。1 vPointCloud裏面的數據是否可以輸出到文件?如何實現呢。2 用OpenGL畫是不是調用vPointCloud就可以了?萬分感謝!向大大鞠躬。

  7. to trust 1. 基本上,vPointCloud 就只是一個 SColorPoint3D 所構成的 vector 而已,要怎麼輸出到檔案,是看你要怎麼定義檔案格式來決定。2. 是的,最簡單的 Point Cloud 所需的資料(位置、顏色)都儲存在裡面了,如果是單純要用點的方法畫出來的話,這樣就夠了。

  8. heresy大大你好~請問要怎麼重建Mesh在去貼texture呢?麻煩大大幫我解惑了,謝謝。

  9. to yaoba您好。要重建 Mesh 也是由那些深度資料下手。基本上,讀出來的 Depth map 本身就是一個可以代表 mesh 的圖了;要重建出完整的 mesh,最簡單的做法就是把這個 regular grid 建立成 graphics 所需的大量三角形,如此就可以了。但是實作上要做得比較好,則還要考慮到兩個相鄰點距離太遠的話要斷開、幾何簡化方面的問題。

  10. 大人所有比克都写得简单易懂,思考问题很详细,佩服啊:o

  11. heresy 你好我按照您的方法實現了3D點云的建立,可是有一個問題,就是顯示出來的點云與深度影像是鏡像的關係,這是什?原因呢?怎樣可以使點云與深度影像顯示一致,謝謝

  12. 嘿嘿,我知道哪的問題了pDepthPointSet[idx].X = i; pDepthPointSet[idx].Y = j;將i,j互換就ok了

  13. heresy你好,请问vPointCloud的数据可以用MATLAB来作图显示么,应该用什么格式来存取?

  14. to euphy

    這個應該是看你用 Matlab 的時候打算怎麼讀取?

    比較直覺的方法,應該就是自己定義一個純文字檔的格式、然後自己來控制 C 的寫入和 Matlab 的讀取了。

  15. heresy你好,文章中的视频我通过网页看不到,可否发一个视频的链接,谢谢了

  16. ConvertProjectiveToRealWorld
    在此之前画点云, 是正常画面
    用了之后,画面会上下颠倒。

  17. to euphy
    影片連結是:http://www.youtube.com/watch?v=moyDkVulRO0

    另外請問一下,看不到影片不知道是看不到 YouTube 的影片?還是瀏覽器不支援造成的?

  18. to gbadown
    不太確定你想描述的意思?
    不過,OpenNI 的真實世界座標系統和投影座標系統本來就是不一樣的。

  19. to heresy
    比如 投影坐标 设置 左上角为 原点

    for(i:0->h)
    for(j:0-w)
    drawpixel(j,i,depth)
    显示出的画面是从上到下。画面正常。
    ====================
    世界坐标 的原点在 中心
    for(i:0->h)
    for(j:0-w)
    { 3D.x=j; 3D.y=i; 3D.z=depth;}
    ConvertProjectiveToRealWorld(w*h,&3D,&3D);
    for(i:0->h)
    for(j:0-w)
    drawpixel(3D.x,3D.y,3D.z)
    显示出的画面是从下到上。 画面垂直颠倒。

  20. to gbadown

    這個就是座標系統的定義不一樣啊
    在一般 3D Graphics 的座標系統和 Image 的座標系統,本來就是不同的。

  21. to heresy
    是不支持youtube的问题,您发给我的链接也是看不了的,貌似大陆这边的校园网是连不上的…

  22. 您好 heresy,我把vPointCloud的x,y,z数据存入三个txt文件中后,发现z的所有值都是0,不知是为什么?

  23. to euphy
    建議你先確認一下官方的範例顯示出來的畫面是否正常?
    另外,有把所有的點輸出嗎?還是只輸出第一個點?

  24. 您好,heresy
    OpenNI的sample里的可以正常显示的,我是把所有像素点输出

  25. heresy大大你好,我也是输出到文件的时候出现问题,得到的RGB值会出现负数的情况。

  26. to Auu
    麻煩請確定你的輸出方法看看
    SColorPoint3D 裡的色彩是使用 float 來儲存的,值理論上都會在 0 – 1 之間,不太可能會有負數。

  27. heresy,你好,
    我是一名kinect初学者,看了你的博文受益匪浅。有几个问题想请教一下你。1: 真实坐标系的原点在哪里呢? 中心吗? 2: 我在做kinect视觉导航,在取得深度信息后,我似乎不知道该怎么做了。单个像素的深度信息没什么意义。 你有什么建议吗?

  28. to xx255

    1. 真實世界座標系統的原點是裝置(Kinect / Xtion Pro)的中心。
    2. 這取決於你要怎麼控制,一般來說把找到的關節點拿來用會比較好控制。

  29. 谢谢了 ! 我还想问下怎么抓取kinect的一帧图像呢? 好像用opencv的CvCapture *capture=0;capture = cvCreateCameraCapture(0);cvQueryFrame(capture)读不出来。

  30. to xx255
    抱歉,Heresy 沒有在使用 OpenCV,所以不應處 OpenCV 要如何讀取他的資料。
    不過,這篇的範例就是會把 OpenNI 的深度、彩色資料都讀取出來,應該就已經算是把當下的 frame 抓下來了,只是看你之後要把這些資料做什麼處理而已。

  31. 你好,我是一个学生,比较菜鸟,希望给予一点指引。我想利用Kinect自带的骨骼Sample——NUIskeleton,获取里面的数据,保存,再导入3Dmax中驱动人物动起来,要求不高的,只是练习。不知道是否要利用open NI来获取数据,还是怎么办?我真的好迷茫……..期待您的答复~~~~

  32. heresy,你好,我是一位kinect 初学者!因为研究需要,我想知道经过ConvertProjectiveToRealWorld转换之后的点的坐标是怎样的?也就是说所谓的“RealWorld”坐标系到底是怎样的一个坐标系?希望你不吝赐教!

  33. to 小书童
    OpenNI 的 真實世界座標系統基本上是以感應器為原點的 3D 座標系統。

  34. 还有一个问题!“RealWorld”坐标是左手3D坐标,那kinect所获取的关节的坐标也是在这个坐标系下吗?
    谢谢!

  35. to 小书童

    OpenNI 裡面基本上就只有投影座標系統和真實世界座標系統兩種。
    除了 Map Generator 的原始影像資料外,基本上都是真實世界座標系統。

  36. 你好,我想请教下你。 深度信息为0的点去掉以后,那么3D点云中的顺序是怎么样的呢? 怎么和像素坐标对应呢?

  37. 因为我不去掉深度为0的点 转换后深度为0的点对应X,Y,Z全都是0.

  38. to xx / xx255

    不太確定你的問題所在?在這邊的範例,Heresy 就已經把深度為 0 的點去掉了,並沒有問題。
    而實際上,透過 ConvertProjectiveToRealWorld() 進行座標系統轉換時,並沒有順序上的要求;只是在顯示的時候,自己要注意點的 3D 位置和色彩的對應關係而已。

  39. 你好,可能是我表达的不清楚。 其实我就是想问下不去掉深度为0的点进行转换坐标后,像素坐标为i,j对应在点云的位置是 i*width j吧。 如果去掉深度为0的点得话,那么最后的到的点云中的位置可能就不是i*width j了。(因为可能之前有深度为0的点导致不存储)

  40. to xx255
    不太確定你的程式到底是怎麼寫?
    基本上,你所計算的「i*width j」只是在投影座標系統裡,(j,i) 這個點在資料的一維陣列中的位置而已。
    在做座標系統轉換的時候,基本上這個資訊的有無並不會任何影像。在之後的處理時,這個資訊也沒有任何影響。

    而你如果是要考慮到和彩色影像作對應的話,在這個例子裡,Heresy 的做法就是在去掉深度為 0 的點的時候,順便就先把對應的色彩值取出來了,所以並沒有什麼問題。

  41. heresy你好!
    请问通过ConvertProjectiveToRealWorld函式获得的p3DPointSet.X,p3DPointSet.Y,p3DPointSet.Z,格式是怎样的?是int类型还是float或者其他类型?单位是毫米还是米?
    另外,如果我想直接通过printf打印到txt文件中应该如何处理?

    谢谢!!

  42. to guang

    單位都是公厘。
    XnPoint3D 的 X / Y / Z 的資料型別則都是 XnFloat,也就是 float。
    建議可以參考官方文件

  43. heresy你好!
    想要請教一下,我我為一個物體,比如一個椅子或者一個人,透過 OpenNI 建立了3D Point Cloud,發現Point Cloud的数据與椅子或人的實際尺寸有誤差,比方說椅子的實際高度是1000公厘,透過ConvertProjectiveToRealWorld函式得到的數據只有960公厘,請問是什麽原因造成的?
    謝謝解答!

  44. 我按照您给的方法进行三维坐标的计算,但是用ConvertProjectiveToRealWorld算出的结果是所有点都只有x坐标,y和z坐标全为0,这是怎么回事啊?

  45. 不好意思,是我的一个地方弄错了,现在改过来了,不过重建的效果不怎么样,请问大大有什么好的三维冲就爱你算法没,求推荐。。。

  46. heresy你好!
    我是一名学生同时也是一个kinect菜鸟,我参考你的这篇文章和用户手册得到的点云集,并将之转化到realworld中,同时将点云集和转化到realworld中的数据写入txt中,并将深度图保存。用matlab显示realworld的图像和深度图完全不一样(不会opengl),maltab显示的图像完全不知道里面的内容是什么

  47. to lijingcsu
    這應該是要確認你寫出、使用 matlab 讀取時有沒有弄錯東西了。

  48. 你好,请问一下我通过convert到realword之后得到的点云数据,用meshlab可视化之后,是一条直线,还有坐标存在负值,请问是什么问题,

  49. to htlvcc
    不確定你是怎麼把資料給 meshlab 的,不過:
    1. OpenNI 的真實世界座標系統在 x, y 方向本來就是會有負的
    2. 是否有先確認過讀取到的資料是正確的?

  50. heresy大大,您好,请教一下如何通过openni获取一个已知点的深度值,拜谢了~

  51. 哈哈,非常感谢啊,后来用opencv中的at方法解决了,但是也尝试了heresy大大介绍的operator方法,最后两者得出的结果一样,感谢了,现在打算研究openni2,不知道openni2增加了哪些功能

  52. to long

    OpenNI 2 基本上是架構上的改變,開發的方式有點變化。

  53. heresy大大,现在诺基亚被微软收购了,表示QT的前途堪忧啊,不知道还有没有学QT的必要,虽然QT开发界面之类的还是很优雅,很方便的

  54. 现在就是不知道还有没其他做界面比较容易的工具,但是前景还很好的

  55. heresy,请教个问题。想把kinect应用到移动机器人的地图三维地图构建上。假设最初始位置(旋转角度为0,x,y,z的移动为0)为参与坐标系,似设kinect经过旋转角度a和移动(x1,y1, z1),怎么把获得的世界坐标映射回参与坐标系

  56. to water
    在已知位移和旋轉的情況下,應該可以簡單地算出 transformation matrix、並以此做相關的轉換計算。

  57. 很感谢及时回复。我使用了《学习opencv》p379中列出的如下矩阵:
    [cosa 0 -sina]
    [0 1 0 ]
    [sina 0 cosa]
    ,不过实际验证不对,尝试自己推导了下变换矩阵,没有推导对,不知道有没建议?

  58. to water

    你套的矩陣並不完整,很明顯沒有把位移考慮進去。
    另外,位移的計算和旋轉是有先後的順序的(旋轉中心),這點也是要考慮的。

  59. 我使用了pcl的getTransformation,算出来的结果大致是对的,不过有些偏差。我是通过手动旋转整个kinect来测试。不知道是因为kinect的内部的旋转问题,还是什么问题,会导致这个偏差,附上getTransformation的实现:
    template void
    pcl::getTransformation (Scalar x, Scalar y, Scalar z,
    Scalar roll, Scalar pitch, Scalar yaw,
    Eigen::Transform &t)
    {
    Scalar A = cos (yaw), B = sin (yaw), C = cos (pitch), D = sin (pitch),
    E = cos (roll), F = sin (roll), DE = D*E, DF = D*F;

    t (0, 0) = A*C; t (0, 1) = A*DF – B*E; t (0, 2) = B*F A*DE; t (0, 3) = x;
    t (1, 0) = B*C; t (1, 1) = A*E B*DF; t (1, 2) = B*DE – A*F; t (1, 3) = y;
    t (2, 0) = -D; t (2, 1) = C*F; t (2, 2) = C*E; t (2, 3) = z;
    t (3, 0) = 0; t (3, 1) = 0; t (3, 2) = 0; t (3, 3) = 1;
    }

    附上convertDepthToWorldCoordinates的实现:
    OniStatus VideoStream::convertDepthToWorldCoordinates(float depthX, float depthY, float depthZ, float* pWorldX, float* pWorldY, float* pWorldZ)
    {
    if (m_pSensorInfo->sensorType != ONI_SENSOR_DEPTH)
    {
    m_errorLogger.Append(“convertDepthToWorldCoordinates: Stream is not from DEPTH
    “);
    return ONI_STATUS_NOT_SUPPORTED;
    }

    float normalizedX = depthX / m_worldConvertCache.resolutionX – .5f;
    float normalizedY = .5f – depthY / m_worldConvertCache.resolutionY;

    *pWorldX = normalizedX * depthZ * m_worldConvertCache.xzFactor;
    *pWorldY = normalizedY * depthZ * m_worldConvertCache.yzFactor;
    *pWorldZ = depthZ;
    return ONI_STATUS_OK;
    }

    ===xzFactor和yzFactor的实现如下:
    float horizontalFov;
    float verticalFov;
    getProperty(ONI_STREAM_PROPERTY_HORIZONTAL_FOV, &horizontalFov, &size);
    getProperty(ONI_STREAM_PROPERTY_VERTICAL_FOV, &verticalFov, &size);

    m_worldConvertCache.xzFactor = tan(horizontalFov / 2) * 2;
    m_worldConvertCache.yzFactor = tan(verticalFov / 2) * 2;

  60. to water

    這部分基本上就是看誤差到什麼程度。
    Kinect 的 3D 掃描準確度本來就不是非常地精確,再加上你是手動旋轉,誤差應該是一定會有。
    如果希望效果好的話,可能要再加上對位的計算、校正。

  61. 在0度的时候我的一个参照点的距离是2201mm,逆时针转了15度后算出的距离是2021mm,相差180mm。转角度我是用量角器画出转角,然后定位的,所以转角的误差应该不会太大,因为深度误差太大,所以我在想有没可能有其他原因?另外你说的对位的计算、校正是指什么,能稍微详细一点吗,谢谢。

  62. 对位确实是个可选方案,不知道通过映射矩阵为什么会有这么大误差,所以我打算用对位来代替矩阵计算了,后面再找时间研究下这个矩阵映射的问题。

  63. to 依依
    抱歉,不知道你的「辨識過後」是什麼意思?

  64. 是指
    當我使用SDK中的 face tracking之後會有的一些臉部資訊
    我知道會得到2D座標,但我不知道該從何處取得座標
    能否有方法也取得3D座標呢?

  65. to 依依

    抱歉,你指的應該是 Kinect for Windows SDK 吧?
    Heresy 這邊主要是使用 OpenNI NiTE,兩者是不同的東西。
    不過基本上,K4W SDK 也有提供座標轉換的功能,可以把 2D 影像座標的點轉換到 3D 座標系統;這部分請參考 MSDN 的文件。

  66. heresy大大,好久不见,最近研究在ROS下RGBD摄像头的使用,觉得里面他们提供的用起来问题多多,于是想着自己来写一个类似的模块,使用Xtion pro live 测试的时候碰到几个问题,想向您请教一下:
    1。在写的SLAM中需要同时对摄像头获得的RGB,深度和点云同时进行处理,需要保证他们是同一个时间获取的,不知道您之前介绍的用OpenNI获取RGB和深度信息能不能保证这一点,如果不能该如何处理?
    2. 处理的点云一般是这样计算的:
    for v in range(rgb.size[1]):
    for u in range(rgb.size[0]):
    color = rgb.getpixel((u,v))
    Z = depth.getpixel((u,v)) / scalingFactor
    if Z==0: continue
    X = (u – centerX) * Z / focalLength
    Y = (v – centerY) * Z / focalLength
    points.append(“%f %f %f %d %d %d 0
    “%(X,Y,Z,color[0],color[1],color[2]))
    其中centerX,centerY,focalLength为摄像头标定参数,不知道这个和您之前介绍的建立3D点云ConvertProjectiveToRealWorld()有什么区别?

  67. 对了,还有一个问题,就是不知到heresy大大有没有标定过Xtion pro live,能否方便告知下参数,还有一般情况下深度摄像头需要标定吗?

  68. to chao

    1. OpenNI 1 有提供 Frame Sync 這個 Capability,或許可以試試看。
    2. ConvertProjectiveToRealWorld 是 OpenNI 提供的轉換函式,在 OpenNI 2 基本上是靠 FoV 來計算的。如果想知道它的實際算法,建議直接去看他的原始碼。
    3. 抱歉,Heresy 沒做過。

  69. 请问大神,Kinect 采取的数据格式咋么转换成pcl的点云数据处理???

  70. 楼主,你好,我在深度图像生成点云上遇到一点问题,希望能交换交流方式,昵称是我的邮箱。方便的话,希望能交流,谢谢。

  71. 问题如下,我现在在用kinect v2生成点云数据,现在的问题是openni的ConvertProjectiveToRealWorld()不能用了,于是我自己写了一段代码,基本思路是用MapDepthPointToColorSpace函数将深度值匹配到彩色图像的对应像素上,然后对求的的彩色图像的行和列,计算真实的X,Y,深度图像的距离作为Z。代码如下:
    PointCloud.clear();
    ColorSpacePoint ColorPoint;
    DepthSpacePoint DepthPoint;
    for (int i = 0; i < 424; i ) for (int j = 0; j < 512; j ) { DepthPoint.X = i; DepthPoint.Y = j; hr = m_CoordinateMapper->MapDepthPointToColorSpace(DepthPoint, pBuffer_depth[i * 512 j], &ColorPoint);
    if (SUCCEEDED(hr))
    {
    unsigned short dep = pBuffer_depth[i * 512 j] >> 3;
    tmp_point.z = dep;
    tmp_point.x = (ColorPoint.Y – 960)*xScale*dep;
    tmp_point.y = -(ColorPoint.X – 540)*yScale*dep;
    PointCloud.push_back(tmp_point);
    }

    }
    现在呢,我用这段代码采集一个走廊的数据,然后很明显的有一部分缺失点云。我现在不清楚是程序导致这样的结果还是kinect v2本身的原因?我想给你发一个点云的截图,但是这里不能发图片,才想和你交换练习方式的。

  72. 請問如果用laview 我只是要測最短距離 請問有辦法嗎:cry:

  73. to jack

    如果你是指 LabView,抱歉 Heresy 沒有在使用這個工具。

  74. 您好
    我看過您有關kinect、Xtion和openni 的文章後,想請問您一個問題,懇請您能否給我的方向
    我是大三生,我和其他四個朋友想做一個專題,我們想做一台可以自動3D導航及3D mapiing(結合深度及影像)的四軸

    我們現在有一台飛控是pixhawk的四軸,及一台odroid XU4(with ubuntu system),想做ROS

    我們現在有2個想法

    1.用RGB-D camera 然後用open ni建模結合深度及影像,然後再建成octomap來給3D navigation(http://wiki.ros.org/3d_navigation)來做導航(又或者您知道有其他導航的code?),(現在問題是我們不確定OPEN NI能否支援octomap)

    2.用RGB-D camera然後用RTAB-MAP(http://wiki.ros.org/rtabmap_ros)(或RGBD SLAM V2)做出模型,然後再轉成octomap(確定RTAB-MAP有轉成OCTOMAP的功能),然後再用octomap來3D導航

    現在我們RGB-D camera看上 structure sensor、kinect和Xtion pro,structure sensor優點在輕但沒RGB camera,不知道能否加一個相機然後用open ni結合出深度與影像圖,Xtion pro優點也在輕,不過網路上資源少,kinect缺點就太重,不知您有何建議?

    建模則用ROS open source 的code,我們應該會用RTAB map ,因為現在比較多人用這個,但RGBD SLAM 網路上的資源較多(因為出來很久了),或者用open ni,但問題如前所述,OPEN NI能否支援octomap。

    我們對於這方面都是新手,但有心學習,懇請您不吝分享您的高見
    PS如果您不方便在這討論的話我可以給您我的email

  75. to sean

    抱歉,你所要用的其他函式庫,不管是 ROS、OctoMap、或是 RTAB-Map,Heresy 這邊都沒有實際去用過,所以應該沒辦法給你很好的意見。

發佈回覆給「jj」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *