4、錄製、重播 OpenNI 擷取到的資料

4、錄製、重播 OpenNI 擷取到的資料

viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=221

前面已經花了好幾篇文章,來講怎樣透過 OpenNI 來讀取 Kinect 的資料了,而接下來這一篇,則是大概來講一下,怎樣把讀到的資料記錄下來。

在簡介 OpenNI 的時候(文章),已經有提到過,OpenNI 裡提供錄製和撥放功能相關的 Production Node,分別是 Recorder、Player、Codec;而透過 OpenNI 所設計的架構,其實要錄製、或是使用錄製下來的資料,其實都是相當簡單的∼不管是在《OpenNI User Guide》或是《OpenNI Documentation》裡,都有提供範例可以參考。

檔案格式

而以 OpenNI 提供的方法來進行錄製的話,他會把指定 node 的資料,都錄製在一個特殊格式「ONI」的檔案裡;這個格式他裡面包含了複數個 node 的資料,所以只要一個檔案,就可以同時記錄深度和彩色影像了。

而實際上,OpenNI 官方範例裡的 NiViewer 本身就包括了這樣的錄製(程式執行後按鍵盤「s」)、以及撥放的功能(直接點 *.ONI 應該就會由 NiViewer 開啟了)。

錄製

首先,下面就是一個簡單的錄製深度以及彩色影像的程式碼:

// 1. initial context
xn::Context mContext;
mContext.Init();
 
// 2. map output mode
XnMapOutputMode mapMode;
mapMode.nXRes = 640;
mapMode.nYRes = 480;
mapMode.nFPS = 30;
 
// 3. create image generator
xn::ImageGenerator mImageGen;
mImageGen.Create( mContext );
mImageGen.SetMapOutputMode( mapMode );
 
// 4. create depth generator
xn::DepthGenerator mDepthGen;
mDepthGen.Create( mContext );
mDepthGen.SetMapOutputMode( mapMode );
mDepthGen.GetAlternativeViewPointCap().SetViewPoint( mImageGen );

// 5. create recorder
xn::Recorder mRecoder;
mRecoder.Create( mContext );
mRecoder.SetDestination( XN_RECORD_MEDIUM_FILE, sFilename.c_str() );
mRecoder.AddNodeToRecording( mImageGen, XN_CODEC_JPEG );
mRecoder.AddNodeToRecording( mDepthGen, XN_CODEC_16Z_EMB_TABLES );

 
// 6. start generate data
mContext.StartGeneratingAll();
 
// 7. loop
nsigned int i = 0;
while( true )
{
  if(   i > 1000 )
    break;
  cout << i << endl;
  mContext.WaitAndUpdateAll();
}
mRecoder.Release();

 
// 8. stop
mContext.StopGeneratingAll();
mContext.Shutdown();

 

在上面的程式碼裡,應該可以很簡單地看的出來,大部分的程式其實都和《透過 OpneNI 合併 Kinect 深度以及彩色影像資料》一文內的程式碼差不多,主要有所不同的地方,僅有用黃色強調的部分而已;而實際上,要讓現有的 OpenNI 程式能夠把資料錄製下來,也就只要加上這些程式就夠了!

究竟要加那些東西呢?其實真的很簡單,只需要在本來的程式的 node 都設定完成後,在開始建立 xn::Recorder 這個錄製資料用的 node,並進行設定就可以了∼對應到上面的程式碼,就是「5. create recorder」的部分。

這裡,首先就是宣告出一個 xn::Recorder 的物件 mRecorder,並透過 Create() 這個函式來建立出 production node。接下來,則是透過 SetDestination() 這個函式,來指定 recorder 之後要將資料存在哪個檔案裡;而這個函式需要指定兩個參數,第一個是要錄製的媒體形式,目前 OpenNI 僅能使用 XN_RECORD_MEDIUM_FILE、也就是檔案的形式,而沒有其他選擇。第二個參數則就是檔案的名稱,也就是要錄製的檔案名稱(這邊 sFilename 的型別是 std::string)。

在這些設定好了以後,接下來就是要設定要錄製的 node 了,這邊所使用的是 AddNodeToRecording() 這個函式。這個函式在使用上也很單純,第一個參數就是要錄製的 node,在這邊就是 mImageGen 和 mDepthGen 這兩個 node;而第二個參數,則是要用什麼樣的方法,來對這個 node 的資料進行壓縮。

在壓縮的 codec 來說,OpenNI 提供了幾種選擇:

  • XN_CODEC_NULL:採用 node 預設值
  • XN_CODEC_UNCOMPRESSED:不壓縮
  • XN_CODEC_JPEG:JPEG 壓縮(有損)
  • XN_CODEC_16Z、 XN_CODEC_16Z_EMB_TABLES、XN_CODEC_8Z:ZIP 壓縮?

不過很遺憾的是,在官方資料裡面,似乎沒有針對這些 codec 做詳細的說明,所以 Heresy 不太確定最後三個壓縮方法的意義,不過以字面上來看,Heresy 個人覺得應該是針對 16bit 和 8bit 資料做 ZIP 壓縮;而以 NiViewer 裡面的程式來看,一般 image generator 應該是可以使用 XN_CODEC_JPEG 來做壓縮,而 depth generator 則是使用 XN_CODEC_16Z_EMB_TABLES。而如果不在乎空間的話,要使用 XN_CODEC_UNCOMPRESSED 應該也是可行的。

xn::Recorder 都設定好了之後,接下來就可以按照原來的方法,透過 context 的 StartGeneratingAll() 來開始讀取資料了∼而之後呢,只要呼叫了 context 的 WaitAndUpdateAll() 這系列的函式,xn::Recorder 就會把資料寫入到指定的 ONI 檔裡了∼(或者,也可以呼叫 xn::Recorder 的 Record() 函式)

而 Heresy 在這邊,則是用一個迴圈來做資料讀取、錄製的動作,這個迴圈會重複 1000 次,然後結束。在結束時,似乎是需要呼叫 xn::Recorder 的 Release() 函式、來釋放本身的資源、完成檔案寫出的動作。不過這邊可能要注意的是,目前 OpenNI 的 recorder 雖然可以持續的紀錄資料在 ONI 檔中,但是在檔案大小超過一定大小(約 2GB)後,會無法完成最後寫入的動作,導致最後的檔案無法被正常存取;所以如果要長時間錄製的話,可能就要自己注意檔案的大小、考慮想辦法切割檔案了。

 

播放

在播放的部分,如果只是單純要使用錄製下來的 ONI 的話,也相當地簡單,原有的程式只要加上一行就可以了!而如果要有額外的控制功能,也可以透過 OpenNI 的 xn::Player 來做到。

最簡單的其修改方法,就是在 OpenNI 的 context 初始化完成後、建立 Production Node 前,加上一行 xn::Context::OpenFileRecording(),來開起一個 ONI 檔。如果以《透過 OpneNI 合併 Kinect 深度以及彩色影像資料》一文中的程式來說,就是把「2. initial context」的部分,修改為:

xn::Context mContext;
eRes = mContext.Init();
mContext.OpenFileRecording( sFilename.c_str() );

 

接下來,就繼續沿用原來的程式碼就可以了!

而在透過 mContext 的 OpenFileRecording() 去開啟 sFilename(型別為 std::string)這個檔案後,Conext 內部會由讀取實際的裝置(Kinect)、改成去讀取 ONI 檔內的資料,而之後所建立的 Production Node,也都會對應到 ONI 內所錄製的 node。而之後讀取的時候,也是會依序讀出 ONI 檔裡各 node 的資料,不會再去讀取實際的裝置。

不過也由於這邊的資料都是已經記錄好的,所以在設定上會有一些限制,像是 Alternative View 在這個情況下,就會無法使用;不過由於 OpenNI 的設計上並不會因為這類的函示無法呼叫,就強制中斷,所以程式還是可以可以繼續執行的∼但是如果去分析每一個步驟回傳的 XnStatus 的話,就可以看的出來那些函示無法在播放 ONI 時使用了。

另外,如果希望針對撥放在做進一步的控制的話,也可以使用 xn::Player 這個 node 來做操作,包括了跳到某個 frame、重播、撥放速度等等,都可以做控制。不過這部分在這邊就暫時不提,以後如果有機會再寫了。

 

這篇基本上就先到這了。而有了錄製和撥放的功能後,基本上測試資料就可以很簡單地記錄下來,要針對特殊的狀況來幫程式除錯,也會變得比較簡單了∼

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值