12

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

只要图像是已知的,它就可以正常工作,并且我可以手动将阈值传递给 threshold()——在这个特定的图像中,比如 200。但是假设图像不知道,唯一的知识是会有一个黑暗纯色背景和较浅的前景对象如何动态计算阈值?

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

在此处输入图像描述

4

3 回答 3

11

如果你所有的图像都是这样,或者可以带成这种风格,我认为 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 分(这与我们得到的结果相当)。它还消除了噪音。见下面的结果:

在此处输入图像描述

于 2012-06-29T19:41:20.793 回答
7

如果你说背景是暗的(黑色)而前景是亮的,那么我建议使用YUV 颜色空间(或任何其他YXX ,如YCrCb等),因为此类颜色空间的第一个组成部分是亮度(或闪电)。

光通道

所以在提取Y通道之后(通过extractChennel函数)我们需要分析这个通道的直方图(图像):

直方图

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

  • 直方图的(局部)最大值从该点的左侧开始
  • histogram 的值小于一些小的epsilon(您可以将其设置为 10)

我画了一条绿色的垂直线来显示该直方图中线段右点的位置。

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

结果

我认为删除上图中的噪点对您来说不是问题。

于 2012-06-29T18:51:30.750 回答
0

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

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

对原始图像运行它,我得到以下信息: 在此处输入图像描述

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

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

在此处输入图像描述

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

在此处输入图像描述

于 2018-01-18T16:28:40.023 回答