我正在尝试从使用 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);
最佳答案
Otsu 可能足以满足您尝试做的事情,但您确实需要在使用 Otsu 算法计算最佳阈值之前屏蔽掉零值,否则强度值的分布将偏斜低于您想要的.
OpenCV 没有为 cv::threshold
函数提供掩码参数,因此您必须自己删除这些值。我建议将所有非零值放在 1×N 矩阵中,并使用 CV_THRESH_OTSU
调用 cv::threshold
函数并保存返回值(这是估计的最佳阈值),然后仅使用 CV_THRESH_BINARY
标志和计算的阈值在原始图像上再次运行 cv::threshold
函数。
这是一种可能的实现方式:
// 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);
关于opencv - 深度图像的大津阈值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12953993/