最近在做一个Unity+Kinect 的项目,因为涉及一些姿势的识别,所以要锁定一个识别的骨架,但是用户怎么知道我锁定的骨架是谁呢?于是想到一个方法,那就是把当前的锁定的骨架的对象的头部图片展示出来,那么这样用户就知道当前检测的是谁啦~
话不多说,先展示一下demo,最终的一个展示效果~
有了这个想法,那么我们就来开始动手做吧,查找了一些资料,但是一输入关键词头部或者face什么的都是一些Unity的面部检测的相关内容,但是我只是想把头部的彩色图像从ColorView中抠出来而已啊,而且,我的项目最终是需要戴Oculus的,所以面部检测的话,估计最后带上那么大的Oculus也识别不出来。于是乎,突然想到Unity的开发者包里面有一个GreenScreen的项目,但是那个导入貌似有问题…于是乎去解决一下问题,然后再来研究一些那个项目是干嘛的…
对于GreenScreen的导入之后的错误,我们只要更改一下Shader的一处变量就好啦~
然后,我们运行这个程序,你会发现它其实是把检测到的人的部分显示在屏幕上,而其他的部分全部用绿色填充,这也就是为什么叫做GreenScreen吧…
我们来分析一下这个代码:CoordinateMapperManager和CoordinateMapperView。
浏览一遍代码之后,它的实现流程是这样的,利用Kinect的MultiSourceFrameReader读取Kinect的彩色图像,深度图像和BodyIdex,注意,这个BodyIndex不是Body,它不包含骨骼的信息,它是一个和kinect 深度图像等大的一个数组,如果你用texture展示出来它的话,你会得到一个身体的轮廓【如果你想查看一下这个轮廓的话,可以在CoordinateMapperManager里面更改一个texture的声明:m_pColorRGBX = new Texture2D(cDepthWidth,cDeapthHeight,TextureFormat.BC4,false) ,然后在ProcessFrame函数里面更改一下材质的填充语句为m_pColorRGBX.LoadRawTextureData(pBodyIndexBuffer),然后运行的话,你就应该可以看到一个红色的人的轮廓图像】
额,说的有点多,我就不在这里分析代码了,就是说一下实现,他这个例子的实现过程是:采集到图像的数据,然后把深度图像的数据以及BodyIndex的数据作为类似掩码的一个功能,在Shader里面片元着色器渲染的时候,判断当前的像素时候是需要渲染的状态,是的话,就渲染,不是的话就渲染成绿色,大体上讲有点类似于PS的模板的功能。
这里是例子Shader的片元着色器的部分代码:
所以呢,我也就想到了,那我也做一个“模板”啊,于是呢,在做之前,我们要想一想具体的过程是怎么样的?
我这里的流程是:
1. 选取Kinect最近骨架的Head和SpineShoulder两个节点,作为计算展示的区域。
2. 把骨骼的Camera坐标映射到彩色图片的坐标
3. 计算出末班数组的内容(这里0表示不渲染,1表示渲染)
4. Shader片元着色器渲染材质
嗯,好下面就开始编写代码创建一个与BodySourceView类似的MineBodySourceView脚本,首先根据判断当前检测到的骨架的远近,拿出来距离最近的骨架的bodytrackid。
//get the nearest body
float near_Z = 5;
foreach (var body in data) {
if (body == null)
{
continue;
}
if (body.IsTracked) {
if (body.Joints [Kinect.JointType.SpineMid].Position.Z < near_Z) {
nearest_body = body.TrackingId;
near_Z = body.Joints [Kinect.JointType.SpineMid].Position.Z;
}
}
}
然后,根据对应骨架的头部和肩膀中部的坐标,计算显示区域的大小。
private void RefreshBodyObject(Kinect.Body body, GameObject bodyObject)
{
for (Kinect.JointType jt = Kinect.JointType.SpineBase; jt <= Kinect.JointType.ThumbRight; jt++)
{
Kinect.Joint sourceJoint = body.Joints[jt];
Kinect.Joint? targetJoint = null;
if(_BoneMap.ContainsKey(jt))
{
targetJoint = body.Joints[_BoneMap[jt]];
}
Transform jointObj = bodyOb