這篇還是算延續前一篇的《透過 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 直接一點一點畫出來的話,結果大概就會像上面的影片一樣了∼
[url=網址]http://ulpgdq.blu.livefilestore.com/y1pJhFP7vKp7QDGD5diJLhc0Pl4u1MiN6HGm75ueugxfln0YMifjraQCCKNT1Q6rCV3ldwDldljRt-Iu0MVZhHLGL6N48Y9j8x7/新文字文件 (2).txt?psid=1[/url]打不出文字來麻煩大大刪除一下上兩個發文:per:
to Chen,Yuan您好,您應該是使用 Windows Live Sky Drive 的空間吧?微軟的這個空間檔案是不能直連的,他的直連網址只要過一段時間就會改變,而無法連結,所以您所提供的網址已經無法存取了。不過之前有看到您所提供的內容,基本上您的寫法應該是類似「cout << pDepthMap;」,這是直接把 pDepthMap 這個指標所指的位址輸出,基本上是用來看記憶體空間所在的位址用的。但是實際上 depth map 是一個大小是 640 x 480 的一維陣列,要取存取他的資料,一般是要用迴圈去讀裡面的每一項資料的。例如本文中 GeneratePointCloud() 裡的「2. build the data structure for convert」就是在做這件事。
heresy 大大不好意思弄亂了您的Blog小弟先在此跟您道歉 (鞠躬小弟後來用 pDepthMap[] 來顯示一維陣列可是其中有點小小問題抱歉又來麻煩您heresy 大大說他是一個640*480的一維陣列所以小弟用640*480=307200出現的數字 會跟著人移近跟移遠有所變動所以從此處可以大致上認定她就是data可是當小弟印pDepthMap[307210] 卻還是有數字出現而小弟另一個疑問是 關於印出的四位數字不是三原色色碼 也對這些數字沒有頭緒是因為經過middleware轉換所以變成這樣嗎:per:有勞大大了最後 再次向您道歉及道謝 (鞠躬
to Chen,Yuan您的第一個問題,關於超出陣列大小的地方依舊可以印出值,這個算是 C 本身的設計。你可以試試看,自己宣告一個大小為十陣列,然後再去讀取他的第十一項,一樣是可以讀到值的;但是實際上,這個時候你是去讀取到其他的記憶體空間裡面的值,基本上是一種不合法的存取,取到的值也沒有任何意義。而至於在合法範圍內取得的值,他是深度資訊,所以並不是三原色;他基本上就是型別為 unsigned short 的整數,用來代表它的深度。
感謝heresy 大大 大公無私且很有耐心地回答小弟在此深深向您道謝:D
尊敬的heresy大大,小弟有些問題想向您請教一下,麻煩了。1 vPointCloud裏面的數據是否可以輸出到文件?如何實現呢。2 用OpenGL畫是不是調用vPointCloud就可以了?萬分感謝!向大大鞠躬。
to trust 1. 基本上,vPointCloud 就只是一個 SColorPoint3D 所構成的 vector 而已,要怎麼輸出到檔案,是看你要怎麼定義檔案格式來決定。2. 是的,最簡單的 Point Cloud 所需的資料(位置、顏色)都儲存在裡面了,如果是單純要用點的方法畫出來的話,這樣就夠了。
heresy大大你好~請問要怎麼重建Mesh在去貼texture呢?麻煩大大幫我解惑了,謝謝。
to yaoba您好。要重建 Mesh 也是由那些深度資料下手。基本上,讀出來的 Depth map 本身就是一個可以代表 mesh 的圖了;要重建出完整的 mesh,最簡單的做法就是把這個 regular grid 建立成 graphics 所需的大量三角形,如此就可以了。但是實作上要做得比較好,則還要考慮到兩個相鄰點距離太遠的話要斷開、幾何簡化方面的問題。
大人所有比克都写得简单易懂,思考问题很详细,佩服啊:o
heresy 你好我按照您的方法實現了3D點云的建立,可是有一個問題,就是顯示出來的點云與深度影像是鏡像的關係,這是什?原因呢?怎樣可以使點云與深度影像顯示一致,謝謝
嘿嘿,我知道哪的問題了pDepthPointSet[idx].X = i; pDepthPointSet[idx].Y = j;將i,j互換就ok了
heresy你好,请问vPointCloud的数据可以用MATLAB来作图显示么,应该用什么格式来存取?
to euphy
這個應該是看你用 Matlab 的時候打算怎麼讀取?
比較直覺的方法,應該就是自己定義一個純文字檔的格式、然後自己來控制 C 的寫入和 Matlab 的讀取了。
heresy你好,文章中的视频我通过网页看不到,可否发一个视频的链接,谢谢了
ConvertProjectiveToRealWorld
在此之前画点云, 是正常画面
用了之后,画面会上下颠倒。
to euphy
影片連結是:http://www.youtube.com/watch?v=moyDkVulRO0
另外請問一下,看不到影片不知道是看不到 YouTube 的影片?還是瀏覽器不支援造成的?
to gbadown
不太確定你想描述的意思?
不過,OpenNI 的真實世界座標系統和投影座標系統本來就是不一樣的。
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)
显示出的画面是从下到上。 画面垂直颠倒。
to gbadown
這個就是座標系統的定義不一樣啊
在一般 3D Graphics 的座標系統和 Image 的座標系統,本來就是不同的。
to heresy
是不支持youtube的问题,您发给我的链接也是看不了的,貌似大陆这边的校园网是连不上的…
to euphy
那就只能麻煩自行翻牆了
您好 heresy,我把vPointCloud的x,y,z数据存入三个txt文件中后,发现z的所有值都是0,不知是为什么?
to euphy
建議你先確認一下官方的範例顯示出來的畫面是否正常?
另外,有把所有的點輸出嗎?還是只輸出第一個點?
您好,heresy
OpenNI的sample里的可以正常显示的,我是把所有像素点输出
to euphy
可否麻煩先參考
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=215
看看直接輸出深度是否會有問題?
heresy大大你好,我也是输出到文件的时候出现问题,得到的RGB值会出现负数的情况。
to Auu
麻煩請確定你的輸出方法看看
SColorPoint3D 裡的色彩是使用 float 來儲存的,值理論上都會在 0 – 1 之間,不太可能會有負數。
heresy,你好,
我是一名kinect初学者,看了你的博文受益匪浅。有几个问题想请教一下你。1: 真实坐标系的原点在哪里呢? 中心吗? 2: 我在做kinect视觉导航,在取得深度信息后,我似乎不知道该怎么做了。单个像素的深度信息没什么意义。 你有什么建议吗?
to xx255
1. 真實世界座標系統的原點是裝置(Kinect / Xtion Pro)的中心。
2. 這取決於你要怎麼控制,一般來說把找到的關節點拿來用會比較好控制。
谢谢了 ! 我还想问下怎么抓取kinect的一帧图像呢? 好像用opencv的CvCapture *capture=0;capture = cvCreateCameraCapture(0);cvQueryFrame(capture)读不出来。
to xx255
抱歉,Heresy 沒有在使用 OpenCV,所以不應處 OpenCV 要如何讀取他的資料。
不過,這篇的範例就是會把 OpenNI 的深度、彩色資料都讀取出來,應該就已經算是把當下的 frame 抓下來了,只是看你之後要把這些資料做什麼處理而已。
你好,我是一个学生,比较菜鸟,希望给予一点指引。我想利用Kinect自带的骨骼Sample——NUIskeleton,获取里面的数据,保存,再导入3Dmax中驱动人物动起来,要求不高的,只是练习。不知道是否要利用open NI来获取数据,还是怎么办?我真的好迷茫……..期待您的答复~~~~
人體骨架資料的讀取部分,基本上可以參考
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=272
這篇文章的說明
實際上,在你的需求來說,比較麻煩的應該是要知道要怎麼樣輸出,才能讓 3D Max 讀取。
這必須要去研究 3D Max 支援的檔案格式才行。
heresy,你好,我是一位kinect 初学者!因为研究需要,我想知道经过ConvertProjectiveToRealWorld转换之后的点的坐标是怎样的?也就是说所谓的“RealWorld”坐标系到底是怎样的一个坐标系?希望你不吝赐教!
to 小书童
OpenNI 的 真實世界座標系統基本上是以感應器為原點的 3D 座標系統。
谢谢!受益匪浅!
还有一个问题!“RealWorld”坐标是左手3D坐标,那kinect所获取的关节的坐标也是在这个坐标系下吗?
谢谢!
to 小书童
OpenNI 裡面基本上就只有投影座標系統和真實世界座標系統兩種。
除了 Map Generator 的原始影像資料外,基本上都是真實世界座標系統。
谢谢!
你好,我想请教下你。 深度信息为0的点去掉以后,那么3D点云中的顺序是怎么样的呢? 怎么和像素坐标对应呢?
因为我不去掉深度为0的点 转换后深度为0的点对应X,Y,Z全都是0.
to xx / xx255
不太確定你的問題所在?在這邊的範例,Heresy 就已經把深度為 0 的點去掉了,並沒有問題。
而實際上,透過 ConvertProjectiveToRealWorld() 進行座標系統轉換時,並沒有順序上的要求;只是在顯示的時候,自己要注意點的 3D 位置和色彩的對應關係而已。
你好,可能是我表达的不清楚。 其实我就是想问下不去掉深度为0的点进行转换坐标后,像素坐标为i,j对应在点云的位置是 i*width j吧。 如果去掉深度为0的点得话,那么最后的到的点云中的位置可能就不是i*width j了。(因为可能之前有深度为0的点导致不存储)
to xx255
不太確定你的程式到底是怎麼寫?
基本上,你所計算的「i*width j」只是在投影座標系統裡,(j,i) 這個點在資料的一維陣列中的位置而已。
在做座標系統轉換的時候,基本上這個資訊的有無並不會任何影像。在之後的處理時,這個資訊也沒有任何影響。
而你如果是要考慮到和彩色影像作對應的話,在這個例子裡,Heresy 的做法就是在去掉深度為 0 的點的時候,順便就先把對應的色彩值取出來了,所以並沒有什麼問題。
heresy你好!
请问通过ConvertProjectiveToRealWorld函式获得的p3DPointSet.X,p3DPointSet.Y,p3DPointSet.Z,格式是怎样的?是int类型还是float或者其他类型?单位是毫米还是米?
另外,如果我想直接通过printf打印到txt文件中应该如何处理?
谢谢!!
to guang
單位都是公厘。
XnPoint3D 的 X / Y / Z 的資料型別則都是 XnFloat,也就是 float。
建議可以參考官方文件
heresy你好!
想要請教一下,我我為一個物體,比如一個椅子或者一個人,透過 OpenNI 建立了3D Point Cloud,發現Point Cloud的数据與椅子或人的實際尺寸有誤差,比方說椅子的實際高度是1000公厘,透過ConvertProjectiveToRealWorld函式得到的數據只有960公厘,請問是什麽原因造成的?
謝謝解答!
to susan
基本上,不管是什麼感應器都誤差,而 PrimeSense 這系列的深度感應器,基本上在越遠的地方誤差會越大,所以實際上並不能很精確地得到細緻的數據。
建議可以參考:
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=278
我按照您给的方法进行三维坐标的计算,但是用ConvertProjectiveToRealWorld算出的结果是所有点都只有x坐标,y和z坐标全为0,这是怎么回事啊?
不好意思,是我的一个地方弄错了,现在改过来了,不过重建的效果不怎么样,请问大大有什么好的三维冲就爱你算法没,求推荐。。。
to Lixam
抱歉,看不懂你的意思?
heresy你好!
我是一名学生同时也是一个kinect菜鸟,我参考你的这篇文章和用户手册得到的点云集,并将之转化到realworld中,同时将点云集和转化到realworld中的数据写入txt中,并将深度图保存。用matlab显示realworld的图像和深度图完全不一样(不会opengl),maltab显示的图像完全不知道里面的内容是什么
to lijingcsu
這應該是要確認你寫出、使用 matlab 讀取時有沒有弄錯東西了。
你好,请问一下我通过convert到realword之后得到的点云数据,用meshlab可视化之后,是一条直线,还有坐标存在负值,请问是什么问题,
to htlvcc
不確定你是怎麼把資料給 meshlab 的,不過:
1. OpenNI 的真實世界座標系統在 x, y 方向本來就是會有負的
2. 是否有先確認過讀取到的資料是正確的?
heresy大大,您好,请教一下如何通过openni获取一个已知点的深度值,拜谢了~
to long
請參考:
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=215
另外,xn::DepthMetaData 也有對應的函式可以取得特定點的值。
http://kinectcar.ronsper.com/docs/openni/classxn_1_1_depth_meta_data.html
哈哈,非常感谢啊,后来用opencv中的at方法解决了,但是也尝试了heresy大大介绍的operator方法,最后两者得出的结果一样,感谢了,现在打算研究openni2,不知道openni2增加了哪些功能
to long
OpenNI 2 基本上是架構上的改變,開發的方式有點變化。
heresy大大,现在诺基亚被微软收购了,表示QT的前途堪忧啊,不知道还有没有学QT的必要,虽然QT开发界面之类的还是很优雅,很方便的
现在就是不知道还有没其他做界面比较容易的工具,但是前景还很好的
to long
現在 Qt 應該是屬於 Digia 的。
http://zh.wikipedia.org/wiki/Qt
heresy,请教个问题。想把kinect应用到移动机器人的地图三维地图构建上。假设最初始位置(旋转角度为0,x,y,z的移动为0)为参与坐标系,似设kinect经过旋转角度a和移动(x1,y1, z1),怎么把获得的世界坐标映射回参与坐标系
to water
在已知位移和旋轉的情況下,應該可以簡單地算出 transformation matrix、並以此做相關的轉換計算。
很感谢及时回复。我使用了《学习opencv》p379中列出的如下矩阵:
[cosa 0 -sina]
[0 1 0 ]
[sina 0 cosa]
,不过实际验证不对,尝试自己推导了下变换矩阵,没有推导对,不知道有没建议?
to water
你套的矩陣並不完整,很明顯沒有把位移考慮進去。
另外,位移的計算和旋轉是有先後的順序的(旋轉中心),這點也是要考慮的。
我使用了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;
to water
這部分基本上就是看誤差到什麼程度。
Kinect 的 3D 掃描準確度本來就不是非常地精確,再加上你是手動旋轉,誤差應該是一定會有。
如果希望效果好的話,可能要再加上對位的計算、校正。
在0度的时候我的一个参照点的距离是2201mm,逆时针转了15度后算出的距离是2021mm,相差180mm。转角度我是用量角器画出转角,然后定位的,所以转角的误差应该不会太大,因为深度误差太大,所以我在想有没可能有其他原因?另外你说的对位的计算、校正是指什么,能稍微详细一点吗,谢谢。
to water
例如:
http://pointclouds.org/documentation/tutorials/registration_api.php
对位确实是个可选方案,不知道通过映射矩阵为什么会有这么大误差,所以我打算用对位来代替矩阵计算了,后面再找时间研究下这个矩阵映射的问题。
你好
請問能否取得辨識過後的3D座標呢?
to 依依
抱歉,不知道你的「辨識過後」是什麼意思?
是指
當我使用SDK中的 face tracking之後會有的一些臉部資訊
我知道會得到2D座標,但我不知道該從何處取得座標
能否有方法也取得3D座標呢?
to 依依
抱歉,你指的應該是 Kinect for Windows SDK 吧?
Heresy 這邊主要是使用 OpenNI NiTE,兩者是不同的東西。
不過基本上,K4W SDK 也有提供座標轉換的功能,可以把 2D 影像座標的點轉換到 3D 座標系統;這部分請參考 MSDN 的文件。
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()有什么区别?
对了,还有一个问题,就是不知到heresy大大有没有标定过Xtion pro live,能否方便告知下参数,还有一般情况下深度摄像头需要标定吗?
to chao
1. OpenNI 1 有提供 Frame Sync 這個 Capability,或許可以試試看。
2. ConvertProjectiveToRealWorld 是 OpenNI 提供的轉換函式,在 OpenNI 2 基本上是靠 FoV 來計算的。如果想知道它的實際算法,建議直接去看他的原始碼。
3. 抱歉,Heresy 沒做過。
请问heresy大大,OpenNI2有提供同步这个功能吗?
找到了,setDepthColorSyncEnabled这个函数就可以
请问大神,Kinect 采取的数据格式咋么转换成pcl的点云数据处理???
to 菜鸟
抱歉,Heresy 沒有用過 pcl
楼主,你好,我在深度图像生成点云上遇到一点问题,希望能交换交流方式,昵称是我的邮箱。方便的话,希望能交流,谢谢。
不好意思,我邮箱是这个jtyang@cugb.edu.cn
to ytyang@cugb.edu.cn
您好,建議您直接將您的問題留在這邊就可以了。
问题如下,我现在在用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本身的原因?我想给你发一个点云的截图,但是这里不能发图片,才想和你交换练习方式的。
to ytyang@cugb.edu.cn
個人建議或許可以先參考這篇試試看
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=569
請問如果用laview 我只是要測最短距離 請問有辦法嗎:cry:
to jack
如果你是指 LabView,抱歉 Heresy 沒有在使用這個工具。
您好
我看過您有關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
to sean
抱歉,你所要用的其他函式庫,不管是 ROS、OctoMap、或是 RTAB-Map,Heresy 這邊都沒有實際去用過,所以應該沒辦法給你很好的意見。