connected components algorithm连通组件算法

connected components algorithm连通图算法

什么是connected components algorithm?

用通俗的话说就是一个图像的前景部分有几部分构成,用下面的这幅图作为例子就是有三部分组成(用红线画出来了)
connected components algorithm连通组件算法_第1张图片
当我们在使用这个算法的过程中不可避免的会遇到这两个专业名词:
四邻域: 包括了中心点的上下左右四个方向的点
在这里插入图片描述
八邻域:包括周围8个点的关系,我自己认为8邻域的算法准确度更高
在这里插入图片描述

对图像进行标注

将该算法实施之后得到的图像会有标注,例如这一部分的区域是属于同一类的。为了让视觉效果等突出,我将采用connected Components algorithm算法的图像进行区域的上色(见下图)

connected components algorithm连通组件算法_第2张图片
connected components algorithm连通组件算法_第3张图片

connected components algorithm连通组件算法_第4张图片

算法复现以及伪代码

算法一:Two pass 法

伪代码:
input: image
output:bgr_image
将image进行二值化,但是不可以改变图片的轮廓信息
#第一遍pass
1.按行搜索不为零的元素,并查找其周围84)邻域是否有被标记过的元素;若有则将该点标记为邻域中最小的类别。并将邻域的类别进行union,说明虽然他们的类别不一样,但是实际上是同一类的。
#第二遍pass
1.按行搜索,将每一个类别不为零的pixel的类别标记为与之对应的集合里面的最小值。
该步骤结束就可以得到一个图像中的联通部分了
# -*- coding: utf-8 -*-
"""
4邻域关系做图像连通分割效果不好,改用8邻域

@author: ASUS
"""
import numpy as np
import cv2
import matplotlib.pyplot as plt

def find(image_class,pre_class,row,col):
    #若我们按行搜索,则该点的左边,左上,正上,右上会用于对其查找
    x_move = [0,-1,-1,-1]
    y_move = [-1,-1,0,1]
    x = []
    y = []
    length,width = image_class.shape
    for i in range(len(x_move)):
        a = row + x_move[i]
        b = col + y_move[i]
        if a >=0 and a < length and b>=0 and b< width and image_class[a,b]>0:
            x.append(a)
            y.append(b)
    if len(x)!= 0:
        class_p = np.min(image_class[x,y])
        image_class[row,col] = class_p
        
        M = image_class[x,y]
        index = np.where(M > class_p)
        if len(index[0]) != 0:
            for i in range(len(index[0])):
                weizhi = M[index[0][i]] -1 
                pre_class[weizhi] = class_p
    else:
        pre_class.append(0)
        image_class[row,col] = len(pre_class)
    
    return image_class,pre_class
            
        

image = cv2.imread('morphology.JPG',0)
ret,image=cv2.threshold(image,50,255,cv2.THRESH_BINARY) #这里的binary的阈值不能太高,太高会改变图像的连接信息
index = np.where(image == 255)
image_class = np.zeros(image.shape,dtype = np.uint8)
pre_class = []
for i in range(len(index[0])):
    image_class,pre_class = find(image_class,pre_class,index[0][i],index[1][i])

for i in range(len(pre_class)):
    k = i+1
    while pre_class[k-1] != 0:
        k = pre_class[k-1]

    image_class[np.where(image_class == i+1)] = k
    
bgr_image = np.zeros((image.shape[0],image.shape[1],3),dtype = np.uint8)
union = np.unique(image_class)
for i in range(len(union)-1):
    bgr = np.random.randint(0,255,(3))
    bgr_image[np.where(image_class == union[i+1])] = bgr


plt.subplot(121)
plt.imshow(image,'gray')
plt.title('Original')
plt.axis('off')
plt.subplot(122)
plt.imshow(bgr_image)
plt.title('after connect components algorithm')
plt.axis('off')
plt.show()

# cv2.namedWindow('123', cv2.WINDOW_NORMAL)
# cv2.imshow('123',bgr_image)
# a = cv2.waitKey(0)
# cv2.destroyAllWindows()
# print(a)

算法一复现难点:在编写代码的时候发现在union部分会出现难点。需要一些技巧来解决。我用的是父节点法,具体解决方法见代码。
算法动图描述:
connected components algorithm连通组件算法_第5张图片

算法二:遍历法
该方法比较简单,易于实现,相比来说其运行时间和空间复杂度相比于第一种都会好一些。

首先我们对输入图像进行二值化操作。
按行搜索,遇到不为零的pixel且类别不为零的点:
{1.初始化队列,将该pxiel入队
2.取出队列头并将队列头相连的pxiel入队(需要满足像素值大于零,且class不为零)
3.若队列空,则跳出,继续搜索。否则返回2
}
直到对完整的一幅图像完成搜索。

参考的博客

https://iq.opengenus.org/connected-component-labeling/

你可能感兴趣的:(数字图像处理,算法,opencv)