Python实现多种图像分割方法:基于阈值分割和基于区域分割

news/2024/7/21 5:56:05 标签: python, 图像处理

Python实现多种图像分割方法:基于阈值分割和基于区域分割

图像分割是图像分析的第一步,是计算机视觉的基础,但也是图像处理中最困难的问题之一。经典的计算机视觉任务,如目标检测、图像识别等都和图像分割相关,图像分割的好不好直接决定目标检测识别的准确不准确。

本文首先介绍了基于阈值和区域增长的图像分割方法。

然后针对图片中的书本和窗户旁边的人进行实验,并结合同态滤波和形态学算法对识别效果进行了优化。

图像分割

分割是指根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交的区域,使得这些特征在同一区域内表现出一致性或相似性,而在不同区域间表现出明显的不同。简单的说就是在一幅图像中,把目标从背景中分离出来。

图像分割实质上是图像处理到图像分析的关键步骤,图像分割的好坏直接决定了后期图像分析的精准性。因此我们需要根据图像的特征设计不同的图像分割方法。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。

基于阈值的图像分割

基于阈值的分割方法,是指基于图像的灰度特征来计算一个或多个灰度阈值,并将图像中每个像素的灰度值与阈值作比较,最后将像素根据比较结果分到合适的类别中。因此,该方法最为关键的一步就是按照某个准则函数来求解最佳灰度阈值。之所以能对灰度图像采用阈值分割,是因为灰度图像中区域内部的像素一般具有灰度相似性,而在区域的边界上一般具有灰度不连续性。所以阈值法特别适用于目标和背景占据不同灰度级范围的图片。

常用的阈值分割方法有Ostu阈值分割,自适应阈值分割,最大熵阈值分割,迭代阈值分割等。

图像若只有目标和背景两大类,那么只需要选取一个阈值进行分割,此方法成为单阈值分割;但是如果图像中有多个目标需要提取,单一阈值的分割就会出现作物,在这种情况下就需要选取多个阈值将每个目标分隔开,这种分割方法称为多阈值分割。本文主要采用的是单阈值分割法。

阀值分割方法的优点是计算简单且效率高,但缺点是只考虑了像素点灰度值本身的特征,没有考虑空间特征,因此对噪声比较敏感,鲁棒性不高。

由于阈值分割方法的关键在于阈值的选择,因此如果能将智能遗传算法应用在阀值筛选上,选取最优分割图像的阀值,能够更进一步提升阈值图像分割方法的效果。

基于区域的图像分割

基于区域的分割方法是以直接寻找区域为基础的分割技术,有两种基本形式:一种是基于区域生长的方式,从单个像素出发,逐步合并以形成所需要的分割区域;另一种是基于区域分裂的方式,从全局出发,逐步切割至所需的分割区域。

本文采用的是基于区域增长的方法,区域生长是指从一组代表不同生长区域的种子像素开始,接下来将种子像素邻域里符合条件的像素合并到种子像素所代表的生长区域中,并将新添加的像素作为新的种子像素继续合并过程,直到找不到符合条件的新像素为止,该方法的关键是选择合适的初始种子像素以及合理的生长准则。基于区域增长的方法计算也相对简单,同时对于较均匀的连通目标有较好的分割效果,但也经常会出现欠生长或过生长的情况。

区域生长算法需要解决的三个问题:

(1)选择或确定一组能正确代表所需区域的种子像素;

(2)确定在生长过程中能将相邻像素包括进来的准则;

(3)指定让生长过程停止的条件或规则。

形态学算法

形态学算法一般是针对二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建等。基本的算法:膨胀、腐蚀、开操作和闭操作。形态学算法可以保持图像基本的形状特征,并除去不相干的结构特征。因此可以引入形态学算法来改善图像分割的效果。

Python代码实现图像分割

导入包:

python">import cv2
from  matplotlib import pyplot as plt
%matplotlib inline

读取原始图和灰度化:

python">def cv_show(name,img):
    cv2.namedWindow(name,0)
    cv2.resizeWindow(name,700,900)
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
raw_person = cv2.imread('images/person.png')
cv_show('raw_person', raw_person)

gray_person = cv2.imread('images/person.png', flags=cv2.IMREAD_GRAYSCALE)
cv_show('gray_person', gray_person)
cv2.imwrite('results/person/gray_person.jpg',gray_person)

绘制灰度图和灰度直方图:

python">import numpy as np
hist = np.histogram(gray_person, bins=np.arange(0, 256), normed=True)
fig, axes = plt.subplots(1, 2, figsize=(20, 10))
axes[0].imshow(gray_person, cmap=plt.cm.gray, interpolation='nearest')
axes[0].axis('off')
axes[1].plot(hist[1][:-1], hist[0], lw=2)
axes[1].set_title('histogram of gray values')
plt.show()

定义形态学算法函数:

python">def img_morph(img, size=5, method='open', element='rect'):
    '''
    img: binary image
    size: the size of square used to do morphological filtering
    method: open or close or erode or dilate
    element: structure element, rect or circle or cross
    '''
    if element == 'rect':
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (size, size))
    elif element == 'circle':
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (size, size))
    elif element == 'cross':
        kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (size, size))

    if method == 'open':
        img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    elif method == 'close':
        img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    elif method == 'erode':
        img = cv2.morphologyEx(img, cv2.MORPH_ERODE, kernel)
    elif method == 'dilate':
        img = cv2.morphologyEx(img, cv2.MORPH_DILATE, kernel)
    
    return img

基于阈值的图像分割:

python">t0=170
segmented_gray_img2 = np.where(gray_person[...,:] < t0, 255, 0).astype(np.uint8)

cv_show('segmented_gray_image',segmented_gray_img2)

形态学滤波:

python">open_person=img_morph(segmented_gray_img2,size=200,method='open')
cv_show('open_person', open_person)

dilate_person=img_morph(open_person,size=10,method='dilate')
cv_show('dilate_person', dilate_person)

close_person=img_morph(dilate_person,size=100,method='close')
cv_show('close_person', close_person)

dilate_person1=img_morph(close_person,size=20,method='dilate')
cv_show('dilate_person1', dilate_person1)

segmented_person=cv2.bitwise_and(raw_person,raw_person,mask=dilate_person1)
cv_show('segmented_person', segmented_person)
cv2.imwrite('results/person/segmented_threshold_person.jpg',segmented_person)

基于区域增长的图像分割:

python">def region_grow(img, seeds, threshold):
    '''
    select the bgd pixel attentionally to simplify the problem
    img: gray scale image
    seeds: the seed pixels
    '''
    seed_list = seeds
    neighbors = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
    is_search = np.zeros(img.shape)
    is_add = np.zeros(img.shape)
    for seed in seeds:
        is_add[seed[0], seed[1]] = 1
    grow_img = np.ones(img.shape).astype(np.uint8)*255
    # mean_value = img[seed[0], seed[1]]
    cnt = 1
    while(len(seed_list)>0):
        cnt += 1
        seed = seed_list.pop()
        grow_img[seed[0], seed[1]] = 0
        is_search[seed[0], seed[1]] = 1
        for neighbor in neighbors:
            # print(neighbor, seed)
            neighbor_x = seed[0]+neighbor[0]
            neighbor_y = seed[1]+neighbor[1]
            if neighbor_x < 0 or neighbor_y < 0 or neighbor_x >= img.shape[0] or neighbor_y >= img.shape[1]:
                continue
            elif is_search[neighbor_x, neighbor_y] == 1 or is_add[neighbor_x, neighbor_y] == 1:
                continue
            # elif abs(img[neighbor_x, neighbor_y] - mean_value) > threshold:
            elif abs(float(img[neighbor_x, neighbor_y]) - float(img[seed[0],seed[1]])) > threshold:
                continue
            else:
                seed_list.insert(0, [neighbor_x, neighbor_y])
                is_add[neighbor_x, neighbor_y] = 1
                # mean_value = mean_value/cnt+img[neighbor_x, neighbor_y]/cnt
                # print(mean_value)
                # grow_img[neighbor_x, neighbor_y] = 0
    return grow_img

seeds = [[341,942],[1510,960],[773,931],[2018,949]]
grow_person = region_grow(gray_person, seeds, 4)
grow_person = 255-grow_person
cv_show('grow_person',grow_person)

open_grow_person=img_morph(grow_person,size=50,method='open')
cv_show('open_grow_person', open_grow_person)

close_grow_person1=img_morph(open_grow_person,size=200,method='close')
cv_show('close_grow_person1', close_grow_person1)

segmented_region_person = cv2.bitwise_and(raw_person,raw_person,mask= close_grow_person1)
cv_show('segmented_region_person',segmented_region_person)
cv2.imwrite('results/person/segmented_region_person.jpg',segmented_region_person)

更多详细代码发布在https://github.com/JeremyChou28/digital_image_processing/tree/main/project4


http://www.niftyadmin.cn/n/5261646.html

相关文章

MetaAI发布Seamless:两秒内实现跨语言同声传译

在当今日益互联的世界中&#xff0c;语言差异常常成为沟通的障碍。MetaAI最新发布的语音翻译大模型Seamless&#xff0c;正是为打破这一障碍而生。Seamless不仅提供流畅、高效的多语言翻译功能&#xff0c;更在保留说话人韵律和风格方面取得突破&#xff0c;是AI同声传译领域的…

Spring的AOP基于注解之准备工作(需要添加的依赖以及配置文件)

添加完依赖会爆红&#xff0c;点击m标刷新即可 使用SpringAspectJ的AOP需要引入的依赖如下&#xff1a; <repositories><!--spring6里程碑版本的仓库--><repository><id>repository.spring.milestone</id><name>Spring Milestone Reposi…

Python创建代理IP池详细教程

一、问题背景 在进行网络爬虫或数据采集时&#xff0c;经常会遇到目标网站对频繁访问的IP进行封禁的情况&#xff0c;为了规避这种封禁&#xff0c;我们需要使用代理IP来隐藏真实IP地址&#xff0c;从而实现对目标网站的持续访问。 二、代理IP池的基本概念 代理IP池是一个包…

ACM-MM2023 DITN详解:一个部署友好的超分Transformer

目录 1. Introduction2. Method2.1. Overview2.2. UFONE2.3 真实场景下的部署优化 3. 结果 Paper: Unfolding Once is Enough: A Deployment-Friendly Transformer Unit for Super-Resolution Code: https://github.com/yongliuy/DITN 1. Introduction CNN做超分的缺点 由于卷…

医院患者职工食堂订餐,订餐系统,食堂报餐系统,医院订餐系统

主要功能&#xff1a; 1.患者管理&#xff1a;患者订单信息&#xff0c;患者床位信息 2.菜品管理&#xff1a;价格&#xff0c;图片&#xff0c;规格 3.订餐类型管理&#xff1a;早中晚&#xff0c;日期 4.病房床位管理&#xff1a;科室->床位 5.收入汇总 下单后食堂打印机…

C语言float何时表达6位有效数字,何时表达7位有效数字?

C语言float何时表达6位有效数字&#xff0c;何时表达7位有效数字&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「C语言的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;…

redis-学习笔记(Jedis set 简单命令)

sadd & smembers sadd 往 set 中添加数据, 第二个参数仍是变长参数 smembers 查看 set 中的元素 示例代码 sismember 判断在 set 中该值存不存在 示例代码 scard 查看 set 中元素的数量 示例代码 spop 随机删除一个 set 中的值 示例代码 sinter & sinterstore 求多个 s…

SQL、Jdbc、JdbcTemplate、Mybatics

数据库&#xff1a;查询&#xff08;show、select&#xff09;、创建&#xff08;create)、使用(use)、删除(drop)数据库 表&#xff1a;创建&#xff08;【字段】约束、数据类型&#xff09;、查询、修改&#xff08;alter *add&#xff09;、删除 DML&#xff1a;增加(inse…