• 在显示彩色影像和深度影像时最好使用WriteableBitmap对象;
  • 要想将骨骼数据影像和深度影像,或者彩色影像叠加到一起,首先要确定深度影像的分辨率和大小,为了方便,这里将深度影像数据和彩色影像数据都采用640x480Fps30的格式,同时将Grid的大小也设置为640*480。
  • 要将骨骼数据和深度影像数据叠加,需要将关节点转换到深度影像所在空间中,可以直接调用MapSkeletonPointToDepthPoint,如果要将骨骼数据叠加到彩色影像上,只需要调用MapSkeletonPointToColorPoint方法。

前端代码

界面很简单,在Grid对象下面有两个Image对象,和一个嵌套的Grid对象。前面两个Image对象分别用来显示彩色影像数据和深度影像数据,后面的Grid对象是用来绘制骨骼的,需要注意的是Grid对象的属性要设置为Transparent,这样的话就可以将Grid上绘制骨骼而不会遮住下面的彩色影像或者深度影像了。


后台代码

public partial class MainWindow : Window
{
private KinectSensor kinectDevice;
private readonly Brush[] skeletonBrushes;//绘图笔刷 private WriteableBitmap depthImageBitMap;
private Int32Rect depthImageBitmapRect;
private Int32 depthImageStride;
private DepthImageFrame lastDepthFrame; private WriteableBitmap colorImageBitmap;
private Int32Rect colorImageBitmapRect;
private int colorImageStride;
private byte[] colorImagePixelData; private Skeleton[] frameSkeletons; public MainWindow()
{
InitializeComponent(); skeletonBrushes = new Brush[] { Brushes.Red }; KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
this.KinectDevice = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
} public KinectSensor KinectDevice
{
get { return this.kinectDevice; }
set
{
if (this.kinectDevice != value)
{
//Uninitialize
if (this.kinectDevice != null)
{
this.kinectDevice.Stop();
this.kinectDevice.SkeletonFrameReady -= kinectDevice_SkeletonFrameReady;
this.kinectDevice.ColorFrameReady -= kinectDevice_ColorFrameReady;
this.kinectDevice.DepthFrameReady -= kinectDevice_DepthFrameReady;
this.kinectDevice.SkeletonStream.Disable();
this.kinectDevice.DepthStream.Disable();
this.kinectDevice.ColorStream.Disable();
this.frameSkeletons = null;
} this.kinectDevice = value; //Initialize
if (this.kinectDevice != null)
{
if (this.kinectDevice.Status == KinectStatus.Connected)
{
this.kinectDevice.SkeletonStream.Enable();
this.kinectDevice.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
this.kinectDevice.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
this.frameSkeletons = new Skeleton[this.kinectDevice.SkeletonStream.FrameSkeletonArrayLength];
this.kinectDevice.SkeletonFrameReady += kinectDevice_SkeletonFrameReady;
this.kinectDevice.ColorFrameReady += kinectDevice_ColorFrameReady;
this.kinectDevice.DepthFrameReady += kinectDevice_DepthFrameReady;
this.kinectDevice.Start(); DepthImageStream depthStream = kinectDevice.DepthStream;
depthStream.Enable(); depthImageBitMap = new WriteableBitmap(depthStream.FrameWidth, depthStream.FrameHeight, , , PixelFormats.Gray16, null);
depthImageBitmapRect = new Int32Rect(, , depthStream.FrameWidth, depthStream.FrameHeight);
depthImageStride = depthStream.FrameWidth * depthStream.FrameBytesPerPixel; ColorImageStream colorStream = kinectDevice.ColorStream;
colorStream.Enable();
colorImageBitmap = new WriteableBitmap(colorStream.FrameWidth, colorStream.FrameHeight,
, , PixelFormats.Bgr32, null);
this.colorImageBitmapRect = new Int32Rect(, , colorStream.FrameWidth, colorStream.FrameHeight);
this.colorImageStride = colorStream.FrameWidth * colorStream.FrameBytesPerPixel;
ColorImage.Source = this.colorImageBitmap; DepthImage.Source = depthImageBitMap;
}
}
}
}
} void kinectDevice_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame != null)
{
short[] depthPixelDate = new short[depthFrame.PixelDataLength];
depthFrame.CopyPixelDataTo(depthPixelDate);
depthImageBitMap.WritePixels(depthImageBitmapRect, depthPixelDate, depthImageStride, );
}
}
} void kinectDevice_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, );
}
}
} void kinectDevice_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame frame = e.OpenSkeletonFrame())
{
if (frame != null)
{
Polyline figure;
Brush userBrush;
Skeleton skeleton; LayoutRoot.Children.Clear();
frame.CopySkeletonDataTo(this.frameSkeletons); for (int i = ; i < this.frameSkeletons.Length; i++)
{
skeleton = this.frameSkeletons[i]; if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
{
userBrush = this.skeletonBrushes[i % this.skeletonBrushes.Length]; //绘制头和躯干
figure = CreateFigure(skeleton, userBrush, new[] { JointType.Head, JointType.ShoulderCenter, JointType.ShoulderLeft, JointType.Spine,
JointType.ShoulderRight, JointType.ShoulderCenter, JointType.HipCenter
});
LayoutRoot.Children.Add(figure); figure = CreateFigure(skeleton, userBrush, new[] { JointType.HipLeft, JointType.HipRight });
LayoutRoot.Children.Add(figure); //绘制作腿
figure = CreateFigure(skeleton, userBrush, new[] { JointType.HipCenter, JointType.HipLeft, JointType.KneeLeft, JointType.AnkleLeft, JointType.FootLeft });
LayoutRoot.Children.Add(figure); //绘制右腿
figure = CreateFigure(skeleton, userBrush, new[] { JointType.HipCenter, JointType.HipRight, JointType.KneeRight, JointType.AnkleRight, JointType.FootRight });
LayoutRoot.Children.Add(figure); //绘制左臂
figure = CreateFigure(skeleton, userBrush, new[] { JointType.ShoulderLeft, JointType.ElbowLeft, JointType.WristLeft, JointType.HandLeft });
LayoutRoot.Children.Add(figure); //绘制右臂
figure = CreateFigure(skeleton, userBrush, new[] { JointType.ShoulderRight, JointType.ElbowRight, JointType.WristRight, JointType.HandRight });
LayoutRoot.Children.Add(figure);
}
}
}
}
} private Polyline CreateFigure(Skeleton skeleton, Brush brush, JointType[] joints)
{
Polyline figure = new Polyline(); figure.StrokeThickness = ;
figure.Stroke = brush; for (int i = ; i < joints.Length; i++)
{
figure.Points.Add(GetJointPoint(skeleton.Joints[joints[i]]));
} return figure;
} private Point GetJointPoint(Joint joint)
{
CoordinateMapper cm = new CoordinateMapper(kinectDevice); DepthImagePoint point = cm.MapSkeletonPointToDepthPoint(joint.Position, this.KinectDevice.DepthStream.Format);
//ColorImagePoint point = cm.MapSkeletonPointToColorPoint(joint.Position, this.KinectDevice.ColorStream.Format);
point.X *= (int)this.LayoutRoot.ActualWidth / KinectDevice.DepthStream.FrameWidth;
point.Y *= (int)this.LayoutRoot.ActualHeight / KinectDevice.DepthStream.FrameHeight; return new Point(point.X, point.Y);
} private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch (e.Status)
{
case KinectStatus.Initializing:
case KinectStatus.Connected:
case KinectStatus.NotPowered:
case KinectStatus.NotReady:
case KinectStatus.DeviceNotGenuine:
this.KinectDevice = e.Sensor;
break;
case KinectStatus.Disconnected:
//TODO: Give the user feedback to plug-in a Kinect device.
this.KinectDevice = null;
break;
default:
//TODO: Show an error state
break;
}
} }

Kinect 开发 —— 骨骼数据与彩色影像和深度影像的对齐的更多相关文章

  1. Kinect 开发 —— 骨骼追踪(下)

    Kinect 连线游戏 在纸上将一些列数字(用一个圆点表示)从小到大用线连起来.游戏逻辑很简单,只不过我们在这里要实现的是动动手将这些点连起来,而不是用笔或者鼠标. 在开始写代码之前,需要明确定义我们 ...

  2. Kinect 开发 —— 骨骼追踪

    骨骼追踪技术通过处理景深数据来建立人体各个关节的坐标,骨骼追踪能够确定人体的各个部分,如那部分是手,头部,以及身体.骨骼追踪产生X,Y,Z数据来确定这些骨骼点.骨骼追踪系统采用的景深图像处理技术使用更 ...

  3. Kinect 开发 —— 骨骼追踪进阶(上)

    Kinect传感器核心只是发射红外线,并探测红外光反射,从而可以计算出视场范围内每一个像素的深度值.从深度数据中最先提取出来的是物体主体和形状,以及每一个像素点的游戏者索引信息.然后用这些形状信息来匹 ...

  4. Kinect 开发 —— 骨骼追踪 (下)

    基于景深数据的用户交互 骨骼数据中关节点不仅有X,Y值,还有一个深度值 除了使用WPF的3D特性外,在布局系统中可以根据深度值来设定可视化元素的尺寸大小来达到某种程序的立体效果. 下面的例子使用Can ...

  5. Kinect开发文章目录

    整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...

  6. Kinect 开发 —— 杂一

    Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime ...

  7. Kinect 开发 —— 近距离探测

    如何将Kinect设备作为一个近距离探测传感器.为了演示这一点,我们处理的场景可能在以前看到过.就是某一个人是否站在Kinect前面,在Kinect前面移动的是人还是什么其他的物体.当我们设置的触发器 ...

  8. Kinect SDK(1):读取彩色、深度、骨骼信息并用OpenCV显示

    Kinect SDK 读取彩色.深度.骨骼信息并用OpenCV显示 一.原理说明 对于原理相信大家都明白大致的情况,因此,在此只说比较特别的部分. 1.1 深度流数据: 深度数据流所提供的图像帧中,每 ...

  9. Kinect开发学习笔记之(一)Kinect介绍和应用

    Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...

随机推荐

  1. 隐私:随机选择 MAC 地址

    隐私:随机选择 MAC 地址 从 Android 8.0 开始,Android 设备在未连接到网络的情况下探测新网络时会使用随机 MAC 地址. 在 Android 9 中,您可以启用开发者选项(默认 ...

  2. vue中的分页操作

    首先,先看分页的代码: 这里还需要进行操作: 1.分页操作主要传递俩个数据,total和pagenum,一个显示当前页面共有多少条数据,一个是翻页后的操作,看列表的数据能不能跟着改变,在进页面发送请求 ...

  3. Dia Diagram Editor(流程图、UML)免费开源绘图软件

    近期工作各种繁忙,导致很少分享自己喜欢和常用的一些工具,今天有点时间再次给各位喜欢开源的小伙伴介绍一个好用.免费.开源的软件Dia Diagram Editor. 首先给大家看看这个软件的主界面吧! ...

  4. HNU 12886 Cracking the Safe 二十四点的判断

    经典的一个题,今天竟然写跪了…… 题意: 给你4个数字,让你判断是否能通过四则运算和括号,凑成24点. 思路: 暴力枚举运算顺序和运算符. 代码: #include <iostream> ...

  5. WHU 1542 Countries (floyd)

    题意: 在小明出生的星球X上有n国家. 一些国家通过结盟而拥有良好的双边关系,因此他们的公民得益于这些政策,使得所有这些国家之间的旅行变得免费. 但是,不同联盟之间的旅行就不是这么容易了.如果可能,它 ...

  6. SPOJ 694 Distinct Substrings

    Distinct Substrings Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on SPOJ. O ...

  7. python的开发工具UliPad安装篇

    之前文章里写过一个搭建windows下搭建Selenium+Eclipse+Python环境,如今认为这个Eclipse太大了,太笨重了,重新启动又慢,像Python脚本轻级语言,不是必需用那么大的工 ...

  8. mysql---union的使用方法

    union的作用非常easy用来合并两条sql的结果集 语法: SQL1 UNION SQL2 现有一张价格表 要求:求出价格低于2000和价格高于3000的商品.不能用or和not between- ...

  9. 轻松python专题--文本

    基础篇:(取材于零基础学python) 7.1 python中的字符串简单介绍与经常使用函数 7.2 字符串常量 7.3 字符串的一般使用 7.4 改动字符串实例 7.5 文本解析 7.6 字符串格式 ...

  10. 20.发送http请求服务 ($http)

    转自:https://www.cnblogs.com/best/tag/Angular/ 服务从代码直接与服务器进行交互,底层是通过实现,与中http服务从AngularJS代码直接与Web服务器进行 ...