【问题标题】:Kinect SDK: align depth and color framesKinect SDK:对齐深度和颜色帧
【发布时间】:2013-04-02 21:54:51
【问题描述】:

我正在使用 Kinect 传感器,我正在尝试对齐深度和颜色帧,以便我可以将它们保存为“适合”彼此的图像。我花了很多时间浏览 msdn 论坛和 Kinect SDK 的简陋文档,但我一无所获。

基于此答案:Kinect: Converting from RGB Coordinates to Depth Coordinates

我有以下函数,其中depthData 和colorData 是从NUI_LOCKED_RECT.pBits 获得的,mappedData 是包含新色框的输出,映射到深度坐标:

bool mapColorFrameToDepthFrame(unsigned char *depthData, unsigned char* colorData, unsigned char* mappedData)
{
    INuiCoordinateMapper* coordMapper;

    // Get coordinate mapper
    m_pSensor->NuiGetCoordinateMapper(&coordMapper);

    NUI_DEPTH_IMAGE_POINT* depthPoints = new NUI_DEPTH_IMAGE_POINT[640 * 480];

    HRESULT result = coordMapper->MapColorFrameToDepthFrame(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, 640 * 480, reinterpret_cast<NUI_DEPTH_IMAGE_PIXEL*>(depthData), 640 * 480, depthPoints);
    if (FAILED(result))
    {
        return false;
    }    

    int pos = 0;
    int* colorRun = reinterpret_cast<int*>(colorData);
    int* mappedRun = reinterpret_cast<int*>(mappedData);

    // For each pixel of new color frame
    for (int i = 0; i < 640 * 480; ++i)
    {
        // Find the corresponding pixel in original color frame from depthPoints
        pos = (depthPoints[i].y * 640) + depthPoints[i].x;

        // Set pixel value if it's within frame boundaries
        if (pos < 640 * 480)
        {
            mappedRun[i] = colorRun[pos];
        }
    }

    return true;
}

运行此代码时,我得到的只是一个未更改的颜色框,其中删除了(白色)depthFrame 没有信息的所有像素。

【问题讨论】:

  • 您是否查看过 Kinect for Windows 编码示例中的绿屏示例? kinectforwindows.codeplex.com。它对齐颜色和深度。
  • 是的,我有。它不使用新的INuiCoordinateMapper,而是使用旧的方法INuiSensor::NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution。我已经尝试过了,它对我也不起作用(我得到了全白图像)。不知何故,他们得到的深度值数组是 USHORT(16 位)而我的是 32 位,可能的原因是我用不同的参数初始化了我的 Kinect 传感器(只有深度没有玩家索引)。即使我从 32 位创建一个 16 位深度值的数组,该函数对我也不起作用。
  • 类似的事情在这里解决了:stackoverflow.com/a/19905805/2521214 Kinect SDK 具有对齐图像的功能,但它们根本不适合我(有一个非常旧版本的 kinect)所以我自己做了.. . 在那个链接中是我的 kinect 校准数据,你必须自己测量
  • @Spektre 这不是一回事,因为那里的视图是由同一个相机拍摄的。无法精确地将 RGB 映射到深度,因为图像是从不同的视点拍摄的,因此甚至可能看不到相同的东西(想象在相机之间夹着一张纸 - 每个相机都会看到纸的另一面并且无论如何都无法与其他视图对齐)。这通过相机校准和重投影解决了“远离相机”的物体,这不是一个简单的问题(但解决起来很有趣)。我建议使用 SDK 中的函数(在下面的帖子中提到)。
  • 你找到了一个好的答案吗?

标签: c++ image-processing kinect kinect-sdk


【解决方案1】:

首先,您必须校准您的设备。 这意味着,您应该校准 RGB 和 IR 传感器,然后找到 RGB 和 IR 之间的转换。 一旦你知道了这些信息,你就可以应用这个函数了:

RGBPoint = RotationMatrix * DepthPoint + TranslationVector

查看 OpenCV 或 ROS 项目以获取更多详细信息。

Extrinsic Calibration

Intrinsic Calibration

【讨论】:

【解决方案2】:

我认为在您的代码中有不同的不正确的行。

首先,您将哪种深度图传递给您的函数?

深度数据使用两个字节存储每个值,这意味着您应该为深度数据使用正确的指针类型 是 无符号短。

第二点是,据我了解,您想将深度框架映射到颜色框架,因此您拥有的正确功能 从 kinect sdk 调用是 MapDepthFrameToColorFrame 而不是 MapColorFrameToDepthFrame。

最后,该函数将返回一个点图,对于位置 [i] 处的每个深度数据,您拥有该点应位于的位置 x 和位置 y 被映射。
为此,您 不需要 colorData 指针。

所以你的函数应该修改如下:

/** Method used to build a depth map aligned to color frame
    @param [in]  depthData    : pointer to your data;
    @param [out] mappedData   : pointer to your aligned depth map;
    @return true if is all ok : false whene something wrong
*/

bool DeviceManager::mapColorFrameToDepthFrame(unsigned short *depthData,  unsigned short* mappedData){
    INuiCoordinateMapper* coordMapper;
    NUI_COLOR_IMAGE_POINT* colorPoints = new NUI_COLOR_IMAGE_POINT[640 * 480]; //color points
    NUI_DEPTH_IMAGE_PIXEL* depthPoints = new NUI_DEPTH_IMAGE_PIXEL[640 * 480]; // depth pixel

    /** BE sURE THAT YOU ARE WORKING WITH THE RIGHT HEIGHT AND WIDTH*/  
    unsigned long refWidth = 0;
    unsigned long refHeight = 0;
    NuiImageResolutionToSize( NUI_IMAGE_RESOLUTION_640x480, refWidth, refHeight );
    int width  = static_cast<int>( refWidth  ); //get the image width in a right way
    int height = static_cast<int>( refHeight ); //get the image height in a right way

    m_pSensor>NuiGetCoordinateMapper(&coordMapper); // get the coord mapper
    //Map your frame;
    HRESULT result = coordMapper->MapDepthFrameToColorFrame( NUI_IMAGE_RESOLUTION_640x480, width * height, depthPoints, NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, width * height, colorPoints );
    if (FAILED(result))
       return false;

    // apply map in terms of x and y (image coordinates);
    for (int i = 0; i < width * height; i++)
       if (colorPoints[i].x >0 && colorPoints[i].x < width && colorPoints[i].y>0 &&    colorPoints[i].y < height)
            *(mappedData + colorPoints[i].x + colorPoints[i].y*width) = *(depthData + i );

    // free your memory!!!
    delete colorPoints;
    delete depthPoints;
    return true;
}



确保您的 mappedData 已以正确的方式初始化,例如如下所示。

mappedData = (USHORT*)calloc(width*height, sizeof(ushort));


请记住,kinect sdk 不提供颜色和深度数据之间的准确对齐功能。

如果您想要两个图像之间的准确对齐,您应该使用校准模型。 在这种情况下,我建议您使用基于 Heikkilä 校准模型的 Kinect 校准工具箱。

您可以在以下链接中找到它:
http://www.ee.oulu.fi/~dherrera/kinect/.

【讨论】:

    【解决方案3】:

    我认为问题在于您正在调用 MapColorFrameToDepthFrame,而实际上您应该调用 MapDepthFrameToColorFrame。

    确凿证据就是这行代码:

    mappedRun[i] = colorRun[pos];
    

    从pos 读取和写入i 是反向的,因为pos = depthPoints[i] 表示与i 处的颜色坐标对应的深度坐标。您实际上想要迭代写入所有 depth 坐标并从相应 color 坐标处的输入彩色图像中读取。

    【讨论】:

      【解决方案4】:

      这可能不是您希望的快速答案,但此转换已在 openFrameworks (see here) 的 ofxKinectNui 插件中成功完成。

      看起来ofxKinectNui 委托给GetColorPixelCoordinatesFromDepthPixel 定义的here 函数。

      【讨论】:

        【解决方案5】:

        使用 OpenNI 框架有一个选项调用注册。

        IMAGE_REGISTRATION_DEPTH_TO_IMAGE – 将深度图像转换为与 RGB 图像具有相同的明显有利位置。

        OpenNI 2.0 和 Nite 2.0 可以很好地捕获 Kinect 信息,并且有很多教程。

        你可以看看这个:

        Kinect with OpenNI

        OpenNi 在 SimplerViewer 中有一个合并深度和颜色的示例,也许您可​​以看看并尝试一下。

        【讨论】:

          猜你喜欢
          • 2013-08-05
          • 1970-01-01
          • 1970-01-01
          • 2013-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多