原文链接:https://blog.csdn.net/sgzqc/article/details/119682864
一、简介
区域增长法是一种已受到计算机视觉界十分关注的图像分割方法。它是以区域为处理对象的,它考虑到区域内部和区域之间的同异性,尽量保持区域中像素的临近性和一致性的统一。这样就可以更好地分辨图像真正的边界。
基于区域的分割方法的关键在于定义一个一致性准则,用来判断两个邻接的区域是否可以合并,一致则将两区域合并,直到不能合并为止。区域增长的方法是在图像上选定一个种子点,记录下该点的灰度值,作为一致性判断的标准阈值,此外还需要定义一个标准差。
算法的主要过程是,依次用图像的每一个像素的灰度值和标准阈值相减,判断结果是否小于标准差,是则将该点和种子点合并,不是则保持像素点的灰度值不变。这样处理后的图像就是用区域分割法处理后的边缘分割图像。
二、实例
下面我们通过一个例子来进行详细的解释
上图示意的是区域增长的过程,图中的方格表示图像的像素点,方格中的数值表示像素点的灰度值。(a)表示开始选取的生长点,在生长的过程中,每个生长点都将本身上下左右4个像素点和初试选取的生长点比较灰度值,如果灰度值的差的绝对值在设定的阈值内,则认为这些点是属于相同区域并将其合并,否则将灰度差大于设定阈值的点删除,重复检查区域内的像素点,直到没有像素点可以合并位置。不妨设上图的阈值为2,(b)中4个点和初始点的灰度差都不大于2,所以合并;(c)中只有部分满足条件,所以只合并满足条件的像素点,并且(c)区域周围邻域中没有点再满足条件,因此生长结束。
三、算法步骤
通过上述示例,我们可以总结出区域增长法的一般步骤如下:
1)对图像自上而下,自左而右扫描,找到第1个还没有访问过的像素, 设该像素为(x0, y0);
2)以(x0, y0)为中心, 考虑(x0, y0)的8邻域像素(x, y),如果其邻域满足生长准则, 将(x, y)与(x0, y0)合并(在同一区域内), 同时将(x, y)压入堆栈;
3)从堆栈中取出一个像素, 把它当作(x0, y0)返回到上一步骤;
4)当堆栈为空时 返回到步骤1;
5)重复步骤1 - 4直到图像中的每个点都被访问过时,算法结束。
四、代码实现
1 读入彩色图像
img_name = "test.jpg" img = cv2.imread(img_name)
结果如下:
2 灰度化
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
结果如下:
3 二值化
def get_binary_img(img): # gray img to bin image bin_img = np.zeros(shape=(img.shape), dtype=np.uint8) h = img.shape[0] w = img.shape[1] for i in range(h): for j in range(w): bin_img[i][j] = 255 if img[i][j] > 127 else 0 return bin_img # 调用 bin_img = get_binary_img(gray_img)
结果如下:
4 选取初始种子点
这里选择三个种子点作为初始点,种子点的坐标如下图紫色十字所示。
out_img = np.zeros(shape=(bin_img.shape), dtype=np.uint8) # 选择初始3个种子点 seeds = [(176,255),(229,405),(347,165)] for seed in seeds: x = seed[0] y = seed[1] out_img[y][x] = 255
5 区域增长结果
# 8 邻域 directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)] visited = np.zeros(shape=(bin_img.shape), dtype=np.uint8) while len(seeds): seed = seeds.pop(0)# 将元素从列表中删弹出,默认最后一个 x = seed[0] y = seed[1] # visit point (x,y) visited[y][x] = 1 for direct in directs: cur_x = x + direct[0] cur_y = y + direct[1] # 非法 if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h : continue # 没有访问过且属于同一目标 if (not visited[cur_y][cur_x]) and (bin_img[cur_y][cur_x]==bin_img[y][x]) : out_img[cur_y][cur_x] = 255 visited[cur_y][cur_x] = 1 seeds.append((cur_x,cur_y))
结果如下:
6 获取目标
以上步得到的二值图作为mask,去彩色图中取对应的部分即可。代码如下:
bake_img = img.copy() h = bake_img.shape[0] w = bake_img.shape[1] for i in range(h): for j in range(w): if out_img[i][j] != 255: bake_img[i][j][0] = 0 bake_img[i][j][1] = 0 bake_img[i][j][2] = 0
结果如下:
7 完整代码
通过区域增长法来提取前景目标
# -*- coding:utf-8 -*- import cv2 import numpy as np def get_binary_img(img): # gray img to bin image bin_img = np.zeros(shape=(img.shape), dtype=np.uint8) h = img.shape[0] w = img.shape[1] for i in range(h): for j in range(w): bin_img[i][j] = 255 if img[i][j] > 80 else 0 return bin_img img_name = "test.jpg" img = cv2.imread(img_name) h = img.shape[0] w = img.shape[1] gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 调用 bin_img = get_binary_img(gray_img) out_img = np.zeros(shape=(bin_img.shape), dtype=np.uint8) # 选择初始3个种子点 seeds = [(176,255),(229,205),(307,165)] for seed in seeds: x = seed[0] y = seed[1] out_img[y][x] = 255 # 8 邻域 directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)] visited = np.zeros(shape=(bin_img.shape), dtype=np.uint8) while len(seeds): seed = seeds.pop(0) x = seed[0] y = seed[1] # visit point (x,y) visited[y][x] = 1 for direct in directs: cur_x = x + direct[0] cur_y = y + direct[1] # 非法 if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h : continue # 没有访问过且属于同一目标 if (not visited[cur_y][cur_x]) and (bin_img[cur_y][cur_x]==bin_img[y][x]) : out_img[cur_y][cur_x] = 255 visited[cur_y][cur_x] = 1 seeds.append((cur_x,cur_y)) bake_img = img.copy() h = bake_img.shape[0] w = bake_img.shape[1] for i in range(h): for j in range(w): if out_img[i][j] != 255: bake_img[i][j][0] = 0 bake_img[i][j][1] = 0 bake_img[i][j][2] = 0 cv2.imshow('image',img) cv2.imshow('rowgrow',bake_img) cv2.waitKey(0) cv2.destroyAllWindows()
通过设置阈值来控制生长条件
# -*- coding:utf-8 -*- import cv2 import numpy as np def get_binary_img(img): # gray img to bin image bin_img = np.zeros(shape=(img.shape), dtype=np.uint8) h = img.shape[0] w = img.shape[1] for i in range(h): for j in range(w): bin_img[i][j] = 255 if img[i][j] > 150 else 0 return bin_img img_name = "test.jpg" img = cv2.imread(img_name) h = img.shape[0] w = img.shape[1] gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) print(gray_img ) # 调用 # bin_img = get_binary_img(gray_img) out_img = np.zeros(shape=(gray_img.shape), dtype=np.uint8) # 选择初始3个种子点 seeds = [(276,155)] for seed in seeds: x = seed[0] y = seed[1] out_img[y][x] = 255 # 8 邻域 directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)] visited = np.zeros(shape=(gray_img.shape), dtype=np.uint8) while len(seeds): seed = seeds.pop(0) x = seed[0] y = seed[1] # visit point (x,y) visited[y][x] = 1 for direct in directs: cur_x = x + direct[0] cur_y = y + direct[1] # 非法 if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h : continue # 没有访问过且属于同一目标 if (not visited[cur_y][cur_x]) and (abs(int(gray_img[cur_y][cur_x])-int(gray_img[y][x]))<5.0) : out_img[cur_y][cur_x] = 255 visited[cur_y][cur_x] = 1 seeds.append((cur_x,cur_y)) bake_img = img.copy() h = bake_img.shape[0] w = bake_img.shape[1] for i in range(h): for j in range(w): if out_img[i][j] != 255: bake_img[i][j][0] = 0 bake_img[i][j][1] = 0 bake_img[i][j][2] = 0 cv2.imshow('rowgrow',bake_img) cv2.waitKey(0) cv2.destroyAllWindows()