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')
img = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(img, connectivity=8)
返回值
retval
>>> 3stats
>>> array([[ 0, 0, 10, 10, 76], [ 4, 1, 5, 6, 18], [ 2, 2, 3, 2, 6]], dtype=int32)labels
>>> 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)
之后又因为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:
for point in seedlist:image[point[0],point[1]] = 0img[y:y + h, x:x + w] = image
4 、结果:
原始图:
在这之前我尝试了一些别的函数,都不能很好的操作,下期会整理一下。