网络编程
位置:首页>> 网络编程>> Python编程>> Python基于纹理背景和聚类算法实现图像分割详解

Python基于纹理背景和聚类算法实现图像分割详解

作者:Eastmount  发布时间:2023-11-15 20:05:46 

标签:Python,图像,分割

一.基于纹理背景的图像分割

该部分主要讲解基于图像纹理信息(颜色)、边界信息(反差)和背景信息的图像分割算法。在OpenCV中,GrabCut算法能够有效地利用纹理信息和边界信息分割背景,提取图像目标物体。该算法是微软研究院基于图像分割和抠图的课题,它能有效地将目标图像分割提取,如图1所示[1]。

Python基于纹理背景和聚类算法实现图像分割详解

GrabCut算法原型如下所示:

mask, bgdModel, fgdModel = grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode])

– image表示输入图像,为8位三通道图像

– mask表示蒙板图像,输入/输出的8位单通道掩码,确定前景区域、背景区域、不确定区域。当模式设置为GC_INIT_WITH_RECT时,该掩码由函数初始化

– rect表示前景对象的矩形坐标,其基本格式为(x, y, w, h),分别为左上角坐标和宽度、高度

– bdgModel表示后台模型使用的数组,通常设置为大小为(1, 65)np.float64的数组

– fgdModel表示前台模型使用的数组,通常设置为大小为(1, 65)np.float64的数组

– iterCount表示算法运行的迭代次数

– mode是cv::GrabCutModes操作模式之一,cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK表示使用矩阵模式或蒙板模式

下面是Python的实现代码,通过调用np.zeros()函数创建掩码、fgbModel和bgModel,接着定义rect矩形范围,调用函数grabCut()实现图像分割。由于该方法会修改掩码,像素会被标记为不同的标志来指明它们是背景或前景。接着将所有的0像素和2像素点赋值为0(背景),而所有的1像素和3像素点赋值为1(前景),完整代码如下所示。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
import matplotlib

#读取图像
img = cv2.imread('nv.png')

#灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#设置掩码、fgbModel、bgModel
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1,65), np.float64)
fgdModel = np.zeros((1,65), np.float64)

#矩形坐标
rect = (100, 100, 500, 800)

#图像分割
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5,
           cv2.GC_INIT_WITH_RECT)

#设置新掩码:0和2做背景
mask2 = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')

#设置字体
matplotlib.rcParams['font.sans-serif']=['SimHei']

#显示原图
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(1,2,1)
plt.imshow(img)
plt.title('(a)原始图像')

plt.xticks([]), plt.yticks([])

#使用蒙板来获取前景区域
img = img*mask2[:, :, np.newaxis]
plt.subplot(1,2,2)
plt.imshow(img)
plt.title('(b)目标图像')

plt.colorbar()
plt.xticks([]), plt.yticks([])
plt.show()

输出图像如图2所示,图2(a)为原始图像,图2(b)为图像分割后提取的目标人物,但人物右部分的背景仍然存在。如何移除这些背景呢?这里需要使用自定义的掩码进行提取,读取一张灰色背景轮廓图,从而分离背景与前景,希望读者下来实现该功能。

Python基于纹理背景和聚类算法实现图像分割详解

二.基于K-Means聚类算法的区域分割

K-Means聚类是最常用的聚类算法,最初起源于信号处理,其目标是将数据点划分为K个类簇,找到每个簇的中心并使其度量最小化。该算法的最大优点是简单、便于理解,运算速度较快,缺点是只能应用于连续型数据,并且要在聚类前指定聚集的类簇数[2]。

下面是K-Means聚类算法的分析流程,步骤如下:

  • 第一步,确定K值,即将数据集聚集成K个类簇或小组;

  • 第二步,从数据集中随机选择K个数据点作为质心(Centroid)或数据中心;

  • 第三步,分别计算每个点到每个质心之间的距离,并将每个点划分到离最近质心的小组,跟定了那个质心;

  • 第四步,当每个质心都聚集了一些点后,重新定义算法选出新的质心;

  • 第五步,比较新的质心和老的质心,如果新质心和老质心之间的距离小于某一个阈值,则表示重新计算的质心位置变化不大,收敛稳定,则认为聚类已经达到了期望的结果,算法终止;

  • 第六步,如果新的质心和老的质心变化很大,即距离大于阈值,则继续迭代执行第三步到第五步,直到算法终止。

图29-3是对身高和体重进行聚类的算法,将数据集的人群聚集成三类。

Python基于纹理背景和聚类算法实现图像分割详解

在图像处理中,通过K-Means聚类算法可以实现图像分割、图像聚类、图像识别等操作,本小节主要用来进行图像颜色分割。假设存在一张100×100像素的灰度图像,它由10000个RGB灰度级组成,我们通过K-Means可以将这些像素点聚类成K个簇,然后使用每个簇内的质心点来替换簇内所有的像素点,这样就能实现在不改变分辨率的情况下量化压缩图像颜色,实现图像颜色层级分割。

在OpenCV中,Kmeans()函数原型如下所示:

retval, bestLabels, centers = kmeans(data, K, bestLabels, criteria, attempts, flags[, centers])

– data表示聚类数据,最好是np.flloat32类型的N维点集

– K表示聚类类簇数

– bestLabels表示输出的整数数组,用于存储每个样本的聚类标签索引

– criteria表示算法终止条件,即最大迭代次数或所需精度。在某些迭代中,一旦每个簇中心的移动小于criteria.epsilon,算法就会停止

– attempts表示重复试验kmeans算法的次数,算法返回产生最佳紧凑性的标签

– flags表示初始中心的选择,两种方法是cv2.KMEANS_PP_CENTERS ;和cv2.KMEANS_RANDOM_CENTERS

– centers表示集群中心的输出矩阵,每个集群中心为一行数据

下面使用该方法对灰度图像颜色进行分割处理,需要注意,在进行K-Means聚类操作之前,需要将RGB像素点转换为一维的数组,再将各形式的颜色聚集在一起,形成最终的颜色分割。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像灰度颜色
img = cv2.imread('scenery.png', 0)

#获取图像高度、宽度
rows, cols = img.shape[:]

#图像二维像素转换为一维
data = img.reshape((rows * cols, 1))
data = np.float32(data)

#定义中心 (type,max_iter,epsilon)
criteria = (cv2.TERM_CRITERIA_EPS +
           cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

#设置标签
flags = cv2.KMEANS_RANDOM_CENTERS

#K-Means聚类 聚集成4类
compactness, labels, centers = cv2.kmeans(data, 4, None, criteria, 10, flags)

#生成最终图像
dst = labels.reshape((img.shape[0], img.shape[1]))

#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles = ['原始图像', '聚类图像']  
images = [img, dst]  
for i in range(2):  
  plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray'),
  plt.title(titles[i])  
  plt.xticks([]),plt.yticks([])  
plt.show()

输出结果如图4所示,左边为灰度图像,右边为K-Means聚类后的图像,它将灰度级聚集成四个层级,相似的颜色或区域聚集在一起。

Python基于纹理背景和聚类算法实现图像分割详解

下面代码是对彩色的图像进行颜色分割处理,它将彩色的图像聚集成2类、4类和64类。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('scenery.png')

#图像二维像素转换为一维
data = img.reshape((-1,3))
data = np.float32(data)

#定义中心 (type,max_iter,epsilon)
criteria = (cv2.TERM_CRITERIA_EPS +
           cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

#设置标签
flags = cv2.KMEANS_RANDOM_CENTERS

#K-Means聚类 聚集成2类
compactness, labels2, centers2 = cv2.kmeans(data, 2, None, criteria, 10, flags)

#K-Means聚类 聚集成4类
compactness, labels4, centers4 = cv2.kmeans(data, 4, None, criteria, 10, flags)

#K-Means聚类 聚集成8类
compactness, labels8, centers8 = cv2.kmeans(data, 8, None, criteria, 10, flags)

#K-Means聚类 聚集成16类
compactness, labels16, centers16 = cv2.kmeans(data, 16, None, criteria, 10, flags)

#K-Means聚类 聚集成64类
compactness, labels64, centers64 = cv2.kmeans(data, 64, None, criteria, 10, flags)

#图像转换回uint8二维类型
centers2 = np.uint8(centers2)
res = centers2[labels2.flatten()]
dst2 = res.reshape((img.shape))

centers4 = np.uint8(centers4)
res = centers4[labels4.flatten()]
dst4 = res.reshape((img.shape))

centers8 = np.uint8(centers8)
res = centers8[labels8.flatten()]
dst8 = res.reshape((img.shape))

centers16 = np.uint8(centers16)
res = centers16[labels16.flatten()]
dst16 = res.reshape((img.shape))

centers64 = np.uint8(centers64)
res = centers64[labels64.flatten()]
dst64 = res.reshape((img.shape))

#图像转换为RGB显示
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dst2 = cv2.cvtColor(dst2, cv2.COLOR_BGR2RGB)
dst4 = cv2.cvtColor(dst4, cv2.COLOR_BGR2RGB)
dst8 = cv2.cvtColor(dst8, cv2.COLOR_BGR2RGB)
dst16 = cv2.cvtColor(dst16, cv2.COLOR_BGR2RGB)
dst64 = cv2.cvtColor(dst64, cv2.COLOR_BGR2RGB)

#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles = ['原始图像', '聚类图像 K=2', '聚类图像 K=4',
         '聚类图像 K=8', '聚类图像 K=16', '聚类图像 K=64']  
images = [img, dst2, dst4, dst8, dst16, dst64]  
for i in range(6):  
  plt.subplot(2,3,i+1), plt.imshow(images[i], 'gray'),
  plt.title(titles[i])  
  plt.xticks([]),plt.yticks([])  
plt.show()

输出结果如图5所示,它对比了原始图像和各K-Means聚类处理后的图像。当K=2时,聚集成2种颜色;当K=4时,聚集成4种颜色;当K=8时,聚集成8种颜色;当K=16时,聚集成16种颜色;当K=64时,聚集成64种颜色。

Python基于纹理背景和聚类算法实现图像分割详解

同样,如果是人物图像显示如图6所示,比如小珞珞。

Python基于纹理背景和聚类算法实现图像分割详解

三.总结

本文主要讲解了常用的图像分割方法,包括基于纹理背景和聚类算法的图像分割方法。希望读者能结合本文知识点,围绕自己的研究领域或工程项目进行深入的学习,实现所需的图像处理。

来源:https://blog.csdn.net/Eastmount/article/details/128517003

0
投稿

猜你喜欢

  •  本篇已得到原作者Steve Dennis的翻译准予,在此Jorux表示感谢!本教程主要参考Creating a CSS Layo
  • 使用scrapy爬取了网上的一些数据,存储在了mysql数据库中,想使用Django将数据展示出来,在网上看到都是使用Django的mode
  • 本文主要涉及图形验证码的相关功能,主要包括,图形验证码获取、验证码文字存储、验证码生成等。图形验证码接口设计和定义 验证码获取接口
  • 切片——str[start:end]str1 = ' python str '#切片
  • ASP(Active Server Page)是Microsoft公司推出的基于PWS(Personal We
  • 本文实例为大家分享了python文件写入write()的操作的具体代码,供大家参考,具体内容如下filename = 'pragra
  • DBA_2PC_PENDING Oracle会自动处理分布事务,保证分布事务的一致性,所有站点全部提交或全部回滚。一般情况下,处理过程在很短
  • 同时在线访问量继续增大 对于1G内存的服务器明显感觉到吃力严重时甚至每天都会死机 或者时不时的服务器卡一下 这个问题曾经困扰了我半个多月My
  • 每一字符串字符文字有一个字符集和一个校对规则,它不能为空。一个字符串文字可能有一个可选的字符集引介词和COLLATE子句:[_charset
  • 互联网的真正算得上成功的产品屈指可数,每年都有成千上万个新网站出现,同时也有成千上万的网站死去,而那些算得上成功的产品,无不是从这些尸骨堆里
  • 这篇文章主要给大家介绍了利用Thinkphp结合ajaxFileUpload实现异步图片传输的方法,文中给出了详细的示例代码,对大家具有一定
  • 四、XML应用分类 总的说来的XML的应用可分为四类: (1)应用于客户需要与不同的数据源进行交互时。数据可能来自不同的数据库,他们都有各自
  • 本文主要讲如何不依赖TenserFlow等高级API实现一个简单的神经网络来做分类,所有的代码都在下面;在构造的数据(通过程序构造)上做了验
  • 如果你忘记了你的MYSQL的root口令的话,你可以通过下面的过程恢复。1. 向mysqld server 发
  • 上一小节讲解了行高与单行纯文字的垂直居中,而如果行内含有图片和文字,在浏览器内浏览时,读者可以发现文字和图片在垂直方向并不是沿中线居中,而是
  • 关于《回访确认》这件事情,在我blog和5Gme的回复里普遍出现这么几个疑问:1、下了订单却放弃支付的心理因素是什么?2、回访电话可以促进订
  • 在知乎上遇到一个问题,说:计算机中的「null」怎么读?null正确的发音是/n^l/,有点类似四声‘纳儿&rs
  • 迭代器是一种支持next()操作的对象。它包含一组元素,当执行next()操作时,返回其中一个元素;当所有元素都被返回后,生成一个StopI
  • 1. 关于 try.. finally..假如上帝用 python 为每一个来到世界的生物编写程序,那么除去中间过程的种种复杂实现,最不可避
  • 本文介绍了数据库索引,及其优、缺点。针对MySQL索引的特点、应用进行了详细的描述。分析了如何避免MySQL无法使用,如何使用EXPLAIN
手机版 网络编程 asp之家 www.aspxhome.com