Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Kinect for Windows v2深度到彩色图像未对齐_C++_Opencv_Kinect_Kinect Sdk - Fatal编程技术网

C++ Kinect for Windows v2深度到彩色图像未对齐

C++ Kinect for Windows v2深度到彩色图像未对齐,c++,opencv,kinect,kinect-sdk,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

目前,我正在为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*)深度图像数据,cDepthWidth*cDepthHeight,m_pColorCoordinates);
rgbd_im=cv::Mat::zeros(深度_im.rows,深度_im.cols,cv_8UC3);
双最小值,最大值;
cv::minMaxLoc(深度、最小值和最大值);
for(int i=0;i=0)和&(colorX=0)和&(colorY
有人知道如何解决这个问题吗?如何防止这种重复

提前谢谢

更新:

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


这或多或少是我所期望的,而且背景中没有重复的手。有没有办法防止在背景中出现重复的手牌?

我建议您使用BodyIndexFrame来识别特定值是否属于某个玩家。这样,您可以拒绝任何不属于播放器的RGB像素,并保留其余像素。我不认为协调人在撒谎

请注意:

  • 将BodyIndexFrame源包括到帧读取器中
  • 使用MapColorFrameToDephspace而不是MapDepthFrameToColorSpace;这样,您将获得前景的高清图像
  • 查找相应的DepthSpacePoint和depthX,depthY,而不是ColorSpacePoint和colorX,colorY
下面是我在帧到达时的方法(它是C#):

请注意_depthPoints数组的大小为1920x1080


再次强调,最重要的是使用BodyIndexFrame源代码。

最后我有时间写下期待已久的答案

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

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

在这里,
u
v
是RGB相机图像平面中的坐标。等式右侧的第一个矩阵是摄影机矩阵,也称为RGB摄影机的内部矩阵。以下矩阵是外部对象的旋转和平移,或者更好地说,是从深度摄影机坐标系到RGB摄影机坐标系所需的变换。最后一部分是3D点

基本上,Kinect SDK就是这样做的。那么,是什么导致了手的复制呢?实际上,不止一个点投影到同一个像素

换言之,在问题的背景下

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

现在,一个大问题是,如何避免这种情况……嗯,我不确定是否使用Kinect SDK,因为在应用外部特性后,您不知道点的Z值,因此不可能使用类似的技术……但是,您可以假设Z值非常相似,并使用原始点云中的Z值(风险自负)

如果是手动操作,而不是使用SDK,则可以将外部对象应用于点,并使用“投影”将其投影到图像平面,在另一个矩阵中标记哪个点映射到哪个像素,如果已有一个点已映射,则检查z值并对其进行比较,并始终将最近的点保留到摄影机a、 然后,您将拥有一个没有任何问题的有效映射。这种方法有点幼稚,可能您可以得到更好的映射,因为问题现在已经很清楚了:)

我希望这足够清楚

附言:
我目前没有Kinect 2,因此我无法尝试查看是否有与此问题相关的更新,或者是否仍在发生相同的事情。我使用了SDK的第一个发布版本(不是预发布版)…因此,可能发生了很多更改…如果有人知道此问题是否已解决,请留下评论:)

此映射来自何处?很可能您必须编辑深度图像和彩色图像之间的校准,因为预定义并不完美。因此,您必须执行自己的校准。看一看:它来自kinect SDK v2。我希望使用固件/SDK中的一个,该固件/SDK使用相机的内核来进行此计算
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);
                }
            }

        }
    }
}
depthFrame.CopyFrameDataToArray(_depthData);
colorFrame.CopyConvertedFrameDataToArray(_colorData, ColorImageFormat.Bgra);
bodyIndexFrame.CopyFrameDataToArray(_bodyData);

_coordinateMapper.MapColorFrameToDepthSpace(_depthData, _depthPoints);

Array.Clear(_displayPixels, 0, _displayPixels.Length);

for (int colorIndex = 0; colorIndex < _depthPoints.Length; ++colorIndex)
{
    DepthSpacePoint depthPoint = _depthPoints[colorIndex];

    if (!float.IsNegativeInfinity(depthPoint.X) && !float.IsNegativeInfinity(depthPoint.Y))
    {
        int depthX = (int)(depthPoint.X + 0.5f);
        int depthY = (int)(depthPoint.Y + 0.5f);

        if ((depthX >= 0) && (depthX < _depthWidth) && (depthY >= 0) && (depthY < _depthHeight))
        {
            int depthIndex = (depthY * _depthWidth) + depthX;
            byte player = _bodyData[depthIndex];

            // Identify whether the point belongs to a player
            if (player != 0xff)
            {
                int sourceIndex = colorIndex * BYTES_PER_PIXEL;

                _displayPixels[sourceIndex] = _colorData[sourceIndex++];    // B
                _displayPixels[sourceIndex] = _colorData[sourceIndex++];    // G
                _displayPixels[sourceIndex] = _colorData[sourceIndex++];    // R
                _displayPixels[sourceIndex] = 0xff;                         // A
            }
        }
    }
}
BYTES_PER_PIXEL = (PixelFormats.Bgr32.BitsPerPixel + 7) / 8;

_colorWidth = colorFrame.FrameDescription.Width;
_colorHeight = colorFrame.FrameDescription.Height;
_depthWidth = depthFrame.FrameDescription.Width;
_depthHeight = depthFrame.FrameDescription.Height;
_bodyIndexWidth = bodyIndexFrame.FrameDescription.Width;
_bodyIndexHeight = bodyIndexFrame.FrameDescription.Height;
_depthData = new ushort[_depthWidth * _depthHeight];
_bodyData = new byte[_depthWidth * _depthHeight];
_colorData = new byte[_colorWidth * _colorHeight * BYTES_PER_PIXEL];
_displayPixels = new byte[_colorWidth * _colorHeight * BYTES_PER_PIXEL];
_depthPoints = new DepthSpacePoint[_colorWidth * _colorHeight];