Изображение глубины Kinect видно только частично

Я новичок в Kinect и C#. Я пытаюсь получить изображение глубины с Kinect, преобразовать его в растровое изображение, чтобы выполнить некоторые операции OpenCV, а затем отобразить его. Проблема в том, что я получаю только треть изображения глубины, а остальное полностью черное (как видно на картинке). Это не необработанное изображение глубины, а изображение, которое я получаю после рисования.

введите здесь описание изображения

Вот код-

image и image1 - это холст с двумя изображениями, который у меня есть для отображения.

void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
    {

        DepthImageFrame Image;
        Bitmap bm;
        using (Image = e.OpenDepthImageFrame())
        {


           if (Image != null)
            {
            this.shortpixeldata = new short[Image.PixelDataLength];
            this.depthFrame32 = new byte[Image.Width * Image.Height * Bgr32BytesPerPixel];


            bmp = new Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            Image.CopyPixelDataTo(this.shortpixeldata);

            byte[] convertedDepthBits = this.ConvertDepthFrame(this.shortpixeldata, ((KinectSensor)sender).DepthStream);


            BitmapData bmapdata = bmp.LockBits(
                                new System.Drawing.Rectangle(0, 0, Image.Width, Image.Height),
                                ImageLockMode.WriteOnly,
                                bmp.PixelFormat);


            IntPtr ptr = bmapdata.Scan0;
            Marshal.Copy(convertedDepthBits, 0, ptr, Image.PixelDataLength);
            bmp.UnlockBits(bmapdata);

            MemoryStream ms1 = new MemoryStream(); 
            bmp.Save(ms1, System.Drawing.Imaging.ImageFormat.Jpeg);
            System.Windows.Media.Imaging.BitmapImage bImg = new System.Windows.Media.Imaging.BitmapImage();
            bImg.BeginInit();
            bImg.StreamSource = new MemoryStream(ms1.ToArray());
            bImg.EndInit();

            image.Source = bImg;

                if (bmp != null)
            {

                Image<Bgr, Byte> currentFrame = new Image<Bgr, Byte>(bmp); 

                Image<Gray, Byte> grayImage = currentFrame.Convert<Gray, Byte>().PyrDown().PyrUp();
                Image<Gray, Byte> Dest = new Image<Gray, Byte>(grayImage.Size);
                CvInvoke.cvCanny(grayImage, Dest, 10, 60, 3);


                image1.Source = ToBitmapSource(Dest);

                CalculateFps();
            }



            }



            else
            {
                System.Diagnostics.Debug.WriteLine("depth bitmap empty :/");
            }
        }
    }


        private byte[] ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream)
        {
            System.Diagnostics.Debug.WriteLine("depthframe len :{0}", depthFrame.Length);

        for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < this.depthFrame32.Length; i16++, i32 += 4)
        {

        int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;


        byte Distance = 0;


        int MinimumDistance = 800;
        int MaximumDistance = 4096;


        if (realDepth > MinimumDistance)
        {


        //White = Close
        //Black = Far
        Distance = (byte)(255-((realDepth-MinimumDistance)*255/(MaximumDistance-MinimumDistance)));


        this.depthFrame32[i32 + RedIndex] = (byte)(Distance);
        this.depthFrame32[i32 + GreenIndex] = (byte)(Distance);
        this.depthFrame32[i32 + BlueIndex] = (byte)(Distance);
        }

        else
        {
        this.depthFrame32[i32 + RedIndex] = 0;
        this.depthFrame32[i32 + GreenIndex] = 150;
        this.depthFrame32[i32 + BlueIndex] = 0;
        }
        }

        return this.depthFrame32;
        }

Я пробовал разные PixelFormats безрезультатно. Я не могу понять проблему. Кто-нибудь знает, что я делаю неправильно? Спасибо


person uvcyclotron    schedule 15.03.2013    source источник


Ответы (2)


Я бы предложил использовать WritableBitmap, чтобы скопировать изображение глубины в видимый формат. В случае PixelFormat эта информация доступна в самом изображении глубины, поэтому вы должны использовать тот же формат для WritableBitmap, что и для захвата.

Вы смотрели на какие-либо примеры, предоставленные Microsoft? Их можно найти на странице Kinect for Windows Samples CodePlex. Есть несколько примеров, которые демонстрируют, как копировать данные о глубине в WritableBitmap, а затем выводить их. Например, вот функция обратного вызова DepthFrameReady примера приложения "DepthBasics-WPF":

/// <summary>
/// Event handler for Kinect sensor's DepthFrameReady event
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void SensorDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
    using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
    {
        if (depthFrame != null)
        {
            // Copy the pixel data from the image to a temporary array
            depthFrame.CopyDepthImagePixelDataTo(this.depthPixels);

            // Get the min and max reliable depth for the current frame
            int minDepth = depthFrame.MinDepth;
            int maxDepth = depthFrame.MaxDepth;

            // Convert the depth to RGB
            int colorPixelIndex = 0;
            for (int i = 0; i < this.depthPixels.Length; ++i)
            {
                // Get the depth for this pixel
                short depth = depthPixels[i].Depth;

                // To convert to a byte, we're discarding the most-significant
                // rather than least-significant bits.
                // We're preserving detail, although the intensity will "wrap."
                // Values outside the reliable depth range are mapped to 0 (black).

                // Note: Using conditionals in this loop could degrade performance.
                // Consider using a lookup table instead when writing production code.
                // See the KinectDepthViewer class used by the KinectExplorer sample
                // for a lookup table example.
                byte intensity = (byte)(depth >= minDepth && depth <= maxDepth ? depth : 0);

                // Write out blue byte
                this.colorPixels[colorPixelIndex++] = intensity;

                // Write out green byte
                this.colorPixels[colorPixelIndex++] = intensity;

                // Write out red byte                        
                this.colorPixels[colorPixelIndex++] = intensity;

                // We're outputting BGR, the last byte in the 32 bits is unused so skip it
                // If we were outputting BGRA, we would write alpha here.
                ++colorPixelIndex;
            }

            // Write the pixel data into our bitmap
            this.colorBitmap.WritePixels(
                new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
                this.colorPixels,
                this.colorBitmap.PixelWidth * sizeof(int),
                0);
        }
    }
}

Полный код для этого конкретного класса можно найти здесь: http://kinectforwindows.codeplex.com/SourceControl/changeset/view/861462899ae7#v1.x/ToolkitSamples1.6.0/C#/DepthBasics-WPF/MainWindow.xaml.cs

Пример «Kinect Explorer» — еще один хороший пример для рассмотрения, так как он исследует все три потока одновременно. Для этого требуется библиотека, которая не включена в репозиторий CodePlex, но может быть найдена в Kinect для Windows Toolkit.

person Nicholas Pappas    schedule 15.03.2013
comment
Мне нужно выполнить некоторые операции openCV с нарисованным depthImage, который работает с растровым изображением. Оболочка EmguCV для openCv не принимает WritableBitmap AFAIK. Теперь я решил проблему, спасибо за ваше время! :) - person uvcyclotron; 16.03.2013

Ладно, я разобрался сам. Все это время он прятался на виду.

Функция ConvertDepthFrame возвращает массив байтов в convertedDepthBits другого размера (его 4 отдельных канала, поэтому в 4 раза больше исходного размера), мне нужно использовать длину копируемых данных как 4 * Image.PixelDataLength в вызове метода: Marshal.Copy (...)

Теперь работает нормально. Фу! :)

person uvcyclotron    schedule 15.03.2013
comment
Не забудьте принять свой ответ, как только у вас появится такая возможность. ;) - person weberc2; 16.03.2013