在基于unity引擎扩展开发Kinect功能时,经常会使用到的就是测试人体的身高,其中有一个脚本BodySlicer里面已经有一个取得身高参数的方法GetUserHeightParams(Vector2 pointSpineBase),我们找到这个方法看到前面一段代码:
for (int i = 0, x = 0, y = 0; i < depthLength; i++)
{
if (sensorData.bodyIndexImage[i] == userBodyIndex)
{
//if (posTop.y > y)
posTop = new Vector2(x, y);
Debug.Log(posTop + " xxx" + sensorData.bodyIndexImage[i] + " " + "i:" + i);
break;
}
x++;
if (x >= depthWidth)
{
x = 0;
y++;
}
这一段代码已经意思是选出人所在像素点的最高点,然后就完成了我们的标题内容
如果是这样的,那就没意思了,其实在大部分情况下这种方法得到的数据一般是不稳定的,因为环境的干扰,你的头顶上还有一些像素点被默认为是你人的像素点,这就意味着,数据总是比实际值高很多,我们需要优化上面的这种方法,得到更为精准的值。
原理
我发现在人的上面的一些像素点是比较离散稀少的:
画中有点夸张,实际上人上面没有这么多的像素(系统默认为人的像素),在上面的方法基础上,我们需要筛选出一个像素值是不是真的是人体的,当系统选定了一个值Value之后,我们以这个值为圆心,做一个半径为20(自己视情况定制)的半圆(我们不需要上半部分啊)
接下来我们需要看看有多少点在这个范围内部,如果有很多我们就定义Value是我们的需求值,那么我们就没必要继续后面的遍历了,break循环,并且将这一帧的Value保存在sliceData.startDepthPoint参数里;如果不是呢,继续循环,直到找到一个在人像素上且是最高点的像素点。
半圆的绘制
圆的公式:(x-a)²+(y-b)²=r²,如果X∈[-r+a,r+a],y∈[b,b+r]. 这里的就表明这是一个半圆,所以你的条件判断应当是(x-a)²+(y-b)²<r²,且在上面的两域内。
关于坐标
我们的是笛卡尔坐标系的关于x轴的翻转,也就是说x轴还是------>这样的,但y轴是正方向向下的,所以这是上面半圆的y是b+r的原因。
关于像素点的表述
像素点是用坐标来表示的(x,y)这种形式,Kinect V2的深度图的像素是512x424,所以总的点应该会有217088个,sensorData.bodyIndexImage[i]这里面出现了一个i值,这个i就是关于这个点数的描述,这个描述的公式通过推理出来应该是: i=y*depthWidth+x ,因为当x遍历了424之后y就会+1,所以就是这样了。
if (sensorData.bodyIndexImage[i] == userBodyIndex)
{
//做圆心,在这个圆心的周围画一个半圆,看看有多少值在这个范围内
//如果是因为摄像头偏差导致的非人体像素,其周围的像素点一定没有人的密集
//由此来测量这个是不是人体的像素点
Vector2 value = new Vector2(x, y);
int count = 0; //记录有多少个点满足条件
for (int ver = 0; ver < 10; ver++)
{
for (int hor = -10; hor < 10; hor++)
{
if (Mathf.Pow((hor + value.x) - value.x, 2) + Mathf.Pow((ver + value.y) - value.y, 2) < 400)
{
int zyIndex = (ver + (int)value.y) * depthWidth + (hor + (int)value.x);
if (sensorData.bodyIndexImage[zyIndex] == userBodyIndex)
{
count++;
}
}
}
}
Debug.Log(count + "半圆的点数");
if (count > 100)
{
Debug.Log(count + "大于100的半圆的点数");
posTop = value; //这是一个在人上的点
Debug.Log(posTop + " xxx" + sensorData.bodyIndexImage[i] + " " + "当前像素点i:"+i);
break;
}
else continue;
}
x++;
if (x >= depthWidth) //zy:当超出了屏幕像素所能容纳的最大范围时跳到下一y坐标,x从0继续增加
{
x = 0;
y++; //y值会从0开始增加
}
}
这样你就测出了一个比较精准的人体像素的最高点 topPiexl
总结
环境原因导致Kinect捕捉的深度图在高于人的上方点出现了被系统误认为是人的像素点的情况,我用了一种范围加点法来测出我们系统给我们找的点是不是属于人身上的最高像素点。首先刻画了一个半圆,在半圆的范围内找出有多少个是属于人身上的点,超过了100个时,我们就默认当前的点是这一帧里人所在的最高像素点。