python图像处理 — cv2.connectedComponentsWithStats

cv2.connectedComponentsWithStats 处理不规则连通区域

函数介绍

retval, labels, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=8)

输入值:

  • image : 是要处理的图片,官方文档要求是8位单通道的图像。
  • connectivity : 可以选择是4连通还是8连通。

输出值

  • retval : 返回值是连通区域的数量。
  • labels : labels是一个与image一样大小的矩形(labels.shape = image.shape),其中每一个连通区域会有一个唯一标识,标识从0开始。
  • stats :stats会包含5个参数分别为x,y,h,w,s。分别对应每一个连通区域的外接矩形的起始坐标x,y;外接矩形的wide,height;s其实不是外接矩形的面积,实践证明是labels对应的连通区域的像素个数。
  • centroids : 返回的是连通区域的质心。

实例-参数详解

举个栗子

1、 我创建了10x10的图片,其中像素值分别有0和100
在这里插入图片描述

输入的image就是我们这个10x10的图片
如果我们要分析8连通,就令

connectivity=8

2、用 opencv 将图片读入

image = cv2.imread('test1.tif') # 将上述的10*10图片存为test.tif的图片
img = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) #转灰度
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(img, connectivity=8)

返回值

retval #retval = 3
>>> 3

stats      #我们看出有3个连通区域
            # x   y   w   h  s 
>>> array([[ 0,  0, 10, 10, 76],  # 这代表整个图片,0值也有连通区域
           [ 4,  1,  5,  6, 18],  # 这里18代表有18个像素 下面的6同理
           [ 2,  2,  3,  2,  6]], dtype=int32)
           
labels  # labdels 将背景0值标为0,值为100的标为1 和 2
>>> array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	       [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
	       [0, 0, 2, 2, 2, 0, 1, 0, 0, 0],
	       [0, 0, 2, 2, 2, 0, 1, 1, 1, 0],
	       [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
	       [0, 0, 0, 0, 1, 1, 1, 1, 1, 0],
	       [0, 0, 0, 0, 1, 1, 1, 1, 1, 0],
	       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32)
	       
centroids
>>> array([[4.17105263, 4.68421053],
	       [6.38888889, 4.38888889],
	       [3.        , 2.5       ]]	

3、我们来详细看一下如何利用stats和labels处理不规则图形

按照 stats返回的外接矩形分别如下两个矩形,其中蓝色的矩形有两个值在红色矩形内,同时可以看到原始数据的连通区域与labels可以相互对应
在这里插入图片描述
在这里插入图片描述

问题来了: 如果我想要将原始图片红色框内的100变为0,如果我们直接令外接矩形框内全部为0,这样不可避免的会伤及无辜将蓝色框内的两个100值都改为0.这个是不允许的。
所以我们可以利用labels的标识

label = labels[y:y + h, x:x + w] #获取要处理的红色方框外接矩形
lab = label.reshape(-1, )  # 二维转一维
lab = np.unique(lab)  # 去掉重复
lab = np.setdiff1d(lab, 0)  # 去掉0值,因为0值是背景的标识,我们不用处理0,只要除去1保留2即可

之后又因为stats中的返回值s是像素值的个数,并不是外接矩形内所有100值的个数。
下面两个图可以看出,红色框内100的值是20个,但构成连通区域的之后18个像素,所以stats返回值中是18不是20;这个很重要!!!!
在这里插入图片描述
这样在红色矩形框内的labels= 2 的数量只有两个,labels = 1的数量有18个,并且与s一致,可以依据这个条件,获取labels = 1 的坐标,并令这些坐标所在值等于0,这样labels = 2 的值并没有受到影像。

for l in lab:
    seeds = np.argwhere(label==l)
    seedlist = list(seeds)
    print(seedlist)
    if len(seedlist) == s:
#         print(seedlist)
        for point in seedlist:
            image[point[0],point[1]] = 0
        img[y:y + h, x:x + w] = image

4 、结果:
在这里插入图片描述
原始图:
在这里插入图片描述

在这之前我尝试了一些别的函数,都不能很好的操作,下期会整理一下。

  • 38
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
获取图像的连通域可以使用`cv2.connectedComponentsWithStats()`方法,该方法返回每个连通域的标签、面积、宽度、高度和左上角坐标等信息。然后可以根据面积大小筛选出需要保留的连通域,并使用`cv2.rectangle()`方法框出这些连通域。 下面是一个示例代码: ```python import cv2 # 读取图像 img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE) # 二值化处理 _, thresh = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY) # 获取连通域信息 num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh) # 筛选出需要保留的连通域 min_area = 100 # 最小面积阈值 keep_labels = [] for i in range(1, num_labels): area = stats[i, cv2.CC_STAT_AREA] if area >= min_area: keep_labels.append(i) # 框出保留的连通域 for label in keep_labels: x, y, w, h = stats[label, cv2.CC_STAT_LEFT], stats[label, cv2.CC_STAT_TOP], stats[label, cv2.CC_STAT_WIDTH], stats[label, cv2.CC_STAT_HEIGHT] cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2) # 显示图像 cv2.imshow('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的代码中,我们首先读取图像并进行二值化处理,然后使用`cv2.connectedComponentsWithStats()`方法获取连通域信息。接着,我们根据面积大小筛选出需要保留的连通域,并使用`cv2.rectangle()`方法框出这些连通域。最后,我们显示处理后的图像。 注意,上面的代码中我们设定了一个最小面积阈值`min_area`,面积小于该阈值的连通域将被删除。您可以根据自己的需求调整该阈值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

By-Q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值