大津深度图像阈值 [英] Otsu thresholding for depth image

查看:167
本文介绍了大津深度图像阈值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从使用kinect获取的深度图像中减去背景.当我知道什么是大津阈值法时,我认为可以做到这一点.将深度图像转换为灰度图像,我希望可以应用otsu阈值对图像进行二值化.

I am trying to substract background from depth images acquired with kinect. When I learned what otsu thresholding is I thought that it could with it. Converting the depth image to grayscale i can hopefully apply otsu threshold to binarize the image.

但是我用OpenCV 2.3实现(尝试实现),却徒劳无功.但是,输出图像被二值化,这非常出乎意料.我连续进行阈值处理(即,将结果打印到屏幕上以分析每一帧),发现对于某些帧,阈值被发现为160ish,有时被发现为0.我不太明白为什么会这样.可能是由于kinect返回的深度图像中的0很高,这对应于无法测量的像素.有没有办法让我告诉算法忽略值为0的像素?还是大津阈值法对我想做的事情不好?

However I implemented (tried to implemented) this with OpenCV 2.3, it came in vain. The output image is binarized however, very unexpectedly. I did the thresholding continuously (i.e print the result to screen to analyze for each frame) and saw that for some frames threshold is found to be 160ish and sometimes it is found to be 0. I couldn't quite understand why this is happening. May it be due to the high number of 0's in the depth image returned by kinect, which corresponds to pixels that can not be measured. Is there a way that I could tell the algorithm to ignore pixels having the value 0? Or otsu thresholding is not good for what I am trying to do?

这是相关代码的一些输出和部分.您可能会注意到,第二个屏幕截图看起来可以很好地进行二值化,但是我想实现一个可以区分场景中椅子和背景的像素的方法.

Here are some outputs and segment of the related code. You may notice that the second screenshot looks like it could do some good binarization, however i want to achieve one that distincly differentiates between pixels corresponding to the chair in the scene and the backgroung.

谢谢.

            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);

推荐答案

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

Otsu is probably good enough for what you are trying to do, but you do need to mask out the zero values before computing the optimal threshold with the Otsu algorithm, otherwise the distribution of intensity values will be skewed lower than what you want.

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

OpenCV does not provide a mask argument for the cv::threshold function, so you will have to remove those values yourself. I would recommend putting all the non-zero values in a 1 by N matrix, and calling the cv::threshold function with CV_THRESH_OTSU and saving the return value (which is the estimated optimal threshold), and then running the cv::threshold function again on the original image with just the CV_THRESH_BINARY flag and the computed threshold.

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

Here is one possible implementation:

// 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);

这篇关于大津深度图像阈值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆