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

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

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

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

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

图像分割

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

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

基于阈值的图像分割

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

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

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

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

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

基于区域的图像分割

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

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

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

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

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

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

形态学算法

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

Python代码实现图像分割

导入包:

import cv2
from  matplotlib import pyplot as plt
%matplotlib inline

读取原始图和灰度化:

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)

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

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()

定义形态学算法函数:

def img_morph(img, size=5, method='open', element='rect'):'''img: binary imagesize: the size of square used to do morphological filteringmethod: open or close or erode or dilateelement: 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

基于阈值的图像分割:

t0=170
segmented_gray_img2 = np.where(gray_person[...,:] < t0, 255, 0).astype(np.uint8)cv_show('segmented_gray_image',segmented_gray_img2)

形态学滤波:

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)

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

def region_grow(img, seeds, threshold):'''select the bgd pixel attentionally to simplify the problemimg: gray scale imageseeds: the seed pixels'''seed_list = seedsneighbors = [[-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]] = 1grow_img = np.ones(img.shape).astype(np.uint8)*255# mean_value = img[seed[0], seed[1]]cnt = 1while(len(seed_list)>0):cnt += 1seed = seed_list.pop()grow_img[seed[0], seed[1]] = 0is_search[seed[0], seed[1]] = 1for 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]:continueelif 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:continueelse: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] = 0return grow_imgseeds = [[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.mzph.cn/news/227843.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为OD机试真题-多段线数据压缩-2023年OD统一考试(C卷)

题目描述: 下图中,每个方块代表一个像素,每个像素用其行号和列号表示。 为简化处理,多段线的走向只能是水平、竖直、斜向45度。 上图中的多段线可以用下面的坐标串表示:(2, 8), (3, 7), (3, 6), (3, 5), (4, 4), (5, 3), (6, 2), (7, 3), (8, 4), (7, 5)。 但可以发现,这…

springboot整合webflux访问openai接口报错

报错信息: org.springframework.web.reactive.function.client.WebClientRequestException: 远程主机强迫关闭了一个现有的连接。; nested exception is java.io.IOException: 远程主机强迫关闭了一个现有的连接。at org.springframework.web.reactive.function.client.Excha…

栈和队列的实现(Java篇)

文章目录 一、栈的概念二、栈的实现2.1压栈(push)2.2出栈(pop)2.3获取栈顶元素(peek)2.4判断栈是否为空(isEmpty)栈的实现测试 三、队列的概念四、队列的实现4.1入队(offer)4.2出队(poll)4.3判断队列是否为空4.4获取对头元素队列的实现测试 五、循环队列5.1入队5.2出队5.3获取队…

MAMOS蓝图: 打造自己的质量工程

针对团队中存在的问题&#xff0c;构造MAMOS蓝图&#xff0c;从而以系统化的方式识别并解决问题。本文将针对减少等待时间这一问题举例说明MAMOS蓝图的组成和使用方式。原文: MAMOS Blueprint: Build your own for Quality at Speed 很难完全摆脱等待时间。 我认为没有必要争论…

vue脚手架安装及使用

准备工作 安装node安装cnpm cnpm是npm的“廉价平替” 提高安装速度 npm install -g cnpm --registryhttps://registry.npm.taobao.org 安装脚手架 安装Vue脚手架 cnpm install -g vue/cli 用vue脚手架创建vue项目 找好创建项目的位置 创建项目 vue create test (test为项…

用代码写uml并在线生成uml图

可以用PlantUml写uml,并在线生成uml图。 startuml start:登录系统; if (用户名和密码正确?) then (yes):进入系统首页;:展示主菜单; else (no):显示登录错误;stop endif:选择模块; partition "课程信息" {:查看课程列表;:查看课程详情; } partition "课程签到…

【计算机视觉】SIFT

在边缘提取的时候&#xff0c;用高斯一阶导对信号进行卷积&#xff0c;响应值最大的就是边界如果用高斯二阶导对信号进行卷积&#xff0c;0点就是边界点&#xff08;二阶导等于0的点&#xff0c;对应一阶导的极值点&#xff09; 如果用高斯二阶导在不同的信号上进行卷积&#x…

【Vue原理解析】之响应式系统

引言 Vue2的响应式系统是核心之一&#xff0c;它使得Vue.js能够实现数据驱动的视图变化。其实现主要基于Object.defineProperty API&#xff0c;通过在数据对象上添加属性监听来实现数据变化时对视图进行更新。 vue3实现主要基于Proxy API和Reactive&#xff0c;Reactive函数…

linux 块设备驱动程序介绍

Linux块设备驱动是Linux操作系统中用于处理块设备的设备驱动程序。块设备是指以固定大小的块单位进行访问的存储设备&#xff0c;例如硬盘、固态硬盘和USB存储设备等。 Linux块设备驱动负责管理块设备的读写操作&#xff0c;并将数据传输到相应的存储设备上。它还负责处理块设…

位运算符和移位运算符

位运算 符号规则按位与&两位全为1&#xff0c;结果为1&#xff0c;否则为0按位或|两位有一个为1&#xff0c;结果为1&#xff0c;否则为0按位异或^两位一个为0&#xff0c;一个为1&#xff0c;结果为1&#xff0c;否则为0按位取反~0->1 , 1->0 1. 按位与&&a…

python requests.Session()的使用

cookies and jar 你可以把Session理解成为它内部提供了一系列方法&#xff0c;用来存储状态。这里所说的状态&#xff0c;其实大部分情况下指的就是cookies。 比如使用浏览器时候&#xff0c;你在一个标签页内登陆了&#xff0c;另一个标签页其实就可以读取cookies了&#xf…

口袋参谋:新品上架,如何获取更多免费流量?

​新品上架 如何获得更多的免费流量&#xff1f; 我相信 这是99.999%的商家&#xff0c;都关心的问题&#xff01; 今天我就来和大家好好说道说道。 01 流量的组成 新品本身是没有权重的&#xff0c;买家搜不到我们。 如果想要获得更多的免费流量&#xff0c;我们就要知道…

基础算法(1):排序(1):选择排序

今天对算法产生了兴趣&#xff0c;开始学习基础算法&#xff0c;比如排序&#xff0c;模拟&#xff0c;贪心&#xff0c;递推等内容&#xff0c;算法是很重要的&#xff0c;它是解决某个问题的特定方法&#xff0c;程序数据结构算法&#xff0c;所以对算法的学习是至关重要的&a…

出现 Error:Unable to access jarfile xxxx\target\nacos-server.jar 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 执行Nacos中的startup.cmd的时候出现闪退,于是在该脚本的最后一行添加pause,查看因为什么原因闪退 出现的bug如下所示:Error:Unable to access jarfile xxxx\target\nacos-server.jar 截图如下所示: 查看内部文件夹,…

塑料检查井配套开发了注塑成型的井盖、井筒、井座

塑料检查井配套开发的注塑成型井盖、井筒、井座——城市基础设施的新选择 随着城市化进程的加快&#xff0c;城市基础设施建设的品质与效率日益受到重视。在这个背景下&#xff0c;塑料检查井及其配套开发的注塑成型井盖、井筒、井座以其独特的优势&#xff0c;正在逐渐取代传…

02 使用Vite创建Vue3项目

概述 A Vue project is structured similarly to a lot of modern node-based apps and contains the following: A package.json fileA node_modules folder in the root of your projectVarious other configuration files are usually contained at the root level, such …

ARM(i2C总线通信) 2023.12.13

main.c #include "si7006.h"int main(){unsigned short hum;short tem;//进行si7006的初始化si7006_init();while(1){//读取湿度humsi7006_read_hum_data(0X40,0XE5);//读取温度temsi7006_read_temp_data(0X40,0XE3);//将温度数据和湿度数据按照转换公式进行转换hum…

k8s debug 浅谈

一 k8s debug 浅谈 说明&#xff1a; 本文只是基于对kubectl debug浅显认识总结的知识点,后续实际使用再补充案例 Kubernetes 官方出品调试工具上手指南(无需安装&#xff0c;开箱即用) debug-application 简化 Pod 故障诊断: kubectl-debug 介绍 1.18 版本之前需要自己…

DevEco Studio自定义代码颜色

这里以ArkTS代码颜色举例 进入设置&#xff08;快捷键CtrlAltS&#xff09; 选择Editor > Color Scheme > JavaScript 由于之前用习惯VsCode了&#xff0c;这里以注释颜色举例&#xff0c;变为绿色。 上面说的不是以ArkTS代码颜色举例吗&#xff1f;为什么选择JavaScr…

JRT实现Cache的驱动

我只给PostGreSql和iris写了连接驱动&#xff0c;永国的库是Cache&#xff0c;他就自己写了个驱动&#xff0c;驱动其实就是把数据库差异接口抽取了出来&#xff0c;然后只要配对应数据库驱动就能连响应的数据库了。 package JRT.Dal.Base;import JRT.Core.MultiPlatform.JRTC…