从彩色背景中检测黑色点

15

我的简短问题

如何检测以下图像中的黑点?(我只粘贴了一个测试图像,以使问题看起来紧凑。更多图像可以在→这里←找到)。

输入图像描述

我的长问题

如上所示,背景颜色大致为蓝色,点的颜色为“黑色”。如果选择一个黑色像素并测量其RGB颜色,则该值可以是输入图像描述(0,44,65)或输入图像描述(14,69,89)......因此,我们无法设置范围来判断像素是黑点还是背景。

我测试了10个不同颜色的图像,但我希望我可以找到一种方法来检测黑点,即使背景可能由三种或更多颜色组成,只要人眼可以轻松识别黑点。有些非常小或模糊的点可以被忽略。

以前的工作

上个月,我在stackoverflow上提出了类似的问题,但没有得到完美的解决方案,虽然有一些优秀的答案。如果您感兴趣,可以找到有关我的工作的更多详细信息。

这是我尝试过的方法:

  1. 将图像转换为灰度或亮度。难点在于找不到自适应的阈值进行二值化。显然,将彩色图像转换为灰度或使用亮度 (HSV) 将会失去很多有用信息。 大津算法 计算自适应阈值也无法解决这个问题。

  2. 计算 RGB 直方图。在我的上一个问题中,natan 的方法是通过直方图估计黑色颜色。这样做可以节省时间,但自适应阈值还是一个问题。

  3. 聚类。我尝试了K-Means 聚类 并发现它对只有一种颜色的背景非常有效。缺点是我需要预先设定聚类中心的数量,但我不知道背景会是什么样子。而且速度太慢!我的应用程序是在 iPhone 上进行实时捕捉,现在可以使用 k-means 处理 7~8 帧每秒(我认为 20 FPS 是不错的)。

  4. 总结

    我认为不仅应该聚类相似的颜色,还应该聚类或合并相邻像素以提取黑点。请指导我解决这个问题的正确方法。任何建议或算法都将受到赞赏。没有免费的午餐,但我希望在成本和精度之间取得更好的平衡。


你可以看一下这个链接:http://www.mathworks.com/matlabcentral/fileexchange/25157-image-segmentation-tutorial---blobsdemo-- - Steve
如答案中所建议的那样,它就像寻找局部最大值一样。我想评论一下颜色不变性:尝试使用同态滤波 - LovaBill
3个回答

14

通过使用rgb2hsv将图像转换为HSV颜色空间,然后在值通道上使用Image Processing Toolbox的函数imopenimregionalmin,我能够获得一些相当不错的初步结果:

rgb = imread('6abIc.jpg');
hsv = rgb2hsv(rgb);
openimg = imopen(hsv(:, :, 3), strel('disk', 11));
mask = imregionalmin(openimg);
imshow(rgb);
hold on;
[r, c] = find(mask);
plot(c, r, 'r.');

因此得到的图像(对于问题中的图像和从您的链接中选择的图像):

enter image description here

enter image description here

您可以看到一些误报和错过的点,以及一些用多个点标记的点,但是进行一些细化(例如修改打开步骤中使用的结构元素)可以清理这些。


非常干净的解决方案,处理量最小。我也收藏并点赞了。 - rayryeng
赞!以前从没想过imopen能做这样的工作。我会在OpenCV中实现你的方法。 - WangYudong
@WangYudong,您可以使用OpenCV的adaptiveThreshold函数,然后执行形态学开运算,以获得与此答案大致相同的结果。在我测试时,hsv的v通道或Lab的l通道效果非常好。我认为灰度图像也同样有效,但似乎不如这两种方法好。 - Zaw Lin
@WangYudong,你有机会实现那个了吗? - Sergi0

7

我很好奇想要用我的旧2D峰值查找代码来测试图像,而不考虑任何阈值或颜色限制,这真的很粗糙,你觉得呢?

im0=imread('Snap10.jpg');
im=(abs(255-im0));
d=rgb2gray(im);
filter=fspecial('gaussian',16,3.5);
p=FastPeakFind(d,0,filter);
imagesc(im0); hold on
plot(p(1:2:end),p(2:2:end),'r.')

enter image description here

我使用的代码是一个简单的二维局部极大值查找器,有一些假阳性,但总的来说这捕捉到了大多数点而没有重复。我使用的过滤器是一个二维高斯函数,宽度和标准差类似于一个典型的斑点(最好是为您的问题获取匹配的过滤器)。 更复杂的版本,可以处理颜色 (rgb2hsv?),可能会进一步提高效果...


谢谢您再次回答我的问题。我会在接下来的工作中参考您的峰值查找器。 - WangYudong

3

这是一个非常简化的版本,可以扩展为完整的RGB,它也不使用图像处理库。基本上,您可以使用过滤图像(这是您要查找的点的示例)进行二维卷积,并从卷积返回最高值的点中选出最佳匹配的点。然后您当然可以对其进行阈值处理。这是一个仅包含这些内容的简单二进制图像示例。

%creating a dummy image with a bunch of small white crosses
im = zeros(100,100);
numPoints = 10;

% randomly chose the location to put those crosses
points = randperm(numel(im));
% keep only certain number of points
points = points(1:numPoints);
% get the row and columns (x,y)
[xVals,yVals] = ind2sub(size(im),points);

for ii = 1:numel(points)
   x = xVals(ii);
   y = yVals(ii);
   try
       % create the crosses, try statement is here to prevent index out of bounds
       % not necessarily the best practice but whatever, it is only for demonstration
       im(x,y) = 1;
       im(x+1,y) = 1;
       im(x-1,y) = 1;
       im(x,y+1) = 1;
       im(x,y-1) = 1;
   catch err
   end
end
% display the randomly generated image
imshow(im)

% create a simple cross filter
filter = [0,1,0;1,1,1;0,1,0];
figure; imshow(filter)

% perform convolution of the random image with the cross template
result = conv2(im,filter,'same');

% get the number of white pixels in filter
filSum = sum(filter(:));

% look for all points in the convolution results that matched identically to the filter
matches = find(result == filSum);

%validate all points found
sort(matches(:)) == sort(points(:))
% get x and y coordinate matches
[xMatch,yMatch] = ind2sub(size(im),matches);

我强烈建议查看MATLAB网站上conv2文档,它与IT技术有关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接