【问题标题】:Otsu thresholding for depth image深度图像的 Otsu 阈值
【发布时间】:2012-10-08 20:56:12
【问题描述】:

我正在尝试从使用 kinect 获取的深度图像中减去背景。当我了解 otsu 阈值是什么时,我认为它可以做到。将深度图像转换为灰度我希望可以应用 otsu 阈值来对图像进行二值化。

但是我用 OpenCV 2.3 实现(试图实现)这个,它是徒劳的。然而,输出图像被二值化,非常出乎意料。我连续进行了阈值处理(即将结果打印到屏幕上以对每一帧进行分析),发现某些帧的阈值是 160ish,有时发现是 0。我不太明白为什么会发生这种情况。可能是由于 kinect 返回的深度图像中有大量 0,对应的像素无法测量。有没有办法告诉算法忽略值为 0 的像素?或者 otsu 阈值对我想要做的事情不利?

以下是相关代码的一些输出和段。您可能会注意到第二个屏幕截图看起来可以进行一些很好的二值化,但是我想要实现一个能够明显区分场景中椅子对应的像素和背景的像素。

谢谢。

            cv::Mat1s depthcv(depth->getHeight(), depth->getWidth());
            cv::Mat1b depthcv8(depth->getHeight(), depth->getWidth());
            cv::Mat1b depthcv8_th(depth->getHeight(), depth->getWidth());
            depthcv.data =(uchar*) depth->getDepthMetaData().Data();
            depthcv.convertTo(depthcv8,CV_8U,255/5000.f);

            //apply otsu thresholding
            cv::threshold(depthcv8, depthcv8_th, 128, 255, CV_THRESH_BINARY|CV_THRESH_OTSU);
            std::ofstream output;
            output.open("output.txt");
            //output << "M = "<< endl << " "  << depthcv8 << endl << endl;
            cv::imshow("lab",depthcv8_th);
            cv::waitKey(1);

【问题讨论】:

  • 要在 Ubuntu 中制作单个窗口的屏幕截图,请按 alt+prtsc
  • 我只熟悉官方的Windows SDK,无法直接回答问题。但是,如果您安装了 Windows,则官方 Kinect for Windows SDK 工具包示例中有“绿屏”示例。你也许可以从那里得到一些想法。也许……?
  • 您在创建 Matrix 数组时似乎已经相互更改了高度和宽度。更正应该是cv::Mat1s depthcv(depth-&gt;getWidth(), depth-&gt;getHeight());

标签: opencv kinect background-subtraction


【解决方案1】:

Otsu 可能足以满足您的要求,但您确实需要在使用 Otsu 算法计算最佳阈值之前屏蔽零值,否则强度值的分布将偏斜低于您想要的值.

OpenCV 没有为cv::threshold 函数提供掩码参数,因此您必须自己删除这些值。我建议将所有非零值放入 1 × N 矩阵中,并使用 CV_THRESH_OTSU 调用 cv::threshold 函数并保存返回值(这是估计的最佳阈值),然后运行 ​​cv::threshold 函数再次使用 CV_THRESH_BINARY 标志和计算的阈值在原始图像上。

这是一种可能的实现方式:

// move zeros to the back of a temp array
cv::Mat copyImg = origImg;
uint8* ptr = copyImg.datastart;
uint8* ptr_end = copyImg.dataend;
while (ptr < ptr_end) {
  if (*ptr == 0) { // swap if zero
    uint8 tmp = *ptr_end;
    *ptr_end = *ptr;
    *ptr = tmp;
    ptr_end--; // make array smaller
  } else {
    ptr++;
  }
}

// make a new matrix with only valid data
cv::Mat nz = cv::Mat(std::vector<uint8>(copyImg.datastart,ptr_end),true);

// compute optimal Otsu threshold
double thresh = cv::threshold(nz,nz,0,255,CV_THRESH_BINARY | CV_THRESH_OTSU);

// apply threshold
cv::threshold(origImg,origImg,thresh,255,CV_THRESH_BINARY_INV);

【讨论】:

    猜你喜欢
    • 2020-01-25
    • 2023-02-10
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 2022-06-22
    相关资源
    最近更新 更多