实验前言与目的
这些算法都属于【基于形态学的图像分割】这一范畴,我们最终做的一切,都是为了图像分割(比如分成黑白两块,相对提取物体主题,为物体描轮廓…)
编写程序完成以下算法,并进行比较,得出结论。
- 区域生长算法
- 区域分裂合并算法
- 分水岭分割算法
1、区域生长算法
参考:https://blog.csdn.net/weixin_43487953/article/details/97395528
注意
- 区域生长是一种图像分割方法。
- 区域生长从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止,进而实现目标的提取。
- 区域生长的好坏决定于:1.初始点(种子点)的选取。2.生长准则。3.终止条件。
- 个人感悟:这个算法平均感觉都挺慢的,我运行一个狗子的图,即使换了不同的种子,平均也在10S~20S之间。
PPT思路
本程序思路:
- 先生成同样大小空白矩阵
- 设置一个种子点,通过计算判断周围是否有符合条件新种子,编写在空白矩阵中
- 通过循环可以获得含有种子标志的新矩阵,将矩阵与原图相乘可以得到利用区域生长分割出的图像。
备注:由于代码不长,所以思路主要用备注写代码里了、
输入图像经过区域生成算法之后的效果:
代码
################################################
#################区域生成算法###################
################################################
def 区域生成法(img):
img_array = np.array(img)#图片转为数组方便操作
[m,n]=img_array.shape#返回图片的长和宽
a = np.zeros((m,n)) #建立等大小空矩阵
a[70,70]=1 #设立种子点
k = 40 #设立生长阈值
isMyArea=1
#开始循环遍历周围像素,种子长大。
while isMyArea==1:
isMyArea=0
lim = (np.cumsum(img_array*a)[-1])/(np.cumsum(a)[-1])
for i in range(2,m):
for j in range(2,n):
if a[i,j]==1:
for x in range(-1,2):
for y in range(-1,2):
if a[i+x,j+y]==0:
if (abs(img_array[i+x,j+y]-lim)<=k) :
isMyArea = 1
a[i+x,j+y]=1
print("我是区域,我正在生长...")
data = img_array*a #矩阵相乘获取生长图像的矩阵
new_img = Image.fromarray(data) #data矩阵转化为二维图片
return new_img
2、区域分裂合并算法
参考:
https://www.jianshu.com/p/fa573431ef3d
- 个人感觉,这个分割算法有点【微积分】那种感觉了。
- 不用像区域生长一样还要选个“种子点”,算法比较“稳”?
算法的思想总的来说,就是:
- 先把图像分成4块
- 若这其中的一块符合分裂条件,那么这一块又分裂成4块
- 分裂到一定数量时,以每块为中心,检查相邻的各块,满足一定条件,就合并。
- 如此循环往复进行分裂和合并的操作。
- 最后合并小区,即把一些小块图像的合并到旁边的大块里。
注意
- 本次切割图像不使用专门的库,而是直接通过控制img[x,y,weight,height]来最原图片的一个个小区域直接操作(具体操作是二值化)。
- 从最终成像来看,区域分裂与合并算法的确具有一定的连续性,不会出现黑图中夹杂着一丝白丝儿的那种噪声。
效果图
代码
import numpy as np
import cv2
import matplotlib.pyplot as plt # plt 用于显示图片
#判断方框是否需要再次拆分为四个
def judge(w0, h0, w, h):
a = img[h0: h0 + h, w0: w0 + w]
ave = np.mean(a)
std = np.std(a, ddof=1)
count = 0
total = 0
for i in range(w0, w0 + w):
for j in range(h0, h0 + h):
#注意!我输入的图片数灰度图,所以直接用的img[j,i],RGB图像的话每个img像素是一个三维向量,不能直接与avg进行比较大小。
if abs(img[j, i] - ave) < 1 * std:
count += 1
total += 1
if (count / total) < 0.95:#合适的点还是比较少,接着拆
return True
else:
return False
##将图像将根据阈值二值化处理,在此默认125
def draw(w0, h0, w, h):
for i in range(w0, w0 + w):
for j in range(h0, h0 + h):
if img[j, i] > 125:
img