【问题标题】:how to get depth values and then convert to millimetres in OpenCV with Kinect?如何使用 Kinect 在 OpenCV 中获取深度值然后转换为毫米?
【发布时间】:2012-05-08 10:28:34
【问题描述】:

我用 OpenCV 3.2.1 和 kniect 运行 VS2010。

我正在使用来自here的教程

int main( int argc, char* argv[] ){

VideoCapture capture(CV_CAP_OPENNI); // or CV_CAP_OPENNI
for(;;)
{
    Mat depthMap;
    Mat bgrImage;

    capture.grab();

    capture.retrieve( depthMap, CV_CAP_OPENNI_DEPTH_MAP ); // Depth values in mm (CV_16UC1)
    capture.retrieve( bgrImage, CV_CAP_OPENNI_BGR_IMAGE );

    cout << "rows: " << depthMap.rows << " cols: " << depthMap.cols << endl;
    cout << "depth: " << depthMap.at<int>(0,0) << endl;

    imshow("RGB image", bgrImage);

    if( waitKey( 30 ) >= 0 )
        break;
}h
return 0;

运行代码后,我得到以下结果:

靠近墙壁约一米远:

rows: 480 cols: 640
depth: 1157
rows: 480 cols: 640
depth: 1157
rows: 480 cols: 640
depth: 1157
rows: 480 cols: 640
depth: 1157 

(Kinect 对着墙,一米多远)

rows: 480 cols: 640
depth: 83690629
rows: 480 cols: 640
depth: 83690629
rows: 480 cols: 640
depth: 83690629
rows: 480 cols: 640
depth: 83690629
rows: 480 cols: 640
depth: 83690629

有人告诉我这些值实际上是两个像素?我真的不明白。

这是我目前的理解:

我抓取了一个深度帧并将其存储在一个名为 depthMap 的矩阵中。矩阵的大小现在是 640*480。我正在使用代码 depthMap.at(0,0) 从第 0 行第 0 列中获取第一个深度值。但我没有返回毫米的结果,而是返回 83690629!这与我期望的最大值 10000 相差甚远

如何将这些值转换为毫米以便使用它们?谢谢

【问题讨论】:

  • 也许 Kinect 离墙太近了在一米以下?我知道限制就在附近,如果不是那么精确的话。另见here
  • na 它不低于 1 米,因为我得到相同的值,但在 2-3 米等更远的地方时会稍微高一些。有人对我说,我将 'depthMap.at(0,0)' 更改为 'depthMap.at(0,0)' 并且结果值为 (83690629) 实际上是两个像素和我应该转换为十六进制? (489102879 = 0x1d271e1f) 不知道他在说什么。但我仍然得到相同的值,不知道如何最好地解释它们。

标签: opencv kinect depth openni


【解决方案1】:

深度值以 11 位存储,封装在 16 位变量中。 因此,当您访问矩阵时,您必须提供正确的元素数据类型。 如前所述,您可以使用depthMap.at&lt;unsigned short&gt;(i,j),但您必须确保unsigned short 在所有编译器中都是16 位长。 我更喜欢使用uint16_t 数据类型。

此外,根据您选择的openni PIXEL_FORMAT,存储在矩阵内的深度值可以是:

  • 以毫米为单位 - openni::PIXEL_FORMAT_DEPTH_1_MM
  • 十分之一毫米 - openni::PIXEL_FORMAT_DEPTH_100_UM

您可以使用void openni::VideoMode::setPixelFormat(PixelFormat) 函数设置pixel_format http://www.openni.ru/wp-content/doxygen/html/classopenni_1_1_video_mode.html#af7fd37bba526fced9c7dbbbf1ab419ea

如果您想要更精确的数据 (PIXEL_FORMAT_DEPTH_100_UM),以毫米为单位,您可以将其转换为浮点数并除以 10:

uint16_t redValue = depthMap.at<uint16_t>(i,j);
float myVal = ( (float) redValue ) / 10.0f;

【讨论】:

    【解决方案2】:

    检查正确的数据类型,调试模式,然后有矩阵的断点,然后检查文件数据类型

    【讨论】:

      【解决方案3】:

      我目前正在使用 kinect (+OpenNi + OpenCv),我不知道你是否还在为你的问题而苦恼。

      我尝试了完全相同的代码,但使用了depthMap.at&lt;unsigned short&gt;(i,j),它运行得非常好,给出了以毫米为单位的值(当我距离 kinect 50 厘米时为 502)

      问题是:我不知道深度值是如何传递的,我在互联网上看到了很多相互矛盾的信息。为什么会是2像素?为什么要转换为十六进制?

      我确信我不是那种难以理解这里的基本原则的人。那么,有人有关于 kinect 深度的可靠文档吗?

      (我读过关于 stephane Magnenat/Nicolas Burrus 的公式:11 位上的 kinect 原始数据,添加一些几何材料等等......但 OpenNi 是否已经处理了这个问题并提供了原样的深度??)

      欢迎评论。 干杯。

      【讨论】:

        【解决方案4】:

        深度图数据是单通道无符号16Bit。 尝试将int替换为CV_16UC1

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-09-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-30
          • 2014-03-23
          相关资源
          最近更新 更多