There are simply two steps to get data from Kinect: initialise Kinect and get frame from image stream.
For initialisation, these codes are required:
bool initKinect() { // Get a working kinect sensor int numSensors; if (NuiGetSensorCount(&numSensors) < 0 || numSensors < 1) return false; if (NuiCreateSensorByIndex(0, &sensor) < 0) return false; // Initialize sensor sensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH | NUI_INITIALIZE_FLAG_USES_COLOR); sensor->NuiImageStreamOpen( NUI_IMAGE_TYPE_COLOR, // Depth camera or rgb camera? NUI_IMAGE_RESOLUTION_640x480, // Image resolution 0, // Image stream flags, e.g. near mode 2, // Number of frames to buffer NULL, // Event handle &rgbStream); return sensor; }
HRESULT NuiInitialize(DWORD dwFlags);
dwFlags is a flag used to determine which content you want to capture in the NUI API, include:
Constant
|
Description
|
NUI_INITIALIZE_DEFAULT_HARDWARE_THREAD
|
This flag was deprecated in version 1.5; it
is no longer used.
|
NUI_INITIALIZE_FLAG_USES_AUDIO
|
Initialize the sensor to provide audio data.
|
NUI_INITIALIZE_FLAG_USES_COLOR
|
Initialize the sensor to provide color data.
|
NUI_INITIALIZE_FLAG_USES_DEPTH
|
Initialize the sensor to provide depth data.
|
NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX
|
Initialize the sensor to provide depth data
with a player index.
|
NUI_INITIALIZE_FLAG_USES_SKELETON
|
Initialize the sensor to provide skeleton
data.
|
These flags can be combined together by | (bitwise-OR).
HRESULT NuiImageStreamOpen(NUI_IMAGE_TYPE eImageType,NUI_IMAGE_RESOLUTION eResolution,DWORD dwImageFrameFlags,DWORD dwFrameLimit,HANDLE hNextFrameEvent,HANDLE *phStreamHandle);
This method create a specified data stream for frame grabbing.
Parameters:
eImageType [in]: Specifying what type of data stream we want, it must correspond to the parameter dwFlags in NuiInitialize.
eResolution [in]: Specifying resolution of the image we will get. For colour image, Kinect supports: 1280x1024 (12fps) and 640x240 (30fps). For depth image, it supports: 640x480, 320x240 and 80x60.
dwImageFrameFlags [in]: Specifies the frame event options (like enable near mode for Kinect for Windows).
dwFrameLimit [in]: The number of frames that the Kinect runtime should buffer. The maximum value is NUI_IMAGE_STREAM_FRAME_LIMIT_MAXIMUM. Most applications should use a frame limit of two.
hNextFrameEvent [in, optional]: A handle to a manual reset event that will be fired when the next frame in the stream is available.
phStreamHandleType [out]: A pointer that contains a handle to the opened stream.
phStreamHandleType [out]: A pointer that contains a handle to the opened stream.
Getting frame from the stream by following codes:
Finally, the frame and sensor must be release for later or other program use.
Results:
In order to distinguish the depth easily, a common method is to "compress" the depth in to several intensity region. For example, if the depth values range from 800 to 4000 (mm), we can divide the depth into different regions by mod them by 256 (if the depth is saved in char).
When acquiring the raw IR image, the IR emitter need to be covered or turned off by SDK (not valid for Kinect for Xbox) to avoid random dot pattern showing in the image.
Notes:
- For the same codes, the Kinect for Window requires some delay (800ms) after the initialization before acquiring frame from stream while Kinect for Xbox doesn't need the delay. If no delay is applied, the frame returned by the SDK may be empty or incorrect. The reason is not known so far.
- E_NUI_NOTGENUINE error was returned by the Kinect after few seconds normal running. It is caused by inadequate bandwidth of USB controller (multiple devices are connected to the same controller). It can be solved by plugging the Kinect into another USB port.
void getKinectData(GLubyte* dest) { NUI_IMAGE_FRAME colorFrame; NUI_LOCKED_RECT c_LockedRect; if (sensor->NuiImageStreamGetNextFrame(colorStream, 10, &colorFrame) < 0) return; INuiFrameTexture* c_texture = colorFrame.pFrameTexture; c_texture->LockRect(0, &c_LockedRect, NULL, 0); if (c_LockedRect.Pitch != 0) {// check valid data BYTE* c_buf = (BYTE*) c_LockedRect.pBits; for (int y = 0; y < height; ++y) { const BYTE* pImage = c_buf; for (int x = 0; x < width; ++x) { // Get depth of pixel in millimeters *dest++ = pImage[0]; // B *dest++ = pImage[1]; // G *dest++ = pImage[2]; // R *dest++ = pImage[3]; // A pImage += 4; // Go to next pixel } c_buf += width*4; // Go to next line } } c_texture->UnlockRect(0); sensor->NuiImageStreamReleaseFrame(colorStream, &colorFrame); }NuiImageStreamGetNextFrame() retrieve a frame for a given stream. The returned frame is a NUI_IMAGE_FRAME structure which contains information like frame_number, resolution, texture and etc. NUI_LOCKED_RECT contains a pointer to the actual data. An INuiFrameTexture manages the frame data. Then we get an INuiFrameTexture so that we can get the pixel data out of it, using a NUI_LOCKED_RECT. The Kinect data is in BGRA format, so we can copy it to our buffer and use if as an OpenGL texture.
Finally, the frame and sensor must be release for later or other program use.
Results:
Colour frame |
Depth frame (mod by 256) |
Depth frame(single region) |
Raw IR frame |
Notes:
- For the same codes, the Kinect for Window requires some delay (800ms) after the initialization before acquiring frame from stream while Kinect for Xbox doesn't need the delay. If no delay is applied, the frame returned by the SDK may be empty or incorrect. The reason is not known so far.
- E_NUI_NOTGENUINE error was returned by the Kinect after few seconds normal running. It is caused by inadequate bandwidth of USB controller (multiple devices are connected to the same controller). It can be solved by plugging the Kinect into another USB port.
hi Lin Zhang,
ReplyDeleteRegarding the IR stream, how did you retrieve the IR RAW image? Did you use any other libraries?
Hi, I used PCL which based on OpenNI for Kinect capture. They do provide raw image from IR camera. You need to cover the IR emitter to avoid any disruption in the IR image.
DeleteCan you please share C# code for depth data (single region) ? Thanks :)
ReplyDeleteHi, I used C++ SDK. I believe Microsoft should have provided related tutorial for the C#. Good luck
Delete