计算机视觉 - 计算图像中的小圆圈

时间:2017-11-30 04:49:42

标签: opencv computer-vision object-detection

下面的图片有很多圈子。点击并放大以查看圈子。

https://drive.google.com/open?id=1ox3kiRX5hf2tHDptWfgcbMTAHKCDizSI

我想要的是使用任何免费语言计算圈子,例如python。

有功能或想法吗?

3 个答案:

答案 0 :(得分:6)

编辑:我提出了一个更好的解决方案,部分受到this answer below的启发。我最初想到了这种方法(如OP评论中所述),但我决定反对它。原始图像质量不够好。但是我改进了这种方法,它可以出色地以获得更高质量的图像。最初的方法是先行,然后是最后的新方法。

第一种方法

所以,这是一种似乎运作良好的一般方法,但绝对只是给出了估计。这假设圆圈的大小大致相同。

首先,图像大多是蓝色的 - 所以在蓝色通道上进行分析似乎是合理的。在这种情况下,使用Otsu阈值处理(无需输入确定最佳阈值)对蓝色通道进行阈值处理似乎非常有效。这并不令人惊讶,因为颜色值的分布几乎是二元的。检查由它产生的面具!

Mask

然后,对蒙版进行连通分量分析,得到每个分量的区域(分量=掩码中的白色斑点)。从connectedComponentsWithStats()返回的统计数据给出了(除其他外)该区域,这正是我们所需要的。然后,我们可以通过估算给定组件中基于其面积的圆圈数来简单地计算圆圈。另请注意,除了第一个标签之外,我还会记录每个标签:这是背景标签0,而不是任何白色斑点。

现在,单个圆圈的面积有多大?最好让数据告诉我们。因此,您可以计算所有区域的直方图,并且由于单个圆圈比其他任何区域都要多,因此该区域的高浓度约为250-270像素左右。或者你可以只取50到350之间的所有区域的平均值,这也可以让你进入类似的球场。

Histogram

在此直方图中,您可以非常轻松地看到单个圆圈,双圆圈,三个等之间的分界线。只有较大的组件才会给出非常粗略的估计。事实上,该区域似乎没有完全线性地扩展。两个圆圈的斑点略大于两个单个圆圈,三个斑点比三个单个圆圈还要大,依此类推,所以这使得它很难估计得很好,但是四舍五入仍然应该让我们保持接近。如果你想要的话,你可以包括一个小的乘法参数,随着面积的增加而增加,但是如果不分析地通过直方图就很难量化...所以,我并不担心这个。 / p>

单个圆形区域除以平均单个圆形区域应该接近1.并且5个圆圈组的面积除以平均圆形区域应该接近5.这也意味着小的不重要的组成部分,区域中的1或10或甚至100个像素,将不计入round(50/avg_circle_size) < 1/2以来的总数,因此这些将向下舍入到0的计数。因此,我应该能够占用所有组成区域,除以它们按平均圆形大小,圆形,并通过总结它们得到一个不错的估计。

import cv2
import numpy as np

img = cv2.imread('circles.png')
mask = cv2.threshold(img[:, :, 0], 255, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

stats = cv2.connectedComponentsWithStats(mask, 8)[2]
label_area = stats[1:, cv2.CC_STAT_AREA]

min_area, max_area = 50, 350  # min/max for a single circle
singular_mask = (min_area < label_area) & (label_area <= max_area)
circle_area = np.mean(label_area[singular_mask])

n_circles = int(np.sum(np.round(label_area / circle_area)))

print('Total circles:', n_circles)

此代码对粗略计数简单有效。

然而,对于圆形组与正常圆形尺寸相比,这里肯定存在一些假设,并且存在这样的问题:在边界处的圆圈将不会被正确计数(这些没有被很好地定义 - - 一个半截断的两个圆形斑点看起来更像是一个圆圈---没有明确的方法来计算或不用这个方法计算这些数字)。此外,我在这里通过Otsu使用自动阈值处理;您可以通过更仔细的颜色过滤得到(可能更好)结果。此外,在Otsu生成的蒙版中,一些被遮罩的圆圈从其中心移除了一些像素。形态学可以将这些像素重新添加回来,这样可以为单个圆形组件提供(略大)更准确的区域。无论哪种方式,我只想提出一个大致的想法,即如何用最少的代码轻松估算这一点。

新方法

之前,目标是计算圈数。这种新方法改为计算圆圈的中心。一般的想法是你的阈值,然后从背景像素填充填充背景(洪水填充像照片编辑应用程序中的油漆桶工具),这样你只能看到中心,如this answer below所示。

然而,这依赖于全局阈值处理,这对于局部照明变化并不稳健。这意味着,由于某些中心比其他中心更亮/更暗,因此您无法通过单一阈值获得良好的结果。

在这里,我创建了一个动画来显示不同阈值的循环;看一些中心在不同时间出现和消失,这意味着你根据你选择的门槛得到不同的数量(这只是图像的一小部分,它随处可见):

Varying threshold levels

请注意,出现在左上角的第一个blob实际上会随着阈值的增加而消失。但是,如果我们实际上将每个帧组合在一起,那么每个检测到的像素都会持续存在:

Bitwise OR

但是现在每一个斑点出现,所以我们应该清理每一帧的掩模,以便我们在它们到来时移除单个像素(否则它们可能会累积并且以后很难去除)。带有小内核的简单morphological opening将删除它们:

Opening to remove small pieces

应用于整个图像,此方法非常好并且几乎找到每个单元格。只有三个误报(检测到的blob不是中心)和两个我可以发现的未命中,代码非常简单。创建蒙版后要做的最后一件事就是对组件进行计数,减去背景的一个。此处所需的唯一用户输入是单点到泛洪填充,在后台(代码中为seed_pt)。

Detected centers

img = cv2.imread('circles.png', 0)
seed_pt = (25, 25)
fill_color = 0
mask = np.zeros_like(img)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
for th in range(60, 120):
    prev_mask = mask.copy()
    mask = cv2.threshold(img, th, 255, cv2.THRESH_BINARY)[1]
    mask = cv2.floodFill(mask, None, seed_pt, fill_color)[1]
    mask = cv2.bitwise_or(mask, prev_mask)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

n_centers = cv2.connectedComponents(mask)[0] - 1
print('There are %d cells in the image.'%n_centers)
  

图像中有874个细胞。

答案 1 :(得分:0)

一种可能的解决方案是使用OpenCV读取图像,获取其灰度,然后使用Canny边缘检测并在OpenCV中执行countour查找。这将返回一个countours列表。它看起来像是:

import cv2
image = cv2.imread('path-to-your-image')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# tweak the parameters of the GaussianBlur for best performance
blurred = cv2.GaussianBlur(gray, (7, 7), 0)
# again, try different values here
edged = cv2.Canny(blurred, 20, 140)
(_, contours, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))

答案 2 :(得分:0)

如果您拥有这样的所有图像 - 请考虑对其进行阈值处理,不一定是像Otsu这样的自动阈值搜索算法,而是使用给定阈值的最简单阈值。是的,在阈值处理之前,您必须将颜色输入转换为灰度,或采用其中一种颜色通道。然后基于通道和阈值的少数实验 - 确定阈值以在单色阈值结果中具有带孔的圆。根据你的png图像,我发现81的值(灰度强度从0到255变化)对于输入的阈值灰度版本来说是很好的,以便具有这样的具有孔的二进制图像,如上所述。 thresholded image

然后只计算那些漏洞。

可以通过种子填充白色区域来确定孔,连接到图像边界。因此,您将在黑色背景上使用白洞连接组件 - 因此只需计算它们即可。 holes to count

您可以在此处找到更多详细信息http://www.leptonica.com/filling.html并使用leptonica基元进行阈值处理,计算孔数等。