利⽤Python-opencv进⾏图像分割:Kmeans的使⽤(含源码)
⽂章⽬录
前⾔
本⽂是图像分割·专栏的第⼀篇。图像分割在整个图像处理过程中是很重要的⼀环,它⼤多数作为整个图像处理的预处理步骤,分割的⽬的主要是为了得到ROI区域,并且为后续的特征提取和模式识别打下坚实的基础。
本⽂主要介绍如何⽤Kmeans⽅法进⾏图像分割。
⼀、Kmeans是什么?
Kmeans是⼀种将输⼊数据划分为k个类别的简单聚类算法,该算法能不断提取当前分类的中⼼点,并最终在分类稳定时完成聚类。本质说,Kmeans是⼀种迭代算法。
Kmeans算法⼀般的⽤途是对数据进⾏分类,让计算机对数据进⾏分析,并且⾃动将数据划分为k个类别。⽽图⽚实际上就是⼆维或者三维数组,对图⽚进⾏Kmeans分类⾃然就完成了分割。
⼆、如何使⽤Kmeans
1.opencv中的Kmeans函数
该图是opencv-python中Kmeans函数的参数解析,⽹上有很多资料,我就不在这赘述了。
2.Kmeans代码⽰例
对⼀维数据进⾏分类
from sys import flags
from cv2 import cv2
from matplotlib.image import imread
random在python中的意思import numpy as np
from matplotlib import pyplot as plt
defchararray import center
'''
Kmeans对⼀维数据进⾏聚类
'''
# 随机⽣成⼩⽶和⼤⽶两组数据,⼩⽶数值特征范围0到50,⼤⽶特征范围200到250,都是60个xiaomi = np.random.randint(0,50,60)
dami = np.random.randint(200,250,60)
# 将⼤⽶⼩⽶数据按⽔平线⽅向合并,得到(120,)
mi = np.hstack((xiaomi,dami))
# print(mi.dtype)
# print(mi.shape)
# 将mi的形状变成⼀维向量,并且数据类型变成Kmeans需要的float32
mi = mi.reshape((120,1))
mi = np.float32(mi)
# 设置Kmeans的终⽌条件
critera =(cv2.TermCriteria_EPS+cv2.TermCriteria_MAX_ITER,10,1.0)
# 设置Kmeans的初始化⽅式
flags = cv2.KMEANS_RANDOM_CENTERS
# 将数据传⼊,进⾏聚类
r,best,center = cv2.kmeans(mi,2,None,criteria=critera,attempts=10,flags=flags)
print(r)
print(best)
print(center)
# 标签为0的是⼩⽶,将该结果数据利⽤逻辑索引取出赋给新变量xiaomi
xm = mi[best==0]
dm = mi[best==1]
# 展⽰结果
plt.plot(xm,'ro')
plt.plot(dm,'bo')
plt.plot(center[0],'rx')
plt.plot(center[1],'bx')
plt.show()
结果如下图
对⼆维数据进⾏分类
# 每组数据是⼆维,xiaomi数据是(30,2)的size,且数据范围是0到20,dami的size也是(30,2),范
围是40到60 xiaomi = np.random.randint(0,20,(30,2))
dami = np.random.randint(40,60,(30,2))
# 将两种数据按照垂直⽅式合并,得到(60,2)
mi = np.vstack((xiaomi,dami))
print(mi.dtype)
print(mi.shape)
# 转换数据格式
mi = np.float32(mi)
# 设置Kmeans函数参数
critera =(cv2.TermCriteria_EPS+cv2.TermCriteria_MAX_ITER,10,1.0)
flags = cv2.KMEANS_RANDOM_CENTERS
r,best,center = cv2.kmeans(mi,2,None,criteria=critera,attempts=10,flags=flags)
print(r)
print(best.shape)
print(center)
# 因为是⼆维数据,得到的标签不是(120,),⽽是(120,1),是⼀个⼀维向量,所以逻辑索引和上⾯有的区别xm = mi[best[:,0]==0]
dm = mi[best[:,0]==1]
plt.scatter(xm[:,0],xm[:,1],c='g',marker='s')
plt.scatter(dm[:,0],dm[:,1],c='r',marker='s')
plt.xlabel('height'),plt.ylabel('width')
plt.show()
对图⽚进⾏分割
# 对图像⽤kmeans聚类
# 显⽰图⽚的函数
def show(winname,src):
cv2.namedWindow(winname,cv2.WINDOW_GUI_NORMAL)
cv2.imshow(winname,src)
cv2.waitKey()
img = cv2.imread('segmentation/1.jpg')
o = py()
print(img.shape)
# 将⼀个像素点的rgb值作为⼀个单元处理,这⼀点很重要
data = shape((-1,3))
print(data.shape)
# 转换数据类型
data = np.float32(data)
# 设置Kmeans参数
critera =(cv2.TermCriteria_EPS+cv2.TermCriteria_MAX_ITER,10,0.1)
flags = cv2.KMEANS_RANDOM_CENTERS
# 对图⽚进⾏四分类
r,best,center = cv2.kmeans(data,4,None,criteria=critera,attempts=10,flags=flags) print(r)
print(best.shape)
print(center)
center = np.uint8(center)
# 将不同分类的数据重新赋予另外⼀种颜⾊,实现分割图⽚
data[best.ravel()==1]=(0,0,0)
data[best.ravel()==0]=(255,0,0)
data[best.ravel()==2]=(0,0,255)
data[best.ravel()==3]=(0,255,0)
# 将结果转换为图⽚需要的格式
data = np.uint8(data)
oi = shape((img.shape))
# 显⽰图⽚
show('img',img)
show('res',oi)
原图
结果图
总结
Kmeans对图像分割,本质上还是基于灰度的分割,既然是基于灰度的分割,就会对光照变化敏感。但
这种分割和传统的阈值分割不同在于,它可以对彩⾊图像直接进⾏分割,⽽且⽐传统的阈值分割多了⼀种⾃适应性。当然,这种⾃适应性和⼤津算法(ostu)孰强孰弱还有待验证。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论