【问题标题】:Why kinect color and depth won't align correctly?为什么 kinect 颜色和深度无法正确对齐?
【发布时间】:2013-08-05 16:41:01
【问题描述】:

我已经研究这个问题很长一段时间了,我的创造力已经到了尽头,所以希望其他人可以帮助我指出正确的方向。我一直在使用 Kinect 并尝试将数据捕获到 MATLAB。幸运的是,有很多方法可以做到这一点(我目前正在使用http://www.mathworks.com/matlabcentral/fileexchange/30242-kinect-matlab)。当我尝试将捕获的数据投影到 3D 时,我的传统方法的重建效果很差。

长话短说,我最终为 matlab 编写了一个 Kinect SDK 包装器,用于执行重建和对齐。重建工作就像做梦一样,但是......

正如您在此处看到的,我在对齐方面遇到了很多麻烦:

请不要看得太仔细:(。

如您所见,对齐方式不正确。我不确定为什么会这样。我读过很多论坛,其他人用同样的方法比我更成功。

我当前的管道使用 Kinect Matlab(使用 Openni)来捕获数据,使用 Kinect SDK 重建,然后使用 Kinect SDK 对齐(通过 NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution)。我怀疑这可能是因为 Openni,但我在创建 mex 函数调用以使用 Kinect SDK 进行捕获方面收效甚微。

如果有人能指出我应该更深入研究的方向,将不胜感激。

编辑:

图我应该发布一些代码。这是我用于对齐的代码:

    /* The matlab mex function */
    void mexFunction( int nlhs, mxArray *plhs[], int nrhs, 
            const mxArray *prhs[] ){

        if( nrhs < 2 )
        {
            printf( "No depth input or color image specified!\n" );
            mexErrMsgTxt( "Input Error" );
        }

        int width = 640, height = 480;

        // get input depth data

        unsigned short *pDepthRow = ( unsigned short* ) mxGetData( prhs[0] );
        unsigned char *pColorRow = ( unsigned char* ) mxGetData( prhs[1] );

        // compute the warping

        INuiSensor *sensor = CreateFirstConnected();
        long colorCoords[ 640*480*2 ];
        sensor->NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution(
                NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, 
                640*480, pDepthRow, 640*480*2, colorCoords );
        sensor->NuiShutdown();
        sensor->Release();

        // create matlab output; it's a column ordered matrix ;_;

        int Jdimsc[3];
        Jdimsc[0]=height;
        Jdimsc[1]=width;
        Jdimsc[2]=3;

        plhs[0] = mxCreateNumericArray( 3, Jdimsc, mxUINT8_CLASS, mxREAL );
        unsigned char *Iout = ( unsigned char* )mxGetData( plhs[0] );

        for( int x = 0; x < width; x++ )
            for( int y = 0; y < height; y++ ){

                int idx = ( y*width + x )*2;
                long c_x = colorCoords[ idx + 0 ];
                long c_y = colorCoords[ idx + 1 ];

                bool correct = ( c_x >= 0 && c_x < width 
                        && c_y >= 0 && c_y < height );
                c_x = correct ? c_x : x;
                c_y = correct ? c_y : y;

                Iout[ 0*height*width + x*height + y ] =
                        pColorRow[ 0*height*width + c_x*height + c_y ];
                Iout[ 1*height*width + x*height + y ] =
                        pColorRow[ 1*height*width + c_x*height + c_y ];
                Iout[ 2*height*width + x*height + y ] =
                        pColorRow[ 2*height*width + c_x*height + c_y ];

            }

    }

【问题讨论】:

  • 您应该让其他人知道您的问题的答案是否相关以及他们是否解决了您遇到的问题。如果不是那为什么?这就是这个社区的运作方式
  • 致马萨德:是的,谢谢您的回复。我还没有机会确认您的答案是否有效,但我现在正在这样做。稍后会通知您。

标签: matlab colors alignment kinect depth


【解决方案1】:

这是立体视觉系统的一个众所周知的问题。不久前我遇到了同样的问题。我发布的原始问题可以找到here。我试图做的与此类似。然而,经过大量研究,我得出结论,捕获的数据集不容易对齐。

另一方面,在记录数据集时,您可以轻松地使用函数调用来对齐 RGB 和深度数据。此方法在 OpenNI 和 Kinect SDK 中都可用(功能相同,但每个函数调用的名称不同)

您似乎正在使用 Kinect SDK 来捕获数据集,要将数据与 Kinect SDK 对齐,您可以使用 MapDepthFrameToColorFrame

既然您也提到了使用 OpenNI,请查看 AlternativeViewPointCapability

我没有使用 Kinect SDK 的经验,但是使用 OpenNI v1.5,在注册记录器节点之前,通过以下函数调用解决了整个问题:

depth.GetAlternativeViewPointCap().SetViewPoint(image);

其中image 是图像生成器节点,depth 是深度生成器节点。这是旧的 SDK 已被 OpenNI 2.0 SDK 取代。所以如果你使用的是最新的SDK,那么函数调用可能会有所不同,但总体过程可能是相似的。

我还添加了一些示例图片:

不使用上述对齐函数调用RGB上的深度边缘未对齐

当使用函数调用时,深度边缘会完美对齐(有一些红外阴影区域会显示一些边缘,但它们只是无效的深度区域)

【讨论】:

  • 感谢您的回复。我已经尝试过对齐,但没有成功。事实证明,我使用了正确的调用,但 Kinect 有一个额外的“陷阱”。在“常见的 NUI 问题和常见问题解答”(social.msdn.microsoft.com/Forums/en-US/…)中,它列出了从 Kinect 获得的深度值必须移位 3,因为玩家的索引也存储在深度值中。调整后,使用我的原始代码对齐工作正常。如果没有你的链接,我不会发现这个:)。
  • 我会将您的回复设置为答案,因为它还为对齐问题提供了重要的背景、示例和代码。
【解决方案2】:

depth.GetAlternativeViewPointCap().SetViewPoint(image);

效果很好,但问题是它缩小了深度图像(通过 FOCAL_rgb/FOCAL_kinect)并通过视差 d=focal*B/z 移动深度像素;根据出厂设置,也可能会有轻微的旋转。

因此,如果不撤消这些转换,就无法再恢复所有 3 个真实世界坐标。话虽如此,不依赖于准确的 x、y 并且仅考虑 z 的方法(例如分割)即使在移位的地图中也可能运行良好。此外,它们可以利用颜色和深度来执行更好的分割。

【讨论】:

    【解决方案3】:

    您可以通过使用 Kinect SDK 读取 U、V 纹理映射参数轻松对齐深度帧和颜色帧。对于深度帧 D(i,j) 的每个像素坐标 (i,j),颜色帧的相应像素坐标由 (U(i,j),V(i,j)) 给出,因此颜色为通过 C(U(i,j),V(i,j))。

    U、V 功能包含在每个 Kinect 的硬件中,它们因 Kinect 与 Kinect 不同而不同,因为在工厂胶合在硬件板上时,深度摄像头与视频摄像头的对齐方式不同。但是,如果您从 Kinect SDK 读取 U,V,则不必担心。

    下面我给你一个图像示例和一个实际的源代码示例,使用Java中的Kinect SDK和J4K open source library

    public class Kinect extends J4KSDK{
    
        VideoFrame videoTexture; 
    
    public Kinect() { 
        super(); 
        videoTexture=new VideoFrame(); 
    }
    
    @Override 
    public void onDepthFrameEvent(short[] packed_depth, int[] U, int V[]) { 
        DepthMap map=new DepthMap(depthWidth(),depthHeight(),packed_depth); 
        if(U!=null && V!=null) map.setUV(U,V,videoWidth(),videoHeight()); 
    } 
    
    @Override 
    public void onVideoFrameEvent(byte[] data) {     
        videoTexture.update(videoWidth(), videoHeight(), data); 
    } }
    

    显示同一深度视频对齐帧的 3 个不同视角的图像示例:

    希望对你有帮助!

    【讨论】:

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