Click here to Skip to main content
15,884,986 members
Articles / Desktop Programming / WPF

Smoothing Kinect Depth Frames in Real-Time

Rate me:
Please Sign up or sign in to vote.
4.91/5 (39 votes)
24 Jan 2012CPOL11 min read 282.8K   8.3K   58  
Removing noise from the Kinect Depth Frames in real-time using pixel filters and weighted moving average techniques.
using System.Threading.Tasks;
using System.Windows;

namespace KinectDepthSmoothing
{
    public partial class MainWindow : Window
    {
        private short[] CreateFilteredDepthArray(short[] depthArray, int width, int height)
        {
            /////////////////////////////////////////////////////////////////////////////////////
            // I will try to comment this as well as I can in here, but you should probably refer
            // to my Code Project article for a more in depth description of the method.
            /////////////////////////////////////////////////////////////////////////////////////

            short[] smoothDepthArray = new short[depthArray.Length];

            // We will be using these numbers for constraints on indexes
            int widthBound = width - 1;
            int heightBound = height - 1;

            // We process each row in parallel
            Parallel.For(0,240, depthArrayRowIndex =>
            {
                // Process each pixel in the row
                for (int depthArrayColumnIndex = 0; depthArrayColumnIndex < 320; depthArrayColumnIndex++)
                {
                    var depthIndex = depthArrayColumnIndex + (depthArrayRowIndex * 320);

                    // We are only concerned with eliminating 'white' noise from the data.
                    // We consider any pixel with a depth of 0 as a possible candidate for filtering.
                    if (depthArray[depthIndex] == 0)
                    {
                        // From the depth index, we can determine the X and Y coordinates that the index
                        // will appear in the image.  We use this to help us define our filter matrix.
                        int x = depthIndex % 320;
                        int y = (depthIndex - x) / 320;

                        // The Sum variable is used to accumulate values per pixel for possible averaging.
                        int Sum = 0;

                        // The inner and outer band counts are used later to compare against the threshold 
                        // values set in the UI to identify a positive filter result.
                        int innerBandCount = 0;
                        int outerBandCount = 0;

                        // The following loops will loop through a 5 X 5 matrix of pixels surrounding the 
                        // candidate pixel.  This defines 2 distinct 'bands' around the candidate pixel.
                        // If any of the pixels in this matrix are non-0, we will accumulate them and count
                        // how many non-0 pixels are in each band.  If the number of non-0 pixels breaks the
                        // threshold in either band, then the average of all non-0 pixels in the matrix is applied
                        // to the candidate pixel.
                        for (int yi = 0; yi < 3; yi++)
                        {
                            for (int xi = 0; xi < 3; xi++)
                            {
                                // yi and xi are modifiers that will be subtracted from and added to the
                                // candidate pixel's x and y coordinates that we calculated earlier.  From the
                                // resulting coordinates, we can calculate the index to be addressed for processing.

                                // We do not want to consider the candidate pixel (xi = 0, yi = 0) in our process at this point.
                                // We already know that it's 0
                                if (xi != 0 || yi != 0)
                                {
                                    // We then create our modified coordinates for each pass
                                    var xAdd = x + xi;
                                    var xSub = x - xi;
                                    var yAdd = y + yi;
                                    var ySub = y - yi;

                                    // While the modified coordinates may in fact calculate out to an actual index, it 
                                    // might not be the one we want.  Be sure to check to make sure that the modified coordinates
                                    // match up with our image bounds.
                                    if (xAdd >= 0 && xAdd <= widthBound && yAdd >= 0 && yAdd <= heightBound)
                                    {
                                        var index = xAdd + (yAdd * width);
                                        if (depthArray[index] != 0)
                                        {
                                            Sum += depthArray[index];
                                            if (yi != 2 && xi != 2)
                                                innerBandCount++;
                                            else
                                                outerBandCount++;
                                        }
                                    }

                                    // We are already able to calculate xi = 0 in the previous lines.  We don't want to count
                                    // the same thing twice.
                                    if (xi != 0)
                                    {
                                        if (xSub >= 0 && xSub <= widthBound && yAdd >= 0 && yAdd <= heightBound)
                                        {
                                            var index = xSub + (yAdd * width);
                                            if (depthArray[index] != 0)
                                            {
                                                Sum += depthArray[index];
                                                if (yi != 2 && xi != 2)
                                                    innerBandCount++;
                                                else
                                                    outerBandCount++;
                                            }
                                        }
                                    }

                                    // We are already able to calculate yi = 0 in the previous lines.  We don't want to count
                                    // the same thing twice.
                                    if (yi != 0)
                                    {
                                        if (xAdd >= 0 && xAdd <= widthBound && ySub >= 0 && ySub <= heightBound)
                                        {
                                            var index = xAdd + (ySub * width);
                                            if (depthArray[index] != 0)
                                            {
                                                Sum += depthArray[index];
                                                if (yi != 2 && xi != 2)
                                                    innerBandCount++;
                                                else
                                                    outerBandCount++;
                                            }
                                        }

                                        // We are already able to calculate xi = 0 in the previous lines.  We don't want to count
                                        // the same thing twice.
                                        if (xi != 0)
                                        {
                                            if (xSub >= 0 && xSub <= widthBound && ySub >= 0 && ySub <= heightBound)
                                            {
                                                var index = xSub + (ySub * width);
                                                if (depthArray[index] != 0)
                                                {
                                                    Sum += depthArray[index];
                                                    if (yi != 2 && xi != 2)
                                                        innerBandCount++;
                                                    else
                                                        outerBandCount++;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        // Once we have determined our inner and outer band non-zero counts, and accumulated all of those values,
                        // we can compare it against the threshold to determine if our candidate pixel will be changed to the
                        // average of the non-zero surrounding pixels.
                        if (innerBandCount >= innerBandThreshold || outerBandCount >= outerBandThreshold)
                            smoothDepthArray[depthIndex] = (short)(Sum / (innerBandCount + outerBandCount));

                    }
                    else
                    {
                        // If the pixel is not zero, we will keep the original depth.
                        smoothDepthArray[depthIndex] = depthArray[depthIndex];
                    }
                }
            });

            return smoothDepthArray;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Open Systems Technologies
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions