Sorry it's taken so long, but I've finally had some time to revisit the source code on this article. I have made a first pass with the new v1.7 Kinect SDK, and have posted it to https://kinectdepthsmoothing.codeplex.com/[^].
I still have a little tweaking I'd like to do before I update the article, but this will get the code working on the new SDK's. A few notes about changes in the source code you will find:
-The smoothing methods will now allow for PlayerIndex preservation of DepthImagePixel's. This allows you to use the filters for green screen scenarios now.
-The smoothing methods will now handle multiple depth frame resolutions.
-The WPF example is built upon the DepthBasics-WPF example code from the Kinect for Windows Toolkit.
Hi, your code is very helpfull, i was trying to run both methods you propouse in the new kinect version(1.6), i just figure out how to make work the filter in this new version, but i having problems with the averge method; im doing a code that only get the players silouttes with out the jittering on the edges... can you please help me how to implement your code to the new kinect version or at least tell me how to remove the jittering from the players silouettes? Thank you BTW.
Hi Karl, May i know why do you wanna use inner and outer bounds instead of just a 5x5 grid to slide through? Is it any advantage for using inner & outer bounds?? Thanks!
Hi
Your code looks good . BTW I was trying to implement your filter in the green screen kinect app. But unable to finish it.
Have you tried with new SDK 1.5 ??
Thanks very much for sharing your knowledge, it's outstanding. We are working on a kinect project, which basically is a chromakey effect and your work would help us to enhance the image results, but we are developing it in the last SDK version. Do you think you could give us any clue about how to update this code to the last version. We need to solve this immediately, and we will really appreciate any advice you could give us.
Hi, I'm glad this will help you out. I'm currently working on updating it for the latest SDK... I was hoping to have it done already, but I'm having a hard time getting the time to myself to do it. Hopefully it'll be done soon.
As far as what I'm having to change:
-Basics of the new SDK: the new SDK versus the Beta are very different in how you actually initialize and obtain the depth information.
-Changing how the depth array is created from the ImageFrame: the current CreateDepthArray method needs to be changed to use the newer image frames and depth bits. All subsequent methods use the results of the CreateDepthArray method, so not much else should need to be changed as long as the results stay the same.
-Allowing tracked user depths: currently, my code only supports basic depth frames. there were other requests to accept and preserve player indexes in depth frames, and I am working on adding this functionality. For this, we essentially have to just keep the original frame information, extract our depth data and perform modifications, and reinsert it into the original frame info. this is proving to be a little challenging because it adds the extra steps of smoothing over potential tracked players and expanding it beyond the intended area.
The only advice I would give is to make sure that you have implemented a weighted moving average, and not just a moving average. You could also try reducing the number of frames you are including in the average, or try moving to an exponential weighted moving average.
I am having trouble using this algorythm with the latest kinect sdk.There are few changes i have as per the new sdk but with no luck, would appreciate any help.
" There are 10 types of people one who understands binary and one who don't................."
Sorry, I didn't use any research publications to develop these two approaches. I'm sure there are probably some papers out there that cover similar techniques, but I don't know of them. Is there something specific you had questions about that I could help you with?
Your Article is informative. Cheer Up! I want to implement and evaluate some more filters. Can you suggest the idea to implement Multi-lateral Filter for Real-Time Depth Enhancement.
I am new to Kinect programming, and was frustrated by the blinking edges of the player extracted from the DepthAndPlayer frame.
Your algorithm seems to be a solution for my problem, but in your case you don't handle the player index.
Would you mind giving advice to me what if this algorithm can be useful if I also want the player information? Or what direction should I go if I to solve that?
Hi Leo,
To be able to handle the depth with a player index, there are a couple things to look at. First, you want to be able to calculate the depth correctly. We will change the CalculateDistanceFromDepth method to look like this:
This change will handle the smoothing for output of depth data when using the player index.
However, I'm guessing that what you really want is to be able to change the color of the player? To do this, you will need to preserve the player index from the original depth data in some way. There are any number of ways to do this.
One possible way to do this is to preserve the data in a new array. You could do this by creating a new method that is exactly like the CreateDepthArray except that rather than performing the CalculateDistanceFromDepth method, you would calculate the Player Index like this:
Then you could use this resulting array during the actual rendering to identify pixels that represent a Player.
That would be the rough and dirty approach, and should get you started down the right path.
To make the approach more elegant, something to consider is that smoothing could possibly extend the area that represents a player. You may need to tweak the actual smoothing algorithm to take player indexes into account during the process if you want the player coloring to extend over the smoothed noise pixels.
If I was entirely off, and you actually want to be able to use the Player Indexes of the depth data as a smoothed mask for clipping of color frames, then I would recommend an entirely different approach all together...
Version 1 of the Kinect SDK was released today. I am still reviewing the changes, but I plan to update this article for the new release when I get some free time (maybe this weekend?).
Did you manage to take a look at this for the v1 SDK, as yet?
I've tried integrating the CreateAverageDepthArray() and CreateFilteredDepthArray() functions into my own project that generates a point cloud from Kinect data, but have so far found the smoothing (at leastthe averaging - the filtering doesn't appear to be working at all for me, as yet) to give worse results that the base Kinect.
I'll keep plugging away, in case it's an issue from my side.
HI, and thanks so much for a well written article. Ive been working on somehting similar, and have enjoyed your article immensely. Unfortunatly, Im a VB guy, and while I have gotten the code converted for the most part, Im really stuck with the Parallel.For routines... I cant seem to understand whats happening in them well enough to translate it to something I can use. Im not sure if oyu can or not, but could you either explain the following snippet, or, if possible, provide a vb translation? I think I understand whats going on, but clearly Im missing something...thanks in advance!
// Porcess each row in parallel Parallel.For(0, 240, depthImageRowIndex => { // Process each pixel in the row for (int depthImageColumnIndex = 0; depthImageColumnIndex < 640; depthImageColumnIndex += 2) { var depthIndex = depthImageColumnIndex + (depthImageRowIndex * 640); var index = depthIndex / 2;
Thanks, I'm glad you've enjoyed the article. I've used VB so rarely that you don't want a translation from me. I will try to explain what's happening a bit better, and point you in the right direction.
A Parallel For loop acts much like any normal for loop; you have a From(inclusive) value, a To(exclusive), and some variable to know what loop number you're on. On line 6, the values being passed to the For method are (From 0 (inclusive), To 240 (exclusive), variable to use in the loop). The Parallel.For method will then (possibly) run each of the loops in parallel.
We loop from 0 to 239 because we want to process each row of the array as it would appear in the final render. Since the resolution is 320x240, we can then calculate the start of each row by multiplying the row index (0 - 239) by the number of columns in each row. We can address each pixel in the row by adding this number to the column index as you see in line 11.
You may be wondering why I have 640 in for the number of columns if the resolution is 320x240. This is because of the way we get the depth frame from the Kinect. The byte array from the Kinect that holds the depth information has two bytes per pixel; so there are actually 320 (resolution width) x 2 = 640 columns in the initial data. We use these two bytes on line 14 to calculate an individual depth value. We can then determine the index of the individual value in the final render by dividing our depthIndex by 2 (since our depth frame is twice as big as our output) on line 12. Then notice that we increment our column index by 2 at the end of row 9 to progress to the next pixel.
As you'll see in the code, any other Parallel.For loop after the data has been processed in this method will have a column limit of 320.
At the end of line 6, you'll notice the '=>' symbols, then some curly brackets and some code. This is a lambda expression in C#. You can read more about the VB equivalent at MSDN - Lambda Expressions (Visual Basic)[^].
A well written article. I also enjoyed the structure of your article. Stating what the problem is and showing the solution and highlighting any code that achieves the solution. I wish all articles written used this same structure.