kinect2.0 基础篇第3篇 用C#在Visual Studio上编写把深度图像转换成彩色图像

Posted 1988博客园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kinect2.0 基础篇第3篇 用C#在Visual Studio上编写把深度图像转换成彩色图像相关的知识,希望对你有一定的参考价值。

本示例实现的功能有:有两个Radiobutton控件  选一个,点击启动按钮,

第一个是将深度图像转换成彩色图像

第二个是将深度图像做一些简单处理(例如太暗的调白一点)

 

涉及到一点遥感图像处理知识,将深度数据值转换为色调和饱和度

遥感图像处理那块不懂,有兴趣的自己可以研究研究,代码的基于kinect1的教程,慢慢尝试出来的,虽然功能实现了,但是原理还不是很懂

<Window x:Class="EnhancedDepthWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:EnhancedDepthWPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="520" Width="525">
    <Grid Background="Gray"  Width="512" Height="500" >
        <Grid VerticalAlignment="Top">
            <Grid HorizontalAlignment="Left">
                <RadioButton x:Name="radioBtnColor" Content="彩色的深度图像" />
            </Grid>
            <Grid HorizontalAlignment="Center">
                <RadioButton x:Name="radioBtnCommon" Content="普通的深度图像" IsChecked="True"/>
                </Grid>
            <Button x:Name="btnStartSensor"  Click="btnStartSensor_Click" Content="启动kinect" HorizontalAlignment="Right"/>
        </Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="9*"/>
                <ColumnDefinition Width="5*"/>
            </Grid.ColumnDefinitions>
            <Image x:Name="EnhancedDepthImage" Width="512" Height="424" Grid.ColumnSpan="2" Margin="3,0,3.4,-104"/>
        </Grid>
    </Grid>
</Window>
xaml代码

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;

namespace EnhancedDepthWPF
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private KinectSensor sensor;
        private DepthFrameReader depthReader;
        private FrameDescription depthDescription;
        private WriteableBitmap depthBitmap;
        private Int32Rect depthRect;
        private int depthStride;
        ushort[] pixelData;
        Int32 depth;
        Int32 loThreshold = 50;  //最近能测距离50mm
        Int32 hiThreshold = 450;  //最远能测距离450mm
        Int32 bytesPerPixel = 4;  //32位彩色图像,4字节
        byte[] enhPixelData;  //用于保存彩色图像的数据

        public MainWindow()
        {
            InitializeComponent();
            sensor = KinectSensor.GetDefault();
            depthReader = sensor.DepthFrameSource.OpenReader();
            depthReader.FrameArrived += depthFrame_FrameArrived;
            depthDescription = sensor.DepthFrameSource.FrameDescription;
           
            enhPixelData = new byte[depthDescription.Width * depthDescription.Height * bytesPerPixel];
        }

        private void depthFrame_FrameArrived(object sender, DepthFrameArrivedEventArgs e)
        {
            using (DepthFrame depthFrame = e.FrameReference.AcquireFrame())
            {
                if (depthFrame != null)
                {                    
                    depthFrame.CopyFrameDataToArray(pixelData);
                    if (radioBtnColor.IsChecked == true)
                    {
                        enhPixelData= DepthToColorImage(ref pixelData);
                        depthBitmap.WritePixels(depthRect, enhPixelData, depthStride, 0);
                    }
                    else
                    {
                        DepthCommonImage(ref pixelData);
                        depthBitmap.WritePixels(depthRect, pixelData, depthStride, 0);
                    }                    
                }
            }
        }

        private void DepthCommonImage(ref ushort[] pixelData)
        {
            //在数字光谱中0代表黑色,65536(16位灰阶)表示白色
            for (int i = 0; i < pixelData.Length; i++)
            {
                depth = pixelData[i] >> 3; //把像素数据转换成深度数据
                if (depth < loThreshold || depth > hiThreshold)  //常识别范围0.5m-4.5
                {
                    pixelData[i] = 35000;
                }
                else
                {
                    pixelData[i] += 20000;  //太黑了,把颜色整体调白一点
                }
                //pixelData[i] = (ushort)~pixelData[i];  //按位翻转像素值
            }
        }

        private byte[] DepthToColorImage(ref ushort[] pixelData)
        {            
            byte[] rgb = new byte[3];
            Double hue;

            for (int i = 0, j = 0; i < pixelData.Length; i++, j += bytesPerPixel)
            {
                depth = pixelData[i] >> 3;
                if (depth < loThreshold || depth > hiThreshold)
                {
                    enhPixelData[j] = 0x00;
                    enhPixelData[j + 1] = 0x00;
                    enhPixelData[j + 2] = 0x00;
                }
                else
                {
                    hue = ((360 * depth / 0xFF) + loThreshold);
                    ConvertHslToRgb(hue, 100, 100, rgb);

                    enhPixelData[j] = rgb[2]; //Blue
                    enhPixelData[j + 1] = rgb[1]; //Green
                    enhPixelData[j + 2] = rgb[0]; //Red
                }
            }
            return enhPixelData;
        }
        /// <summary>
        /// 遥感图像处理,将深度数据值转换为色调和饱和度
        /// </summary>
        /// <param name="hue">色调</param>
        /// <param name="saturation">饱和度</param>
        /// <param name="lightness">亮度</param>
        /// <param name="rgb"></param>
        private void ConvertHslToRgb(Double hue, Double saturation, Double lightness, byte[] rgb)
        {
            Double red = 0.0;
            Double green = 0.0;
            Double blue = 0.0;
            hue = hue % 360.0;
            saturation = saturation / 100.0;
            lightness = lightness / 100.0;
            if (saturation == 0.0)
            { red = lightness; green = lightness; blue = lightness; }
            else
            {
                Double huePrime = hue / 60.0;
                Int32 x = (Int32)huePrime;
                Double xPrime = huePrime - (Double)x;
                Double L0 = lightness * (1.0 - saturation);
                Double L1 = lightness * (1.0 - (saturation * xPrime));
                Double L2 = lightness * (1.0 - (saturation * (1.0 - xPrime)));

                switch (x)
                {
                    case 0: red = lightness; green = L2; blue = L0; break;
                    case 1: red = L1; green = lightness; blue = L0; break;
                    case 2: red = L0; green = lightness; blue = L2; break;
                    case 3: red = L0; green = L1; blue = lightness; break;
                    case 4: red = L2; green = L0; blue = lightness; break;
                    case 5: red = lightness; green = L0; blue = L1; break;
                }
            }
            rgb[0] = (byte)(255.0 * red);
            rgb[1] = (byte)(255.0 * green);
            rgb[2] = (byte)(255.0 * blue);
        }

        private void btnStartSensor_Click(object sender, RoutedEventArgs e)
        {
            //存放深度图像的字节数组的长度=帧长度*帧高度
            pixelData = new ushort[depthDescription.LengthInPixels];
            if (radioBtnColor.IsChecked == true)
            {
                depthBitmap = new WriteableBitmap(depthDescription.Width, depthDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
                //根据数据帧的宽高创建colorBitmap的实例
                this.depthRect = new Int32Rect(0, 0, this.depthBitmap.PixelWidth, depthBitmap.PixelHeight);
                this.depthStride = this.depthDescription.Width * 4;
                EnhancedDepthImage.Source = this.depthBitmap;
            }
            else
            {
                //位图初始化,宽度,高度,96.0表示分辨率,像素格式
                depthBitmap = new WriteableBitmap(depthDescription.Width, depthDescription.Height, 96.0, 96.0, PixelFormats.Gray16, null);
                //存放图像像素的矩形框
                depthRect = new Int32Rect(0, 0, depthBitmap.PixelWidth, depthBitmap.PixelHeight);               
                //步长:宽度*2(字节/像素)
                depthStride = depthDescription.Width * 2;
                EnhancedDepthImage.Source = depthBitmap;
            }
            sensor.Open();
        }
    }
}

 运行结果如下:

 

以上是关于kinect2.0 基础篇第3篇 用C#在Visual Studio上编写把深度图像转换成彩色图像的主要内容,如果未能解决你的问题,请参考以下文章

python基础篇第八篇面向对象(下)

python基础篇第七篇面向对象(上)

Lua从青铜到王者基础篇第一篇:Lua初始教程和环境安装

Python基础篇第2篇: Python文件操作

Python基础篇第6篇: Python模块subprocess

python 基础篇第一篇