问题
I have a kinect project in wpf and it uses skeleton stream that tracks the left and right hand of its users and allows me to hover over buttons.
I tried making a new form and just copying and pasting everything so i can create a new page but it didnt work, i think i may have to reference the methods used in the main page, but i am unsure.
I want to be able to use the skeleton stream alongside the hovering method in a new window
Any help would be appreciated - i apologize if this does not make sense i am a beginner
Code
public partial class MainWindow : Window
{
private KinectSensor _Kinect;
private WriteableBitmap _ColorImageBitmap;
private Int32Rect _ColorImageBitmapRect;
private int _ColorImageStride;
private Skeleton[] FrameSkeletons;
List<Button> buttons;
static Button selected;
float handX;
float handY;
public MainWindow()
{
InitializeComponent();
InitializeButtons();
kinectButton.Click += new RoutedEventHandler(kinectButton_Click);
this.Loaded += (s, e) => { DiscoverKinectSensor(); };
this.Unloaded += (s, e) => { this.Kinect = null; };
}
//initialize buttons to be checked
private void InitializeButtons()
{
buttons = new List<Button> { button1, button2, quitButton};
}
//raise event for Kinect sensor status changed
private void DiscoverKinectSensor()
{
KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
this.Kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
}
private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch (e.Status)
{
case KinectStatus.Connected:
if (this.Kinect == null)
{
this.Kinect = e.Sensor;
}
break;
case KinectStatus.Disconnected:
if (this.Kinect == e.Sensor)
{
this.Kinect = null;
this.Kinect = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
if (this.Kinect == null)
{
MessageBox.Show("Sensor Disconnected. Please reconnect to continue.");
}
}
break;
}
}
public KinectSensor Kinect
{
get { return this._Kinect; }
set
{
if (this._Kinect != value)
{
if (this._Kinect != null)
{
UninitializeKinectSensor(this._Kinect);
this._Kinect = null;
}
if (value != null && value.Status == KinectStatus.Connected)
{
this._Kinect = value;
InitializeKinectSensor(this._Kinect);
}
}
}
}
private void UninitializeKinectSensor(KinectSensor kinectSensor)
{
if (kinectSensor != null)
{
kinectSensor.Stop();
kinectSensor.ColorFrameReady -= Kinect_ColorFrameReady;
kinectSensor.SkeletonFrameReady -= Kinect_SkeletonFrameReady;
}
}
private void InitializeKinectSensor(KinectSensor kinectSensor)
{
if (kinectSensor != null)
{
ColorImageStream colorStream = kinectSensor.ColorStream;
colorStream.Enable();
this._ColorImageBitmap = new WriteableBitmap(colorStream.FrameWidth, colorStream.FrameHeight,
96, 96, PixelFormats.Bgr32, null);
this._ColorImageBitmapRect = new Int32Rect(0, 0, colorStream.FrameWidth, colorStream.FrameHeight);
this._ColorImageStride = colorStream.FrameWidth * colorStream.FrameBytesPerPixel;
videoStream.Source = this._ColorImageBitmap;
kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters()
{
Correction = 0.5f,
JitterRadius = 0.05f,
MaxDeviationRadius = 0.04f,
Smoothing = 0.5f
});
kinectSensor.SkeletonFrameReady += Kinect_SkeletonFrameReady;
kinectSensor.ColorFrameReady += Kinect_ColorFrameReady;
kinectSensor.Start();
this.FrameSkeletons = new Skeleton[this.Kinect.SkeletonStream.FrameSkeletonArrayLength];
}
}
private void Kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame frame = e.OpenColorImageFrame())
{
if (frame != null)
{
byte[] pixelData = new byte[frame.PixelDataLength];
frame.CopyPixelDataTo(pixelData);
this._ColorImageBitmap.WritePixels(this._ColorImageBitmapRect, pixelData,
this._ColorImageStride, 0);
}
}
}
private void Kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame frame = e.OpenSkeletonFrame())
{
if (frame != null)
{
frame.CopySkeletonDataTo(this.FrameSkeletons);
Skeleton skeleton = GetPrimarySkeleton(this.FrameSkeletons);
if (skeleton == null)
{
kinectButton.Visibility = Visibility.Collapsed;
}
else
{
Joint primaryHand = GetPrimaryHand(skeleton);
TrackHand(primaryHand);
}
}
}
}
//track and display hand
private void TrackHand(Joint hand)
{
if (hand.TrackingState == JointTrackingState.NotTracked)
{
kinectButton.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
kinectButton.Visibility = System.Windows.Visibility.Visible;
DepthImagePoint point = this.Kinect.MapSkeletonPointToDepth(hand.Position, DepthImageFormat.Resolution640x480Fps30);
handX = (int)((point.X * LayoutRoot.ActualWidth / this.Kinect.DepthStream.FrameWidth) -
(kinectButton.ActualWidth / 2.0));
handY = (int)((point.Y * LayoutRoot.ActualHeight / this.Kinect.DepthStream.FrameHeight) -
(kinectButton.ActualHeight / 2.0));
Canvas.SetLeft(kinectButton, handX);
Canvas.SetTop(kinectButton, handY);
if (isHandOver(kinectButton, buttons)) kinectButton.Hovering();
else kinectButton.Release();
if (hand.JointType == JointType.HandRight)
{
kinectButton.ImageSource = "/Images/RightHand.png";
kinectButton.ActiveImageSource = "/Images/RightHand.png";
}
else
{
kinectButton.ImageSource = "/Images/LeftHand.png";
kinectButton.ActiveImageSource = "/Images/LeftHand.png";
}
}
}
//detect if hand is overlapping over any button
private bool isHandOver(FrameworkElement hand, List<Button> buttonslist)
{
var handTopLeft = new Point(Canvas.GetLeft(hand), Canvas.GetTop(hand));
var handX = handTopLeft.X + hand.ActualWidth / 2;
var handY = handTopLeft.Y + hand.ActualHeight / 2;
foreach (Button target in buttonslist)
{
Point targetTopLeft = new Point(Canvas.GetLeft(target), Canvas.GetTop(target));
if (handX > targetTopLeft.X &&
handX < targetTopLeft.X + target.Width &&
handY > targetTopLeft.Y &&
handY < targetTopLeft.Y + target.Height)
{
selected = target;
return true;
}
}
return false;
}
//get the hand closest to the Kinect sensor
private static Joint GetPrimaryHand(Skeleton skeleton)
{
Joint primaryHand = new Joint();
if (skeleton != null)
{
primaryHand = skeleton.Joints[JointType.HandLeft];
Joint rightHand = skeleton.Joints[JointType.HandRight];
if (rightHand.TrackingState != JointTrackingState.NotTracked)
{
if (primaryHand.TrackingState == JointTrackingState.NotTracked)
{
primaryHand = rightHand;
}
else
{
if (primaryHand.Position.Z > rightHand.Position.Z)
{
primaryHand = rightHand;
}
}
}
}
return primaryHand;
}
//get the skeleton closest to the Kinect sensor
private static Skeleton GetPrimarySkeleton(Skeleton[] skeletons)
{
Skeleton skeleton = null;
if (skeletons != null)
{
for (int i = 0; i < skeletons.Length; i++)
{
if (skeletons[i].TrackingState == SkeletonTrackingState.Tracked)
{
if (skeleton == null)
{
skeleton = skeletons[i];
}
else
{
if (skeleton.Position.Z > skeletons[i].Position.Z)
{
skeleton = skeletons[i];
}
}
}
}
}
return skeleton;
}
void kinectButton_Click(object sender, RoutedEventArgs e)
{
selected.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, selected));
}
private void button1_Click(object sender, RoutedEventArgs e)
{
message.Content = "Button 1 clicked!";
}
private void button2_Click(object sender, RoutedEventArgs e)
{
message.Content = "Button 2 clicked!";
}
private void quitButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
回答1:
You can do this in a couple of different ways, and more ways then what is below.
You could pass a reference to the sensor itself to the new window when it is created:
public MainWindow()
{
// init code for window and Kinect
// show the second window
SecondWindow mySecondWindow = new SecondWindow(_Kinect);
mySecondWindow.Show();
// other stuff...
}
public class SecondWindow : Window
{
public SecondWindow(KinectSensor sensor)
{
// ... stuff
sensor.SkeletonFrameReady += SkeletonFrameReadyCallback;
// ... more stuff
}
}
Then subscribe to the SkeletonFrameReady
callback in your second window. This might work for your situation if you are interacting with items in the seconds window.
Another way would be to create a public callback inside your second window and subscribe it to the SkeletonFrameReady
event.
public MainWindow()
{
// init code for window and Kinect
// show the second window
SecondWindow mySecondWindow = new SecondWindow(_Kinect);
mySecondWindow.Show();
_Kinect.SkeletonFrameReady += mySecondWindow.SkeletonFrameReadyCallback;
}
I also notice in your code that you are firing events. If you are wanting to act on events from one window in a different window, you can subscribe to those custom events in the same mentioned above.
来源:https://stackoverflow.com/questions/15423327/how-can-i-pass-kinect-tracking-into-another-form