图像分割基于模式识别系统的设计与实现
1.1 题目的主要研究内容
选择任意图片,通过提取的纹理特征、结合像素值与坐标的mean shift、K-means聚类进行图像分割
(2)系统流程图
1.2 题目研究的工作基础或实验条件
电脑PC端 Win10
Python语言
1.3 数据集描述
图像分割图片来源于网上图片皮卡丘进行图片分割
1.4 特征提取过程描述
颜色特征提取
颜色集是对颜色直方图的一种近似首先将图像从 RGB颜色空间转化成视觉均衡的颜色空间 HSV 空间,并将颜色空间量化成若干个柄。然后,用色彩自动分割技术将图像分为若干区域,每个区域用量化颜色空间的某个颜色分量来索引,从而将图像表达为一个二进制的颜色索引集。在图像匹配中,比较不同图像颜色集之间的距离和色彩区域的空间关系。
1.5 分类过程描述
对图像K-means进行聚类分析,根据当前聚类中心,利用选定的度量方式,分类所用的样本点,计算当前每一类的样本均值点,作为下次迭代聚类中心,计算下一次迭代的聚类中心与当前聚类中心的差距,如果差距小于给定迭代阈值,迭代结束。
data: 需要分类数据,每个特征放一列。
K: 聚类个数
bestLabels:预设的分类标签或者None
criteria:迭代停止的模式选择,这是一个含有三个元素的元组型数。格式为(type, max_iter, epsilon) 其中,type有如下模式:
cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon,则停止。
cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter,则停止。
cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER:两者结合,满足任意一个结束。
attempts:重复试验kmeans算法次数,将会返回最好的一次结果
1.6 主要程序代码(要求必须有注释).
(1)纹理特征提取和进行图像分割
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
# print_imshow用于输出标题、图片信息
def print_imshow(title,image):
plt.title(title)
plt.imshow(image)
plt.colorbar()
plt.show()
# 读取图片
image = cv.imread("pkpk.jpg")[:,:,[2,1,0]]
print_imshow("原始图像",image)
# 进行预处理操作
blur = cv.blur(image,(5,5))
blur0=cv.medianBlur(blur,5)
# 把BGR格式转为HSV格式
hsv = cv.cvtColor(blur0, cv.COLOR_BGR2HSV)
# 进行阈值分割,以确定需要提取的像素阈值
low_blue = np.array([55, 0, 0])
high_blue = np.array([118, 255, 255])
mask = cv.inRange(hsv, low_blue, high_blue)
print_imshow("mask",mask)
# 显示由Mask作为边界的图像
res = cv.bitwise_and(image,image, mask= mask)
print_imshow("res",res)
(2)使用K-means进行聚类
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取原始图像
image = cv2.imread('pkpk.jpg')
print(image.shape)
#图像二维像素转换为一维
data = image.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((image.shape))
centers4 = np.uint8(centers4)
res = centers4[labels4.flatten()]
dst4 = res.reshape((image.shape))
centers8 = np.uint8(centers8)
res = centers8[labels8.flatten()]
dst8 = res.reshape((image.shape))
centers16 = np.uint8(centers16)
res = centers16[labels16.flatten()]
dst16 = res.reshape((image.shape))
centers64 = np.uint8(centers64)
res = centers64[labels64.flatten()]
dst64 = res.reshape((image.shape))
#图像转换为RGB显示
img = cv2.cvtColor(image, 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 = [u'原始图像', u'聚类图像 K=2', u'聚类图像 K=4',
u'聚类图像 K=8', u'聚类图像 K=16', u'聚类图像 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()
(3)mean shift
import cv2
import numpy as np
def generate(filename,mode,sp,sr,postfix):
return filename+"_"+mode+"_"+str(sp)+"_"+str(sr)+postfix
def fill_image(image):
copyImage = image.copy() # 复制原图像
h, w = image.shape[:2] # 读取图像的宽和高
mask = np.zeros([h+2, w+2], np.uint8) # 新建图像矩阵 +2是官方函数要求
# image 输出
# mask 每当一个原始图上一个点位(x,y)被填充之后,该点位置对应的mask上的点(x+1,y+1)的灰度值随机被设置为1(原本该点的灰度值为0),代表该点已经被填充处理过。
# seedPoint 漫水填充的起始种子点
# newVal 被填充的色彩值
# loDiff 定义跟种子点相比色彩的下限值和上限值,介于种子点减去loDiff和种子点加上upDiff的值会被填充为跟种子点同样的颜色。
# 定义漫水填充的模式,用于连通性、扩展方向等的定义
cv2.floodFill(copyImage, mask, (0, 80), (0, 100, 255), (100, 100, 50), (50, 50, 50), cv2.FLOODFILL_FIXED_RANGE)
return copyImage
filename = 'pkpk'
postfix = ".jpg"
sp = 10
sr = 255
src = cv2.imread(filename+postfix)
# src:待分割的输入图像,必须是三通道CU_8U的彩色图像
# dst:分割后的输出图像,与输入图像具有相同的尺寸和数据类型
# sp:滑动窗口的半径
# sr:滑动窗口颜色幅度
# maxLevel:分割金字塔缩放层数
# termcrit:迭代算法终止条件。
dst = cv2.pyrMeanShiftFiltering(src, sp, sr, None, 2)
cv2.imwrite(generate(filename,"tmp",sp,sr,postfix),dst)
cv2.imwrite(generate(filename,"fill",sp,sr,postfix),fill_image(dst))
(4)通过graph partition图分割的方式进行图像分割
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 读取图像
img = cv.imread('pkpk.jpg')
plt.imshow(img[:,:,[2,1,0]]),plt.colorbar(),plt.show()
# 创建一个掩膜(与图像同大小)
mask = np.zeros(img.shape[:2],np.uint8)
# 创建以0填充的前景和背景模型
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
# 划定一个区域,
rect = (150,150,370,400)
# 执行图分割
cv.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img[:,:,[2,1,0]]),plt.colorbar(),plt.show()
1.7 运行结果及分析
(1)
(2)使用K-means聚类
上图是像素值结合k-means聚类的效果图