如何使用python OpenCV在单通道图像中找到与特定值匹配的最大连通分量?

Posted

技术标签:

【中文标题】如何使用python OpenCV在单通道图像中找到与特定值匹配的最大连通分量?【英文标题】:How to use python OpenCV to find largest connected component in a single channel image that matches a specific value? 【发布时间】:2018-05-11 06:08:12 【问题描述】:

所以我有一个单通道图像,大部分是 0(背景),以及一些前景像素的值,如 20、21、22。非零前景像素大多与其他具有相同值的前景像素聚集在一起。但是,图像中有一些噪点。为了消除噪音,我想使用连通分量分析,并且对于每个值(在本例中为 20、21、22),将除最大连通分量之外的所有值都归零。所以最后,我将有 3 个大的连接组件并且没有噪音。我将如何使用 cv2.connectedComponentsWithStats 来完成此任务?它似乎记录得很差,即使在查看this post 之后,我也不完全理解如何解析函数的返回值。有没有办法向函数指定我只希望连接的组件匹配特定的灰度值?

【问题讨论】:

掩盖给定的强度并对其进行分析怎么样? 所以您的意思是可能有许多不同区域的值为 20,但您只希望每个值的最大区域? 你能添加一些示例输入图像吗? 【参考方案1】:

这是一般方法:

    创建一个新的空白图像以添加组件 遍历图像中每个不同的非零值 为每个值创建一个掩码(为每个值提供多个 blob) 在面具上运行connectedComponentsWithStats() 找到最大区域对应的非零标签 创建一个具有最大标签的蒙版,并将该值插入新图像的蒙版位置

这里令人讨厌的是第 5 步,因为 0 的值通常,但并不总是是最大的分量。所以我们需要得到面积最大的非零分量。

这是一些我认为可以实现一切的代码(可以肯定的是一些示例图像):

import cv2
import numpy as np

img = np.array([
    [1, 0, 1, 1, 2],
    [1, 0, 1, 1, 2],
    [1, 0, 1, 1, 2],
    [1, 0, 1, 1, 2],
    [1, 0, 1, 1, 2]], dtype=np.uint8)

new_img = np.zeros_like(img)                                        # step 1
for val in np.unique(img)[1:]:                                      # step 2
    mask = np.uint8(img == val)                                     # step 3
    labels, stats = cv2.connectedComponentsWithStats(mask, 4)[1:3]  # step 4
    largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])      # step 5
    new_img[labels == largest_label] = val                          # step 6

print(new_img)

显示所需的输出:

[[0 0 1 1 2]
 [0 0 1 1 2]
 [0 0 1 1 2]
 [0 0 1 1 2]
 [0 0 1 1 2]]

要查看代码,首先我们创建新的标记图像,难以想象地称为new_img,用零填充,稍后由正确的标签填充。然后,np.unique() 找到图像中的唯一值,我将获取除第一个值之外的所有值;请注意,np.unique() 返回一个排序数组,所以 0 将是第一个值,我们不需要找到零的分量。对于每个唯一的 val,创建一个填充有 0 和 1 的掩码,并在此掩码上运行连接的组件。这将用不同的标签标记每个不同的区域。然后我们可以抓取最大的非零标记组件**,为其创建一个遮罩,并将该 val 添加到该位置的新图像中。

** 这是在代码中看起来很奇怪的烦人之处。

largest_label = 1 + np.argmax(stats[1:, cv2.CC_STAT_AREA])

首先,您可以查看您为stats 数组的形状链接的答案,但每一行对应一个标签(因此标签0 将对应于第一行等),并且列已定义由整数 cv2.CC_STAT_AREA (只有 4)。我们需要确保我们正在查看最大的非零标签,所以我只查看第一个之后的行。然后,抓取最大区域对应的索引。由于我们去掉了零行,索引现在对应于label-1,所以加 1 以获得正确的标签。然后我们可以像往常一样屏蔽并插入值。

【讨论】:

感谢您的详尽解释。对此,我真的非常感激。我还有一个问题。在这种情况下,stats 不应该总是只有 2 行,因为掩码只有 2 个标签(0 和 val)吗?在这种情况下,直接使用[1]而不是[1:]访问第1行是否有问题?还是我误解了关于连接组件统计信息的“标签”一词的使用? @Terry Martin 你误解了标签。连接的组件用...标签标记每个组件。如果 blob 是独立的,则它们是不同的组件。因此,即使像一个 3x3 图像,左侧和右侧为 1,中间为 0,该图像的连接组件也会使它们左侧为 1,中间为 0,右侧为 2。每个连接的组件都有一个新标签,这就是区分相同颜色的组件的方式。

以上是关于如何使用python OpenCV在单通道图像中找到与特定值匹配的最大连通分量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中使用 OpenCV 合并 2 个灰度图像

openCV-python(六)图像操作——通道拆分与合并

Python使用OpenCV加载彩色图像为BGR图计算每个图像通道的均值(mean of each channel)可视化图像在每个通道的均值

使用Python,OpenCV获取更改像素,修改图像通道,剪裁ROI

opencv 提取单通道 ,转化灰度图像。

计算机视觉OpenCV 4高级编程与项目实战(Python版):通道详解