Kinect for Windows v2深度到彩色图像不对齐

api*_*i55 15 c++ opencv kinect kinect-sdk

目前我正在为Kinect for Windows v2开发一个工具(类似于XBOX ONE中的那个).我尝试了一些示例,并有一个工作示例,显示相机图像,深度图像,以及使用opencv将深度映射到rgb的图像.但是我看到它在进行映射时重复了我的手,我认为这是由于坐标映射器部分出了问题.

这是一个例子: 错误

这是创建图像的代码片段(示例中的rgbd图像)

void KinectViewer::create_rgbd(cv::Mat& depth_im, cv::Mat& rgb_im, cv::Mat& rgbd_im){
    HRESULT hr = m_pCoordinateMapper->MapDepthFrameToColorSpace(cDepthWidth * cDepthHeight, (UINT16*)depth_im.data, cDepthWidth * cDepthHeight, m_pColorCoordinates);
    rgbd_im = cv::Mat::zeros(depth_im.rows, depth_im.cols, CV_8UC3);
    double minVal, maxVal;
    cv::minMaxLoc(depth_im, &minVal, &maxVal);
    for (int i=0; i < cDepthHeight; i++){
        for (int j=0; j < cDepthWidth; j++){
            if (depth_im.at<UINT16>(i, j) > 0 && depth_im.at<UINT16>(i, j) < maxVal * (max_z / 100) && depth_im.at<UINT16>(i, j) > maxVal * min_z /100){
                double a = i * cDepthWidth + j;
                ColorSpacePoint colorPoint = m_pColorCoordinates[i*cDepthWidth+j];
                int colorX = (int)(floor(colorPoint.X + 0.5));
                int colorY = (int)(floor(colorPoint.Y + 0.5));
                if ((colorX >= 0) && (colorX < cColorWidth) && (colorY >= 0) && (colorY < cColorHeight))
                {
                    rgbd_im.at<cv::Vec3b>(i, j) = rgb_im.at<cv::Vec3b>(colorY, colorX);
                }
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有人知道如何解决这个问题?如何防止这种重复?

提前致谢

更新:

如果我做一个简单的深度图像阈值处理,我会得到以下图像: 阈值

这或多或少是我预期会发生的事情,并且在后台没有重复的手.有没有办法在后台防止这个重复的手?

api*_*i55 1

终于有时间写下期待已久的答案了。

让我们从一些理论开始,了解到底发生了什么,然后得出可能的答案。

我们首先应该了解如何从以深度相机为坐标系原点的 3D 点云传递到 RGB 相机图像平面中的图像。为此,使用相机针孔模型就足够了:

在此输入图像描述

这里,uv是 RGB 相机图像平面中的坐标。等式右侧的第一个矩阵是相机矩阵,又称 RGB 相机的内联矩阵。下面的矩阵是外参的旋转和平移,或者更好地说,是从深度相机坐标系到 RGB 相机坐标系所需的变换。最后一部分是 3D 点。

基本上,类似的事情就是 Kinect SDK 所做的事情。那么,什么问题会导致手牌被重复呢?好吧,实际上不止一个点投影到同一个像素......

换句话说,在问题的背景下。

深度图像是有序点云的表示,我正在查询u v其每个像素的值,这些值实际上可以轻松转换为 3D 点。SDK 为您提供了投影,但它可以指向相同的像素(通常,两个相邻点之间 z 轴上的距离越大,可能很容易出现此问题。

现在,最大的问题是,如何避免这种情况......好吧,我不确定是否使用 Kinect SDK,因为您不知道应用外部函数后点的 Z 值,因此不可能使用像Z 缓冲这样的技术......但是,您可能会假设 Z 值将非常相似并使用原始点云中的值(风险自负)。

如果您手动执行此操作,而不是使用 SDK,则可以将 Extrinsics 应用于这些点,然后使用将它们投影到图像平面中,在另一个矩阵中标记哪个点映射到哪个像素以及是否存在现有的已映射的点,检查 z 值并进行比较,并始终保留距离相机最近的点。然后,您将拥有一个有效的映射,没有任何问题。这种方法有点幼稚,也许你可以得到更好的方法,因为问题现在已经清楚了:)

我希望它足够清楚。

PS:我目前没有 Kinect 2,所以我无法尝试查看是否有与此问题相关的更新,或者是否仍然发生同样的情况。我使用了 SDK 的第一个发布版本(不是预发布版本)...所以,可能发生了很多变化...如果有人知道这是否解决了,请发表评论:)