0x01
第一次使用SDK寫代碼,有很多不懂的地方,在設備來之前把文檔看了一下,大概明白了點,東平西湊大概寫了點,但是當把設備連接上去進行測試的時候就出現了各種問題,用RealSenseCamera進行開發的人還比較少,只有論壇上的一些零星的討論,並且用C#進行開發的人還是占多數,畢竟和Unity3D結合起來還是比較有趣的。文檔里寫了入門的教程,但是因為和我的使用場景不太一樣,其中又有些奇葩的地方,文檔里又沒有說明,對編程又不是很熟悉,導致到后來才大概猜到了一點,理解了一點,在這里寫下來給大家一個參考。
0x02

我們這次采用的設備是intel RealSense Camera R200,它有RGB攝像頭以及兩個IR攝像頭,通過與IR Laser Projector的結合可以得到場景的深度信息。SDK中還有很多內置的面部識別和手勢識別等函數。但是我們並不需要用到那些,我只想獲取它的左右兩個紅外攝像頭采集到的圖片。
0x03
首先遇到的問題的就是visual studio 2013配置的問題,本來它很貼心的提供了直接導入Property Sheet一鍵式的配置,可是我試了兩次都失敗了,而且傳到github上以后發現其他人下載下來就沒辦法打開我的Solution了(里面出現我的配置文件的具體路徑),於是還是進行了手動的配置。其實手動配置也挺好的,下次遇到其他的時候需要配置就可以自己動手了。原來配置opencv的時候就是各種不懂,別人怎么說我就怎么做,雖然最后可以寫代碼了,但是下次遇到這些問題又要把博客翻出來看看是怎么回事了。
本來按部就班按照他的指導手冊一步一步來就可以了,可是各種報錯。
Create Session
The SDK core is represented by two interfaces:
- PXCSessionmanages all of the modules of the SDK
- PXCSenseManagerorganizes a pipeline by starting,stopping,and pausing the operations of its varies modalities.
PXCSenseManager *psm=0;
psm = PXCSenseManager::CreateInstance();
if (!psm)
{
wprintf_s(L"Unable to create the PXCSenseManager\n");
return 1;// select the color stream of size 640x480 and depth stream of size 640x480
}
psm->EnableStream(PXCCapture::STREAM_TYPE_LEFT, 640, 480);
psm->EnableStream(PXCCapture::STREAM_TYPE_RIGHT, 640, 480);
psm -> Init()
}
然后初始化的時候就報錯了,前面的配置沒有問題。我就看了一下它的例子,然后把其中一段拷貝了出來
// Select the color and depth streams
PXCVideoModule::DataDesc ddesc={};
ddesc.deviceInfo.streams=PXCCapture::STREAM_TYPE_RIGHT |PXCCapture::STREAM_TYPE_LEFT;
sm->EnableStreams(&ddesc);
然后初始化沒有問題,我當時就可想不通為什么這么來就行,用EnableStream就是不行呢,明明官方文檔里沒有提到這個問題啊。各種不理解,困惑了很長世間,導致我下面也沒辦法寫下去。
0x04
后來在論壇里看到了這段代碼
// Get the raw 16bit data from the infrared image
PXCMImage.ImageData irImageData;
irImageSource.AcquireAccess(PXCMImage.Access.ACCESS_READ,PXCMImage.PixelFormat.PIXEL_FORMAT_Y16,out irImageData);
irImageData.ToUShortArray(0, irData);
// despite the ir camera being 628 pixels wide, the raw bytes are stored with a "pitch" of 640
// in the case of 16bit data, the pitch is returned as 1280
int pitch = irImageData.pitches[0]/2;
int width = irImageSource.info.width;
int height = irImageSource.info.height;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int iA = (height-y-1) * pitch + x;
int iB = (y * width + x) * 4;
byte intensity = (byte)(irData[iA]/4);// raw pixels range between 0-1024
imgData[iB] = intensity;
imgData[iB+1] = intensity;
imgData[iB+2] = intensity;
imgData[iB+3] = 255; // Alpha
}
}
仔細琢磨了以后我發現自己對於PXCMImage::ImageData里面的piches和panels並不理解。重新看了文檔以后我的理解是這樣的:PXCMImage::ImageData里面存儲的數據是在內存的某段空間,這段空間的首地址(類似於數組名)就放在panels[0]里。而piches(間距)表示的則是這段內存空間的寬度。
但是還是不明白,為什么我上面的初始化會失敗。我們后來還曾經嘗試過用Github上面的一段代碼把讀取到的圖像中的信息放到cv::Mat的格式里(長和寬設置為640×480)。它會提示超出了內存范圍。嘗試了各種斷點之后發現,設備的信息返回的圖像的大小是很詭異的628×468,當把圖像大小設置為這個數字的時候按照教程來就不會出現無法初始化的問題了,看來問題出在這個圖像的大小上。
於是搜索了一下SDK的文檔,關於紅外成像的大小的,發現是這樣的

返回的並沒有640×480這個選項。到這里就恍然大悟了。
首先為什么初始化失敗:我把圖像的大小設置成了640×480,雖然能夠啟動數據流,但是初始化就出問題了,而后面提到的那種設置方式是采用了默認的大小。
第二,為什么后面會出現超出內存空間的錯誤,是因為雖然他的piches是640,但是在紅外的情況下,實際上只在前面的628位上存儲有圖像的數據,后面的索引自然是失效的。但是如果要把圖像的信息傳輸完全就要把循環結構中的int iA = (height-y-1) * pitch + x;使用pich而不是628。
0x05
寫了這么幾段,也不知道有沒有把問題說清楚,第一次寫這樣子的所謂技術博客還是沒什么經驗,但是我相信會越寫越好的,下次用_visio_畫圖把問題說的更清楚。
