头歌 基于区域的图像分割——区域生长

任务描述
本关任务:学习并完成基于区域生长的图像分割算法。

相关知识
为了完成本关任务,你需要掌握:1.区域生长算法,2.如何实现区域生长算法。

区域生长算法
区域生长算法是一种基于像素相似性的图像分割算法,旨在将图像中相似的像素点组合成连通的区域。该算法从一个或多个种子点开始,逐步生长扩展,将与种子点相似的像素点归为同一个区域。

以下是区域生长算法的基本步骤:

选择种子点:从图像中选择一个或多个像素点作为种子点。通常情况下,种子点是根据特定的准则或用户交互选择的。

定义相似性准则:确定像素点之间的相似性度量标准。这通常是基于像素的灰度值、颜色值、纹理特征等。

定义生长准则:确定像素生长的条件。这个条件通常是基于像素之间的相似性度量和阈值。例如,当两个像素的相似性大于阈值时,它们被认为是同一个区域的一部分。

初始化标记图像:创建一个与原始图像大小相同的标记图像,用于记录每个像素点所属的区域。

开始生长扩展:从种子点开始,逐步扩展区域生长。一般情况下,使用队列或栈数据结构来管理待生长的像素点。

扩展过程:对于当前的生长像素点,根据生长准则和相似性度量,将其与相邻像素点进行比较。如果相邻像素点与当前像素点相似且尚未标记,则将其标记为同一区域,并加入待生长队列或栈中。

继续生长:重复步骤6,直到没有更多的待生长像素点。

输出结果:最终得到标记图像,每个像素点被分配一个唯一的标签,表示其所属的区域。

区域生长算法的优点是简单且易于实现,对于具有均匀纹理、明显边界或明显对比度的图像分割效果较好。然而,该算法对于光照变化、噪声或复杂背景的图像可能会产生较差的分割结果。因此,在实际应用中,可能需要结合其他算法或改进区域生长算法以适应不同的图像场景。

如何实现区域生长算法
区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素具有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当做新的种子像素继续进行上面的过程,直到再没有满足条件的像素可被包括进来,这样,一个区域就长成了。
  区域生长的算法实现:

根据图像的不同应用选择一个或一组种子,它或者是最亮或最暗的点,或者是位于点簇中心的点,当然也可以手动选择种子点。
选择一个描述符(条件),常见的有基于区域灰度差、基于区域灰度分布统计性质。
从该种子开始向外扩张,首先把种子像素加入结果集合,然后不断将与集合中各个像素连通、且满足描述符的像素加入集合。
上一过程进行到不再有满足条件的新结点加入集合为止。


实现案例

# 计算种子点和其领域的像素值之差
def getGrayDiff(gray, current_seed, tmp_seed):
    return abs(int(gray[current_seed[0], current_seed[1]]) - int(gray[tmp_seed[0], tmp_seed[1]]))
# 区域生长算法
def regional_growth(gray, seeds):
    # 八领域
    connects = [(-1, -1), (0, -1), (1, -1), (1, 0), \
                (1, 1), (0, 1), (-1, 1), (-1, 0)]
    seedMark = np.zeros((gray.shape))
    height, width = gray.shape
    threshold = 6
    seedque = deque()
    label = 255
    seedque.extend(seeds)
    
    while seedque:
        # 队列具有先进先出的性质。所以要左删
        current_seed = seedque.popleft()
        seedMark[current_seed[0], current_seed[1]] = label
        for i in range(8):
            tmpX = current_seed[0] + connects[i][0]
            tmpY = current_seed[1] + connects[i][1]
            # 处理边界情况
            if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= width:
                continue
            grayDiff = getGrayDiff(gray, current_seed, (tmpX, tmpY))
            if grayDiff < threshold and seedMark[tmpX, tmpY] != label:
                seedque.append((tmpX, tmpY))
                seedMark[tmpX, tmpY] = label
    return seedMark
getGrayDiff(gray, current_seed, tmp_seed): 这个函数用于计算当前种子点和其领域像素点之间的灰度值差异。它接收三个参数:gray 表示灰度图像,current_seed 表示当前种子点的坐标,tmp_seed 表示待比较的邻域像素点的坐标。函数内部通过索引访问灰度图像的对应像素值,并计算其差的绝对值。最后返回两个像素值之间的差异。

regional_growth(gray, seeds): 这个函数实现了区域生长算法。它接受以下参数:
gray: 灰度图像,表示待处理的图像。
seeds: 种子点的坐标列表。
函数首先定义了八领域的连接关系,即每个像素点周围八个相邻像素的相对位置。然后,它创建一个与原始图像大小相同的标记图像 seedMark,用于记录每个像素点所属的区域。

接下来,函数初始化了一些变量,包括图像的高度和宽度、生长阈值、种子点队列等。然后,它开始对种子点进行生长扩展。

在生长过程中,函数使用队列 seedque 来管理待处理的像素点。它从队列中取出当前的种子点,将其标记为指定的标签,并遍历种子点的八个相邻像素。对于每个相邻像素,函数检查其是否满足生长条件:灰度差异小于阈值,并且未被标记为已处理。如果满足条件,邻域像素将被添加到队列中,并被标记为同一区域。

该过程重复进行,直到队列中没有更多待处理的像素点。最终,函数返回标记图像 seedMark,其中每个像素点被赋予一个唯一的标签,表示其所属的区域。

这两个函数共同实现了区域生长算法的关键步骤:计算像素差异并扩展区域生长。通过调用这两个函数,可以对图像进行区域生长分割,并得到分割后的结果。

编程要求
根据提示,在右侧编辑器补充代码,实现图像分割——区域生长法。

测试说明
平台会对你编写的代码进行测试:

测试输入:

 

预先给定的种子列表 

seed = [(129, 593), (117, 641), (111, 667), (118, 680), (132, 713), (133, 680), (127, 651), (163, 746), (164, 773),
        (169, 807), (171, 829), (202, 856), (227, 869), (250, 888), (290, 879), (336, 878), (384, 882), (433, 890),
        (478, 894), (491, 885), (517, 838), (563, 833), (596, 823), (636, 805), (658, 800), (735, 769), (769, 787),
        (809, 799), (851, 801), (843, 788), (901, 798), (927, 820), (975, 844), (1008, 842), (1057, 834), (1106, 833),
        (1148, 808), (1145, 798), (1136, 799), (1110, 803), (1074, 792), (1035, 784), (975, 759), (895, 736),
        (860, 719), (793, 694), (726, 682), (688, 673), (700, 636), (772, 628), (832, 627), (895, 624), (925, 625),
        (972, 640), (1024, 632), (1070, 620), (1096, 628), (1110, 618), (1118, 563), (1119, 499), (1113, 514),
        (1100, 544), (1088, 584), (1044, 580), (992, 563), (923, 544), (896, 535), (858, 525), (831, 526), (797, 560),
        (738, 591), (682, 590), (647, 600), (650, 582), (732, 541), (760, 526), (753, 551), (620, 637), (515, 629),
        (434, 572), (473, 543), (540, 515), (595, 477), (666, 454), (694, 455), (636, 441), (585, 450), (533, 483),
        (483, 507), (431, 513), (399, 513), (369, 517), (344, 543), (342, 618), (286, 615), (255, 562), (236, 560),
        (204, 556), (177, 565), (161, 586), (138, 635), (195, 618), (222, 648), (226, 586), (207, 627), (271, 633),
        (222, 730), (342, 720), (358, 644), (413, 588), (436, 678), (454, 642), (524, 659), (437, 678), (571, 621),
        (630, 599), (657, 708), (555, 760), (428, 764), (494, 721), (603, 731), (651, 737), (399, 757), (400, 756)]
预期输出:


开始你的任务吧,祝你成功!

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from collections import deque

##########begin##########
# 计算种子点和其领域的像素值之差
def getGrayDiff(gray, current_seed, tmp_seed):
    return abs(int(gray[current_seed[0], current_seed[1]]) - int(gray[tmp_seed[0], tmp_seed[1]]))




# 区域生长算法
def regional_growth(gray, seeds):
    # 八领域
    connects = [(-1, -1), (0, -1), (1, -1), (1, 0), \
                (1, 1), (0, 1), (-1, 1), (-1, 0)]
    seedMark = np.zeros((gray.shape))
    height, width = gray.shape
    threshold = 6
    seedque = deque()
    label = 255
    seedque.extend(seeds)

    while seedque:
        # 队列具有先进先出的性质。所以要左删
        current_seed = seedque.popleft()
        seedMark[current_seed[0], current_seed[1]] = label
        for i in range(8):
            tmpX = current_seed[0] + connects[i][0]
            tmpY = current_seed[1] + connects[i][1]
            # 处理边界情况
            if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= width:
                continue

            grayDiff = getGrayDiff(gray, current_seed, (tmpX, tmpY))
            if grayDiff  < threshold and seedMark[tmpX, tmpY] !=  label:
                seedque.append((tmpX, tmpY))
                seedMark[tmpX, tmpY] = label
    return seedMark
    ##########end##########



def Region_Grow(img,seed):
    for i in seed:
        # 在图像上画出实心点位
        cv.circle(img, center=(i[-1],i[0]), radius=5,color=(0, 0, 255), thickness=-1)

    # 进行区域生长分割
    astronaut = cv.imread('imgs/astronaut.png', 1)
    seedMark = np.uint8(regional_growth(cv.cvtColor(astronaut, cv.COLOR_BGR2GRAY), seed))

    # 绘制并保存
    plt.figure(figsize=(16, 6))
    plt.subplot(131), plt.imshow(cv.cvtColor(astronaut, cv.COLOR_BGR2RGB))
    plt.axis('off'), plt.title(f'$input\_image$')
    plt.subplot(132), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
    plt.axis('off'), plt.title(f'$seeds\_image$')
    plt.subplot(133), plt.imshow(seedMark, cmap='gray', vmin=0, vmax=255)
    plt.axis('off'), plt.title(f'$segmented\_image$')
    plt.savefig('img_user/astronaut.png')





 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值