Kinecting with Lua, Phase IIPosted: April 21, 2012
I did the initial interop FFI work for the Kinect a couple weeks back. That initial effort was sufficient to allow me to view an upside down image on my screen. The video was not very reliable, and quite a few frames were dropped, and eventually the thing would just kind of hang. Same as on the XBox actually. Mostly it works, but occasionally, it just kind of loses its mind.
Well, I’ve updated the code a bit. But, one of the most noticeable changes in my rig is that I’ve purchased the Kinect for PC. It does in fact make a difference. I don’t know if it’s primarily the slightly shorter USB cable, or because I plugged into a better USB port on my machine, or that MS has actually done something to improve it, but it is better.
In this picture, I’m capturing the color video stream at 640×480, which simultaneously capturing the depth at 320×240. It’s good enough that I can display both in realtime (~30 fps). It does get a bit jerky when there is a lot of movement in the scene, but it will run on and on and on.
I’ve done a couple of things to the code itself. First, I put evrything into a single file (Kinect.lua). It’s a bit beefy at about 1070 lines, but compared to various other files, it’s fairly tame.
Second, I abstracted the video and depth streams, so there is a KinectImageStream object. Getting that from the sensor looks like this now:
flags = bor(NUI_INITIALIZE_FLAG_USES_COLOR,NUI_INITIALIZE_FLAG_USES_DEPTH) local sensor0 = Kinect.GetSensorByIndex(0, flags); local colorStream = sensor0.ColorStream; local depthStream = sensor0.DepthStream;
Pretty simple. And what do you get from these streams? Well, in my case, I want to copy the data from the stream into a texture object so that I can display it using a quad, or do other interesting processing. The setup of the textures looks like this:
local colorWidth = 640 local colorHeight = 480 local colorImage = GLTexture.Create(colorWidth, colorHeight) local depthWidth = 320 local depthHeight = 240 local depthImage = GLTexture.Create(depthWidth, depthHeight, GL_LUMINANCE, nil, GL_LUMINANCE, GL_SHORT, 2)
Then, at every clock tick, the display routine does the following:
function displaycolorimage() local success = colorStream:GetCurrentFrame(300) if success then colorImage:CopyPixelData(colorWidth, colorHeight, colorStream.LockedRect.pBits, GL_BGRA) glViewport(windowWidth/2, windowHeight/2, windowWidth/2, windowHeight/2) displayfullquad(colorImage) colorStream:ReleaseCurrentFrame() end end function displaydepthimage() local success = depthStream:GetCurrentFrame(300) if success then depthImage:CopyPixelData(depthWidth, depthHeight, depthStream.LockedRect.pBits, GL_LUMINANCE, GL_SHORT) glViewport(0, windowHeight/2, windowWidth/2, windowHeight/2) displayfullquad(depthImage, windowWidth, windowHeight) depthStream:ReleaseCurrentFrame() end end function display(canvas) glClear(GL_COLOR_BUFFER_BIT) displaycolorimage(); displaydepthimage(); end
That’s about as simple as it gets. To go further, I could have had the stream automatically copy into a texture object, but it’s find the way it is right now. This gets very interesting when you consider the possibly collaboration with OpenCL, and OpenGL shaders. First of all, the memory can be a memory Buffer, or Image2D in OpenCL terms. That can be shared with OpenGL, for zero copying when going between the two environments.
So, imagine if you will, you can now capture data from the Kinect with very little glue code. Next, you can process that data with OpenCL kernels if you feel like it, taking advantage of some GPU processing without having to deal with GLSL. The, in the end, you can utilize the results in OpenGL, for doing whatever it is that you’ll be doing.
That’s quite a few different pieces of technology coming together there. I think LuaJIT and Lua in general makes this task a bit easier. Once the basic interfaces are done up in Lua, stitching things together gets progressively easier.
I imagine I’ll be able to shave off at least a couple hundred lines of code from that Kinect.lua file. There’s some cruft in there that I just did not clean up yet. With this one file, a developer is able to easily incorporate Kinect data into their programming flow. So, now things get really fun.