使用 CL NUI Kinect 驱动程序,将深度颜色转换为实际相对距离

发布于 2024-10-13 11:25:41 字数 2240 浏览 4 评论 0原文

我正在使用 Kinect 驱动程序 CL NUI 并尝试获取项目的相对深度。

该库提供了一种获取表示屏幕上对象深度的图像的方法。这是一个例子:
Kinect Depth Image

有没有一种简单的方法可以将像素颜色转换为图像深度?例如,最近的颜色可能是深度 0,最远的颜色可能是深度 1。

有​​谁知道该怎么做?

我发现了这些关于如何将深度数据转换为颜色的计算,我想要的是相反的:

float RawDepthToMeters(int depthValue)
{
    if (depthValue < 2047)
    {
        return float(1.0 / (double(depthValue) * -0.0030711016 + 3.3309495161));
    }
    return 0.0f;
}

Vec3f DepthToWorld(int x, int y, int depthValue)
{
    static const double fx_d = 1.0 / 5.9421434211923247e+02;
    static const double fy_d = 1.0 / 5.9104053696870778e+02;
    static const double cx_d = 3.3930780975300314e+02;
    static const double cy_d = 2.4273913761751615e+02;

    Vec3f result;
    const double depth = RawDepthToMeters(depthValue);
    result.x = float((x - cx_d) * depth * fx_d);
    result.y = float((y - cy_d) * depth * fy_d);
    result.z = float(depth);
    return result;
}

Vec2i WorldToColor(const Vec3f &pt)
{
    static const Matrix4 rotationMatrix(
                            Vec3f(9.9984628826577793e-01f, 1.2635359098409581e-03f, -1.7487233004436643e-02f),
                            Vec3f(-1.4779096108364480e-03f, 9.9992385683542895e-01f, -1.2251380107679535e-02f),
                            Vec3f(1.7470421412464927e-02f, 1.2275341476520762e-02f, 9.9977202419716948e-01f));
    static const Vec3f translation(1.9985242312092553e-02f, -7.4423738761617583e-04f, -1.0916736334336222e-02f);
    static const Matrix4 finalMatrix = rotationMatrix.Transpose() * Matrix4::Translation(-translation);

    static const double fx_rgb = 5.2921508098293293e+02;
    static const double fy_rgb = 5.2556393630057437e+02;
    static const double cx_rgb = 3.2894272028759258e+02;
    static const double cy_rgb = 2.6748068171871557e+02;

    const Vec3f transformedPos = finalMatrix.TransformPoint(pt);
    const float invZ = 1.0f / transformedPos.z;

    Vec2i result;
    result.x = Utility::Bound(Math::Round((transformedPos.x * fx_rgb * invZ) + cx_rgb), 0, 639);
    result.y = Utility::Bound(Math::Round((transformedPos.y * fy_rgb * invZ) + cy_rgb), 0, 479);
    return result;
}

我的矩阵数学很弱,我不知道如何反转计算。

I am playing with the Kinect driver, CL NUI and trying to get the relative depth of items.

The Library provides a way to get an image representing the depth of an object on the screen. Here is an example:
Kinect Depth Image

Is there an easy way to convert from the pixel color to the images depth? For example, the closest color could be depth of 0, and the farthest color could be the depth of 1.

Does anyone know how to do that?

I found these cacluations on how to convert the depth data to color, what I want is the inverse:

float RawDepthToMeters(int depthValue)
{
    if (depthValue < 2047)
    {
        return float(1.0 / (double(depthValue) * -0.0030711016 + 3.3309495161));
    }
    return 0.0f;
}

Vec3f DepthToWorld(int x, int y, int depthValue)
{
    static const double fx_d = 1.0 / 5.9421434211923247e+02;
    static const double fy_d = 1.0 / 5.9104053696870778e+02;
    static const double cx_d = 3.3930780975300314e+02;
    static const double cy_d = 2.4273913761751615e+02;

    Vec3f result;
    const double depth = RawDepthToMeters(depthValue);
    result.x = float((x - cx_d) * depth * fx_d);
    result.y = float((y - cy_d) * depth * fy_d);
    result.z = float(depth);
    return result;
}

Vec2i WorldToColor(const Vec3f &pt)
{
    static const Matrix4 rotationMatrix(
                            Vec3f(9.9984628826577793e-01f, 1.2635359098409581e-03f, -1.7487233004436643e-02f),
                            Vec3f(-1.4779096108364480e-03f, 9.9992385683542895e-01f, -1.2251380107679535e-02f),
                            Vec3f(1.7470421412464927e-02f, 1.2275341476520762e-02f, 9.9977202419716948e-01f));
    static const Vec3f translation(1.9985242312092553e-02f, -7.4423738761617583e-04f, -1.0916736334336222e-02f);
    static const Matrix4 finalMatrix = rotationMatrix.Transpose() * Matrix4::Translation(-translation);

    static const double fx_rgb = 5.2921508098293293e+02;
    static const double fy_rgb = 5.2556393630057437e+02;
    static const double cx_rgb = 3.2894272028759258e+02;
    static const double cy_rgb = 2.6748068171871557e+02;

    const Vec3f transformedPos = finalMatrix.TransformPoint(pt);
    const float invZ = 1.0f / transformedPos.z;

    Vec2i result;
    result.x = Utility::Bound(Math::Round((transformedPos.x * fx_rgb * invZ) + cx_rgb), 0, 639);
    result.y = Utility::Bound(Math::Round((transformedPos.y * fy_rgb * invZ) + cy_rgb), 0, 479);
    return result;
}

My Matrix Math is weak, and I'm not sure how to reverse the calculations.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绾颜 2024-10-20 11:25:41

我找到了解决方案。

深度值存储在 CLNUIDevice.GetCameraDepthFrameRAW 图像中。
该图像的颜色是根据 11 位深度值创建的。 IE 中 RGB 颜色有 24 位(如果是 ARGB,则为 32 位)。为了获得深度,您需要像这样截断不必要的位:

    private int colorToDepth(Color c) {
        int colorInt = c.ToArgb();

        return (colorInt << 16) >> 16;
    }

您使用 16,因为 11 位数字在 16 位位置填充了 0。 IE 中的数字如下所示: 1111 1111 0000 0### #### #### 其中 1 是 Alpha 通道,零是填充,“#”是实际值。
对左边 16 位进行移位后,得到 0000 0### #### #### 0000 0000,你想将其向右移位 16 次: 0000 0000 0000 0### ##### ####

I found the solution.

The depth value is stored in the CLNUIDevice.GetCameraDepthFrameRAW image.
This image's color is created from the eleven bit depth value. I.E. you have 24 bits for the RGB color (32 if ARGB). To get the depth, you need to truncate the unnecessary bits like this:

    private int colorToDepth(Color c) {
        int colorInt = c.ToArgb();

        return (colorInt << 16) >> 16;
    }

You use 16, because the 11-bit number is 0 padded for the 16 bit place. I.E. you have a number that looks like this: 1111 1111 0000 0### #### #### where the 1 is the alpha channel, the zeros are the padding, and the '#' is the actual value.
Bitshifting the the left 16 leaves you with 0000 0### #### #### 0000 0000, which you want to push back my shifting to the right 16 times: 0000 0000 0000 0### ##### ####

等往事风中吹 2024-10-20 11:25:41

如果我错了,请纠正我,但据我了解,您的代码从 Kinect 接收深度数组,使用 DepthToWorld 将其转换为“世界”对象(带有 x、y、z 坐标),然后转换使用 WorldToColor 将其转换为颜色 2D 数组。由此,您尝试检索每个像素相对于 Kinect 的距离(以米为单位)。正确的?

那么为什么不直接获取从 Kinect 获得的初始深度数组,并对每个像素调用 RawDepthToMeters 函数呢?

反转代码之前完成的操作会带来巨大的性能损失......

Correct me if I'm wrong but from what I understand your code receives a depth array from the Kinect, converts it to "world" objects (with x,y,z coordinates) using DepthToWorld, then converts that to a color 2D array using WorldToColor. From that, you're trying to retrieve the distance (in meters) of each pixel relative to the Kinect. Right?

So why don't you just take the initial depth array you get from the Kinect, and call the RawDepthToMeters function on each of the pixels?

Inversing the operations done by your code just before is a huge loss of performance...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文