区域生长法是较为基础的一种区域分割方法
它的基本思想我说的通俗些,即是一开始有一个生长点(可以一个像素也可以是一个小区域),从这个生长点开始往外扩充,扩充的意思就是它会把跟自己有相似特征的像素或者区域拉到自己的队伍里,以此壮大自己的势力范围,每次扩大后的势力范围就是一个新的生长点,一直生长一直生长,直到不能生长为止。
所以很容易就能总结出来三个要点:
(1)一个合适的像素或者小区域作为开始的生长点
(2)生长准则,也就是通过什么标准你才能拉他入伙
(3)停止生长的条件 什么时候停止扩充
下面是一个简单的例子:
import cv2
import numpy as np
####################################################################################
#######################################################################################
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
connects = [
Point(-1, -1),
Point(0, -1),
Point(1, -1),
Point(1, 0),
Point(1, 1),
Point(0, 1),
Point(-1, 1),
Point(-1, 0)
]
#####################################################################################
# 计算两个点间的欧式距离
def get_dist(seed_location1, seed_location2):
l1 = im[seed_location1.x, seed_location1.y]
l2 = im[seed_location2.x, seed_location2.y]
count = np.sqrt(np.sum(np.square(l1 - l2)))
return count
# import Image
im = cv2.imread('./7.jpg')
cv2.imshow('src', im)
im_shape = im.shape
height = im_shape[0]
width = im_shape[1]
print('the shape of image :', im_shape)
# 标记,判断种子是否已经生长
img_mark = np.zeros([height, width])
cv2.imshow('img_mark', img_mark)
# 建立空的图像数组,作为一类
img_re = im.copy()
for i in range(height):
for j in range(width):
img_re[i, j][0] = 0
img_re[i, j][1] = 0
img_re[i, j][2] = 0
cv2.imshow('img_re', img_re)
# 取一点作为种子点
seed_list = []
seed_list.append(Point(15, 15))
T = 7 # 阈值
class_k = 1 # 类别
# 生长一个类
while (len(seed_list) > 0):
seed_tmp = seed_list[0]
# 将以生长的点从一个类的种子点列表中删除
seed_list.pop(0)
img_mark[seed_tmp.x, seed_tmp.y] = class_k
# 遍历8邻域
for i in range(8):
tmpX = seed_tmp.x + connects[i].x
tmpY = seed_tmp.y + connects[i].y
if (tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= width):
continue
dist = get_dist(seed_tmp, Point(tmpX, tmpY))
# 在种子集合中满足条件的点进行生长
if (dist < T and img_mark[tmpX, tmpY] == 0):
img_re[tmpX, tmpY][0] = im[tmpX, tmpY][0]
img_re[tmpX, tmpY][1] = im[tmpX, tmpY][1]
img_re[tmpX, tmpY][2] = im[tmpX, tmpY][2]
img_mark[tmpX, tmpY] = class_k
seed_list.append(Point(tmpX, tmpY))
########################################################################################
# 输出图像
cv2.imshow('OUTIMAGE', img_re)
cv2.waitKey(0)
区域生长法的优点是计算简单,对于较均匀的连通目标有较好的分割效果。
缺点是需要人为确定种子点,对噪声敏感,可能导致区域内有空洞。另外当目标较大时,分割速度较慢,因此在设计算法时,要尽量提高效率。
分裂和聚合
具体来说 举个例子
区域分裂与聚合就是判断一个区域的均值和方差是不是在人为设定的阈值中,如果是的话这个区域分割出来,不是的话就将这个区域分为左上、右上、左下、右下四个部分再递归判断,直到最后结束。
import cv2 as cv
import numpy as np
class region_div:
def __init__(self, img):
self.img = img
self.res = np.zeros(img.shape)
def region_div_group(self, range1, range2):
if range1[1] - range1[0] == 0 or range2[1] - range2[0] == 0:
return
mean = self.img[range1[0]:range1[1], range2[0]:range2[1]].mean()
var = self.img[range1[0]:range1[1], range2[0]:range2[1]].var()
# print(self.img[range1[0]:range1[1],range2[0]:range2[1]])
# print(range1, range2, var)
if var < 10:
self.res[range1[0]:range1[1], range2[0]:range2[1]] = 255
else:
if range1[1] - range1[0] >= 2 and range2[1] - range2[0] >= 2:
self.region_div_group(
[range1[0], (range1[0] + range1[1]) // 2],
[range2[0], (range2[0] + range2[1]) // 2])
self.region_div_group(
[(range1[0] + range1[1]) // 2, range1[1]],
[range2[0], (range2[0] + range2[1]) // 2])
self.region_div_group(
[range1[0], (range1[0] + range1[1]) // 2],
[(range2[0] + range2[1]) // 2, range2[1]])
self.region_div_group(
[(range1[0] + range1[1]) // 2, range1[1]],
[(range2[0] + range2[1]) // 2, range2[1]])
image = cv.imread('./8.jpg')
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
# print(gray.shape)
# print(gray[0:1, 5:11])
res = np.zeros(gray.shape)
rd = region_div(gray)
rd.region_div_group([0, gray.shape[0]], [0, gray.shape[1]])
res = rd.res
cv.namedWindow("gray")
cv.imshow("gray", gray)
cv.waitKey(0)
cv.namedWindow("res")
cv.imshow("res", res)
cv.waitKey(0)