如何从直方图中获取阈值?

时间:2012-06-29 17:16:27

标签: image-processing opencv computer-vision

我正在OpenCV中编写一个Android应用来检测blob。一个任务是阈值图像以区分前景对象和背景(见图像)。

只要图像已知并且我可以手动将阈值传递到阈值(),它就能正常工作 - 在这个特定的图像中,例如,200。但是假设图像不知道,只知道会有是一个黑暗的固体背景和更轻的前景物体如何动态计算出阈值?

我遇到了直方图,我可以在其中计算灰度图像的强度分布。但我找不到一种分析直方图的方法,并选择感兴趣的物体(较轻的)所在的值。那是;我想区分明显的暗背景尖峰与较轻的前景尖峰 - 在这种情况下高于200,但在另一种情况下可以说,如果对象是灰色的话,则为100。

enter image description here

3 个答案:

答案 0 :(得分:10)

如果您的所有图像都是这样的,或者可以使用这种风格,我认为cv2.THRESHOLD_OTSU,即otsu的阈值算法是一个很好的镜头。

以下是在命令终端中使用Python的示例:

>>> import cv2
>>> import numpy as np
>>> img2 = cv2.imread('D:\Abid_Rahman_K\work_space\sofeggs.jpg',0)

>>> ret,thresh = cv2.threshold(img2,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

>>> ret
122.0

ret是自动计算的阈值。我们只是将“0”作为阈值传递给它。

我在GIMP中获得了124分(这与我们得到的结果相当)。它还消除了噪音。见下面的结果:

enter image description here

答案 1 :(得分:7)

如果您说背景是黑色(黑色)且前景较浅,那么我建议使用YUV color space(或任何其他 YXX ,如 YCrCb 等),因为此类色彩空间的第一个成分是亮度(或闪电)。

light channel

因此,在提取 Y 频道后(通过extractChennel函数),我们需要分析此频道的直方图(图片):

histogram

看到第一个(左)驼峰?它代表图像上的暗区(背景情况)。所以我们现在的目标是找到一个包含这个驼峰的片段(在横坐标上,它是图像中的红色部分)。显然,该段的左侧点是。正确的点是第一点:

  • 直方图的(局部)最大值来自点的左侧
  • 直方图的值小于某些小 epsilon (您可以将其设置为10)

我绘制了一条绿色垂直线,以显示该直方图中段的正确位置。

就是这样!该段的右侧点是所需的阈值。结果如下( epsilon 为10,计算出的阈值为50):

result

我认为删除上图中的噪音不是问题。

答案 2 :(得分:0)

以下是Abid的答案的C ++实现,适用于OpenCV 3.x:

// Convert the source image to a 1 channel grayscale:
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
// Apply the threshold function with the CV_THRESH_OTSU setting as well
// You can skip having it return the value, but I include it for showing the
// results from OTSU
double thresholdValue = threshold(gray, gray, 0, 255, CV_THRESH_BINARY+CV_THRESH_OTSU);
// Present the threshold value
printf("Threshold value: %f\n", thresholdValue);

针对原始图像运行此操作,我得到以下内容: enter image description here

OpenCV为它计算了一个122的阈值,接近他在答案中找到的值Abid。

为了验证,我改变了原始图像,如下所示:

enter image description here

并产生以下内容,新阈值为178:

enter image description here