C#Kinect for Windows:如何组合/覆盖骨架和颜色流/图像?

时间:2013-07-07 20:13:38

标签: kinect kinect-sdk

我正在尝试编写一个程序,它向我显示当前的colorstream,并将其与骨架流叠加/组合。

我采用了microsoft skeletonviewer示例并尝试实现colorstream。那很有效,色彩缤纷,但骨架消失了......

所以现在我的问题是:如何启用骨架,以便如果人站在kinect前面,颜色流和骨架出现?

这是我的代码:

namespace Microsoft.Samples.Kinect.SkeletonBasics
{
using System.IO;
using System.Windows;
using System.Windows.Media;
using Microsoft.Kinect;
using System;
using System.Windows.Media.Imaging;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    /// <summary>
    /// Width of output drawing
    /// </summary>
    private const float RenderWidth = 640.0f;

    /// <summary>
    /// Height of our output drawing
    /// </summary>
    private const float RenderHeight = 480.0f;

    /// <summary>
    /// Thickness of drawn joint lines
    /// </summary>
    private const double JointThickness = 3;

    /// <summary>
    /// Thickness of body center ellipse
    /// </summary>
    private const double BodyCenterThickness = 10;

    /// <summary>
    /// Thickness of clip edge rectangles
    /// </summary>
    private const double ClipBoundsThickness = 10;

    /// <summary>
    /// Brush used to draw skeleton center point
    /// </summary>
    private readonly Brush centerPointBrush = Brushes.Blue;

    /// <summary>
    /// Brush used for drawing joints that are currently tracked
    /// </summary>
    private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68));

    /// <summary>
    /// Brush used for drawing joints that are currently inferred
    /// </summary>        
    private readonly Brush inferredJointBrush = Brushes.Yellow;

    /// <summary>
    /// Pen used for drawing bones that are currently tracked
    /// </summary>
    private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6);

    /// <summary>
    /// Pen used for drawing bones that are currently inferred
    /// </summary>        
    private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1);

    /// <summary>
    /// Active Kinect sensor
    /// </summary>
    //private KinectSensor sensor;
    KinectSensor sensor = KinectSensor.KinectSensors[0];
    private byte[] colorPixelData;
    private WriteableBitmap outputImage;


    /// <summary>
    /// Drawing group for skeleton rendering output
    /// </summary>
    private DrawingGroup drawingGroup;

    /// <summary>
    /// Drawing image that we will display
    /// </summary>
    private DrawingImage imageSource;

    /// <summary>
    /// Initializes a new instance of the MainWindow class.
    /// </summary>
    public MainWindow()
    {
        InitializeComponent();
    }


    /// <summary>
    /// Draws indicators to show which edges are clipping skeleton data
    /// </summary>
    /// <param name="skeleton">skeleton to draw clipping information for</param>
    /// <param name="drawingContext">drawing context to draw to</param>
    private static void RenderClippedEdges(Skeleton skeleton, DrawingContext drawingContext)
    {
        if (skeleton.ClippedEdges.HasFlag(FrameEdges.Bottom))
        {
            drawingContext.DrawRectangle(
                Brushes.Red,
                null,
                new Rect(0, RenderHeight - ClipBoundsThickness, RenderWidth, ClipBoundsThickness));
        }

        if (skeleton.ClippedEdges.HasFlag(FrameEdges.Top))
        {
            drawingContext.DrawRectangle(
                Brushes.Red,
                null,
                new Rect(0, 0, RenderWidth, ClipBoundsThickness));
        }

        if (skeleton.ClippedEdges.HasFlag(FrameEdges.Left))
        {
            drawingContext.DrawRectangle(
                Brushes.Red,
                null,
                new Rect(0, 0, ClipBoundsThickness, RenderHeight));
        }

        if (skeleton.ClippedEdges.HasFlag(FrameEdges.Right))
        {
            drawingContext.DrawRectangle(
                Brushes.Red,
                null,
                new Rect(RenderWidth - ClipBoundsThickness, 0, ClipBoundsThickness, RenderHeight));
        }
    }

    /// <summary>
    /// Execute startup tasks
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void WindowLoaded(object sender, RoutedEventArgs e)
    {
        // Create the drawing group we'll use for drawing
        this.drawingGroup = new DrawingGroup();

        // Create an image source that we can use in our image control
        this.imageSource = new DrawingImage(this.drawingGroup);

        // Display the drawing using our image control
        videoimage.Source = this.imageSource;

        // Look through all sensors and start the first connected one.
        // This requires that a Kinect is connected at the time of app startup.
        // To make your app robust against plug/unplug, 
        // it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit
        foreach (var potentialSensor in KinectSensor.KinectSensors)
        {
            if (potentialSensor.Status == KinectStatus.Connected)
            {
                this.sensor = potentialSensor;
                break;
            }
        }

        if (null != this.sensor)
        {
            // Turn on the skeleton stream to receive skeleton frames
            this.sensor.SkeletonStream.Enable();
            this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
            this.sensor.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(this.SensorColorFrameReady);


            // Add an event handler to be called whenever there is new color frame data
            this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady;


            // Start the sensor!
            try
            {
                this.sensor.Start();
            }
            catch (IOException)
            {
                this.sensor = null;
            }
        }

        if (null == this.sensor)
        {
            this.statusBarText.Text = Properties.Resources.NoKinectReady;
        }
    }

    /// <summary>
    /// Execute shutdown tasks
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        if (null != this.sensor)
        {
            this.sensor.Stop();
        }
    }

    /// <summary>
    /// Event handler for Kinect sensor's SkeletonFrameReady event
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
    {
        Skeleton[] skeletons = new Skeleton[0];

        using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
        {
            if (skeletonFrame != null)
            {
                skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
                skeletonFrame.CopySkeletonDataTo(skeletons);
            }
        }

        using (DrawingContext dc = this.drawingGroup.Open())
        {
            // Draw a transparent background to set the render size
            //dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight));

            if (skeletons.Length != 0)
            {
                foreach (Skeleton skel in skeletons)
                {
                    RenderClippedEdges(skel, dc);

                    if (skel.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        this.DrawBonesAndJoints(skel, dc);
                    }
                    else if (skel.TrackingState == SkeletonTrackingState.PositionOnly)
                    {
                        dc.DrawEllipse(
                        this.centerPointBrush,
                        null,
                        this.SkeletonPointToScreen(skel.Position),
                        BodyCenterThickness,
                        BodyCenterThickness);
                    }
                }
            }

            // prevent drawing outside of our render area
            this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));
        }
    }

    private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
    {
        using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
        {
            if (colorFrame != null)
            {
                this.colorPixelData = new byte[colorFrame.PixelDataLength];

                colorFrame.CopyPixelDataTo(this.colorPixelData);

                this.outputImage = new WriteableBitmap(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null);
                this.outputImage.WritePixels(new Int32Rect(0, 0, colorFrame.Width, colorFrame.Height), this.colorPixelData, colorFrame.Width * 4, 0);
                this.videoimage.Source = this.outputImage;

            }
        }

     }

    /// <summary>
    /// Draws a skeleton's bones and joints
    /// </summary>
    /// <param name="skeleton">skeleton to draw</param>
    /// <param name="drawingContext">drawing context to draw to</param>
    private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext)
    {
        // Render Torso
        this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter);
        this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft);
        this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight);
        this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.Spine);
        this.DrawBone(skeleton, drawingContext, JointType.Spine, JointType.HipCenter);
        this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipLeft);
        this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.HipRight);

        // Left Arm
        this.DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft);
        this.DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft);
        this.DrawBone(skeleton, drawingContext, JointType.WristLeft, JointType.HandLeft);

        // Right Arm
        this.DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight);
        this.DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight);
        this.DrawBone(skeleton, drawingContext, JointType.WristRight, JointType.HandRight);

        // Left Leg
        this.DrawBone(skeleton, drawingContext, JointType.HipLeft, JointType.KneeLeft);
        this.DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft);
        this.DrawBone(skeleton, drawingContext, JointType.AnkleLeft, JointType.FootLeft);

        // Right Leg
        this.DrawBone(skeleton, drawingContext, JointType.HipRight, JointType.KneeRight);
        this.DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight);
        this.DrawBone(skeleton, drawingContext, JointType.AnkleRight, JointType.FootRight);

        // Render Joints
        foreach (Joint joint in skeleton.Joints)
        {
            Brush drawBrush = null;

            if (joint.TrackingState == JointTrackingState.Tracked)
            {
                drawBrush = this.trackedJointBrush;                    
            }
            else if (joint.TrackingState == JointTrackingState.Inferred)
            {
                drawBrush = this.inferredJointBrush;                    
            }

            if (drawBrush != null)
            {
                drawingContext.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(joint.Position), JointThickness, JointThickness);
            }

    }


    }


    /// <summary>
    /// Maps a SkeletonPoint to lie within our render space and converts to Point
    /// </summary>
    /// <param name="skelpoint">point to map</param>
    /// <returns>mapped point</returns>
    private Point SkeletonPointToScreen(SkeletonPoint skelpoint)
    {
        // Convert point to depth space.  
        // We are not using depth directly, but we do want the points in our 640x480 output resolution.
        DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30);
        return new Point(depthPoint.X, depthPoint.Y);
    }

    private Point UpdateDraw(Joint joint)
    {
        //foreach (Joint joint in skeleton.Joints)
        //{
            ColorImagePoint colorPoint = this.sensor.CoordinateMapper.MapSkeletonPointToColorPoint(joint.Position, ColorImageFormat.RgbResolution640x480Fps30);
            //var point = new Point((int)ColorImagePoint.X / 640.0 * this.ActualWidth, (int)ColorImagePoint.Y / 480.0 * this.ActualHeight);
            return new Point(colorPoint.X, colorPoint.Y);
        //}

    }

    /// <summary>
    /// Draws a bone line between two joints
    /// </summary>
    /// <param name="skeleton">skeleton to draw bones from</param>
    /// <param name="drawingContext">drawing context to draw to</param>
    /// <param name="jointType0">joint to start drawing from</param>
    /// <param name="jointType1">joint to end drawing at</param>
    private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1)
    {
        Joint joint0 = skeleton.Joints[jointType0];
        Joint joint1 = skeleton.Joints[jointType1];

        // If we can't find either of these joints, exit
        if (joint0.TrackingState == JointTrackingState.NotTracked ||
            joint1.TrackingState == JointTrackingState.NotTracked)
        {
            return;
        }

        // Don't draw if both points are inferred
        if (joint0.TrackingState == JointTrackingState.Inferred &&
            joint1.TrackingState == JointTrackingState.Inferred)
        {
            return;
        }

        // We assume all drawn bones are inferred unless BOTH joints are tracked
        Pen drawPen = this.inferredBonePen;
        if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked)
        {
            drawPen = this.trackedBonePen;
        }

        drawingContext.DrawLine(drawPen, this.SkeletonPointToScreen(joint0.Position), this.SkeletonPointToScreen(joint1.Position));
    }

    /// <summary>
    /// Handles the checking or unchecking of the seated mode combo box
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void CheckBoxSeatedModeChanged(object sender, RoutedEventArgs e)
    {
        if (null != this.sensor)
        {
            if (this.checkBoxSeatedMode.IsChecked.GetValueOrDefault())
            {
                this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
            }
            else
            {
                this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;
            }
        }
    }

    private void btnDown(object sender, RoutedEventArgs e)
    {
        try
        {
            sensor.ElevationAngle = sensor.ElevationAngle - 5;
        }
        catch (ArgumentOutOfRangeException outOfRangeException)
        {
            System.Windows.MessageBox.Show(outOfRangeException.Message);
            System.Windows.MessageBox.Show("Die niedrigste Einstellung ist bereits erreicht.", "Ungütliger Winkel");
        }
    }

    private void btnUp(object sender, RoutedEventArgs e)
    {
        try
        {
            sensor.ElevationAngle = sensor.ElevationAngle + 5;
        }
        catch (ArgumentOutOfRangeException outOfRangeException)
        {
            System.Windows.MessageBox.Show(outOfRangeException.Message);
            System.Windows.MessageBox.Show("Die höchste Einstellung ist bereits erreicht.", "Ungütliger Winkel");
        }
    }
}
}

这是我的XML文件:

<Window x:Class="Microsoft.Samples.Kinect.SkeletonBasics.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SkeletonApp - Kinect configuration" Height="720.075" Width="770" Loaded="WindowLoaded" Closing="WindowClosing" WindowStyle="ToolWindow">

<Window.Resources>
    <SolidColorBrush x:Key="MediumGreyBrush" Color="#ff6e6e6e"/>
    <SolidColorBrush x:Key="KinectPurpleBrush" Color="#ff52318f"/>
    <SolidColorBrush x:Key="KinectBlueBrush" Color="#ff00BCF2"/>
    <Style TargetType="{x:Type Image}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
    </Style>
    <Style TargetType="{x:Type CheckBox}" x:Key="SquareCheckBox" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <Grid>
                        <StackPanel Orientation="Horizontal" Background="Transparent">
                            <Grid x:Name="SquareCheckBoxChecked">
                                <Image x:Name="CheckedNormal" Source="Images\CheckedNormal.png" Stretch="None" HorizontalAlignment="Center"/>
                                <Image x:Name="CheckedHover" Source="Images\CheckedHover.png" Stretch="None" HorizontalAlignment="Center" Visibility="Collapsed"/>
                            </Grid>
                            <Grid x:Name="SquareCheckBoxUnchecked" Visibility="Collapsed">
                                <Image x:Name="UncheckedNormal" Source="Images\UncheckedNormal.png" Stretch="None" HorizontalAlignment="Center"/>
                                <Image x:Name="UncheckedHover" Source="Images\UncheckedHover.png" Stretch="None" HorizontalAlignment="Center" Visibility="Collapsed"/>
                            </Grid>
                            <TextBlock x:Name="SquareCheckBoxText" Text="{TemplateBinding Content}" TextAlignment="Left"  VerticalAlignment="Center" Foreground="{StaticResource KinectPurpleBrush}" FontSize="15"  Margin="9,0,0,0"/>
                        </StackPanel>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="false">
                            <Setter Property="Visibility" Value="Collapsed" TargetName="SquareCheckBoxChecked"/>
                            <Setter Property="Visibility" Value="Visible" TargetName="SquareCheckBoxUnchecked"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Visibility" Value="Collapsed" TargetName="CheckedNormal"/>
                            <Setter Property="Visibility" Value="Collapsed" TargetName="UncheckedNormal"/>
                            <Setter Property="Visibility" Value="Visible" TargetName="CheckedHover"/>
                            <Setter Property="Visibility" Value="Visible" TargetName="UncheckedHover"/>
                            <Setter Property="Foreground" Value="{StaticResource KinectBlueBrush}" TargetName="SquareCheckBoxText"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Window.Background>
    <SolidColorBrush Color="#FF272727"/>
</Window.Background>

<Grid Name="layoutGrid" Margin="10 0 10 0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="289*"/>
        <ColumnDefinition Width="276*"/>
        <ColumnDefinition Width="177*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <DockPanel Grid.Row="0" Margin="0 0 0 20" Grid.ColumnSpan="3"/>
    <Viewbox Grid.Row="1" Stretch="Uniform" HorizontalAlignment="Center" Grid.ColumnSpan="3">
        <Grid ClipToBounds="True">
            <Image Name="videoimage" Width="640" Height="480"/>
            <Canvas Background="Transparent" Name="ColorImagePoint"></Canvas>
        </Grid>
    </Viewbox>
    <CheckBox Grid.Row="2" Style="{StaticResource SquareCheckBox}" Content="Seated Mode" Height="Auto" VerticalAlignment="Center" Margin="0,10,157,10" Name="checkBoxSeatedMode" Checked="CheckBoxSeatedModeChanged" Unchecked="CheckBoxSeatedModeChanged" Foreground="White"/>
    <StatusBar Grid.Row="3" HorizontalAlignment="Stretch" Name="statusBar" VerticalAlignment="Bottom" Background="White" Foreground="{StaticResource MediumGreyBrush}" Grid.ColumnSpan="3">
        <StatusBarItem Padding="0 0 0 10">
            <StatusBarItem.Background>
                <SolidColorBrush Color="#FF272727"/>
            </StatusBarItem.Background>
            <TextBlock Name="statusBarText" Margin="-1 0 0 0" Foreground="White">Click 'Seated' to change skeletal mode</TextBlock>
        </StatusBarItem>
    </StatusBar>
    <Button Content="UP" HorizontalAlignment="Left" Margin="198,5,0,0" VerticalAlignment="Top" Width="115" Height="35" Click="btnUp" Grid.Row="2" Grid.Column="1" RenderTransformOrigin="-0.122,0.716" Grid.ColumnSpan="2" Foreground="White" BorderBrush="DodgerBlue" Background="DodgerBlue"/>
    <Button Content="DOWN" HorizontalAlignment="Right" Margin="0,5,10,0" VerticalAlignment="Top" Width="115" Height="35" Grid.Column="2" Click="btnDown" Grid.Row="2" Foreground="White" Background="DodgerBlue" BorderBrush="DodgerBlue"/>
    <Label x:Name="Label_Angle" Content="Adjust Kinect Angle:" Grid.Column="1" HorizontalAlignment="Left" Margin="73,10,0,0" Grid.Row="2" VerticalAlignment="Top" RenderTransformOrigin="0.787,-0.551" Background="#00000000" Foreground="White"/>
</Grid>

1 个答案:

答案 0 :(得分:2)

最简单的方法是将两个图像控件叠加在一起。确保骨架在顶部。看起来您的代码目前同时将骨架和彩色图像写入&#34; videoimage&#34;,这就是为什么它不断被写入。