Kinect raw depth to distance in meters

谁说胖子不能爱 提交于 2019-11-27 09:20:52

The correct answer is actually a comment on your question. The number given is actually a distance in millimetres. To get this number, you either need to use a skeleton joint and call DepthImageFrame's MapFromSkeletonPoint or shift the raw short value right by DepthImageFrame.PlayerIndexBitmaskWidth.

E.g. Skeleton

using (var skeletonFrame= e.OpenSkeletonFrame())
using (var depthFrame = e.OpenDepthImageFrame())
{
    skeletonFrame.CopySkeletonDataTo(skeletons);
    var skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];

    foreach (var skeleton in skeletons)
    {
            if (skeleton.TrackingState != SkeletonTrackingState.Tracked) continue;

            var head = skeleton.Joints[JointType.Head];
            if (head.TrackingState == JointTrackingState.NotTracked) continue;

            var depthImagePoint = depthFrame.MapFromSkeletonPoint(head.Position);

            int depthInMillimeters = depthImagePoint.Depth; // TADA!
    }
}

E.g. shift

using (var depthFrame = e.OpenDepthImageFrame())
{
    var depthArray = new short[depthFrame.PixelDataLength];
    depthFrame.CopyPixelDataTo(depthArray);

    for (int i = 0; i < depthArray.Length; i++) {
        int depthInMillimeters = 
            depthArray[i] >> DepthImageFrame.PlayerIndexBitmaskWidth;
        // TADAx2!
}

The original solution below is no longer correct:

Based on the contents of this article - http://openkinect.org/wiki/Imaging_Information:

if (depthValue <= 2047) {
   depthM = 0.1236 * Math.Tan(depthValue / 2842.5 + 1.1863);
}

old inactive question but anyway here is what worked for me I have an old model of kinect (1414 for XBOX360 + PC reduction) and recently had time to make some code and measurements:

  1. my raw data is 16 bit not 10/11/12/13 bit !!!

    so probably your data is very similar. Min distance measured is ~0.95m max distance unknown (have not big enough area for testing) and min valid value is 6408 ... ~0.95m from sensor . Another valid value is 15800 ... ~2.5m from sensor for interpolation

  2. naive (linear) transformation to meters

    float z,m=(2.5-0.9)/(15800.0-6408.0);
    WORD raw;
    
    raw=... raw depth form camera/image;
    z=0.0;
    if ((raw>=6408)&&(raw< 0xFFF0)) 
     z=0.9+(float(raw-6408)*m);
    // here z is range in [m] or 0 for invalid depth
    
  3. when I will have more time then I will check the linearity and make it more precise

    to do that I need to make some programing for better measurement and setup working area for more precise distance measurements. More precise constants maybe add cosine correction if its needed. I do not know if device/driver make it itself or not have to measure it. When I get to it will update my answer but I am very lazy so it can be a while ...

[Edit 1] made some geometry measurement setup and code changes
so here are new more precise conclusions:

if (raw==0x0000) z=0.0;
else if (p.raw>=0x8000) p.z=4.0;
else p.z=0.8+(float(p.raw-6576)*0.00012115165336374002280501710376283);

raw data is already cosine corrected by driver or kinect itself so raw represent perpendicular distance from sensor. raw data is linear to perpendicular distance (at least on 0.8 - 2.0 m range) and after more precise measurement the depth range is <0.8 - 4.0> [m]. Measurements before was inaccurate.


raw = 0 is too close value
raw >= 32768 is too far / unknown value or even something else (there are more possibilities)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!