-
前情提要:
最近由于做机器学习不想手动标签,所以想用聚类的方法让机器自己学习,在网站上找到了很多博主的程序,有其效果但是最后都是将每一类的图片用plot显示出来,把所有的子图拼接在一个界面上。这样在尝试大约800张图片的数据集的时候还凑活,通过加一行程序调整子图之间的宽度和高度,勉强能看清图片内容,以观察聚类的效果。但是一般机器学习的数据集都更大,聚类完想要对每类图片再进行处理的话,原本的程序就不太方便。因此在找到的程序基础上进行了一些变动,以达到其他效果。
-
具体描述:
在这个程序中,主体部分和网上多数的图片聚类程序一致,略有不同的地方是在结尾部分,把flatten后的数组reshape并还原,然后保存为图片格式,每个类别(cluster)都存到一个文件夹内。其中文件夹的生成是用了另外一个小程序(见上篇博文),结尾的保存部分也偷懒没有用循环写(主要是用到的类别少,就直接elif了)
因为看了好多K聚类的程序,不知道我用的主要程序是哪位原创的然后我做了改动,如果有原作者能够认领的话欢迎留言,我会在文章开头补充著名出处的!
整体属于学习过程中的小尝试,有问题还请指出,多交流~
- 具体代码:
# -*- coding: utf-8 -*-
import pickle
import os
import cv2
from pylab import *
from PIL import Image
from scipy.cluster.vq import *
from PCV.tools import pca, imtools
from matplotlib import pyplot as plt
下面是输入部分,主要是路径,手动输入想要的簇数,以及图片尺寸(图片尺寸一定要对,因为我用的图片是单通道而不是RGB三通道的,如果是三通道的话,最后reshape的位置要写三个参数,要不然最后reshape的时候会有无法映射的问题)
PCA_MODE = 'pca_mode.pkl' # 保存的PCA文件
IMG_TRAIN_LIST = r'E:/d15/frame/try/' # 用于计算PCA的图片列表
IMG_CLUSTER_LIST = r'E:/d15/frame/try/' # 用于聚类的图片列表
CLUSTER = 10 # 簇数
IMG_WIDTH, IMG_HEIGHT = 240, 320 # 图片尺寸
print("the number of cluster is:", CLUSTER)
print("****************************************")
# 获取训练图像列表
imlist = imtools.get_imlist(IMG_TRAIN_LIST) #imlist 为图像路径('E:/d15/frame/try2/1.jpg')构成的列表
namelist = len(imlist)*[''] #使namelist有对应长度
这下面一点本来是想在输出的时候用文件原名输出来着,所以做了个name的分离,但是最后也并没这么搞,直接重命名了。。但是也一起把代码放上来了。。。
for i in range(0,len(imlist)):
namelist[i]=imlist[i].strip('E:/d15/frame/try2')
# namelist为列表内文件的文件名(加了后缀,如'x_1.jpg')
im = array(Image.open(imlist[0])) # 打开任意一张图片
# #im为图对应的矩阵
接主要部分:
m, n = im.shape[:2] # 图片尺寸(要都统一) #m=240 ,n=320
imnbr = len(imlist) # 图片数量
print('The number of training images is {}'.format(imnbr))
immatrix = array([array(Image.open(imname)).flatten() for imname in imlist], 'f') # 拼接所有图片
# 保存均值和主成分
print('Training...')
V, S, immean = pca.pca(immatrix) # PCA降维
f = open(PCA_MODE, 'wb')
pickle.dump(immean, f)
pickle.dump(V, f)
f.close()
print('{} had saved'.format(PCA_MODE))
# 获取聚类图像列表
imlist = imtools.get_imlist(IMG_CLUSTER_LIST)
imnbr = len(imlist)
print('The number of clustering images is {}'.format(imnbr)
# 加载主成分
with open(PCA_MODE, 'rb') as f:
immean = pickle.load(f)
V = pickle.load(f)
print('{} had loaded'.format(PCA_MODE))
接下来是我做了改动的主要部分:
原程序在这个部分是reshape后加了图的坐标、大小、像素,子图的参数,然后show()
由于我最近一次用了9000张图片做了聚类,这样显示之后每一张都是看不清的,所以输出到文件夹内。
其中,在输出部分往下三四行的这句:
array2=(immatrix[ind[i]].reshape((240,320)))
要注意,我这里为了顺手就直接把240,320的图片尺寸敲上去了,原本程序可以直接在开头改,开头有:IMG_WIDTH, IMG_HEIGHT = 240, 320 # 图片尺寸
就是这里的两个尺寸;另外,如果是RGB的话,应该改为array2=(immatrix[ind[i]].reshape((240,320,3)))
,这里“3”表示RGB是颜色三通道
# 使用主成分进行k-means聚类
immatrix = array([array(Image.open(im)).flatten() for im in imlist], 'f') # 拼接所有图片
#对imlist中的所有图片转换为数组array,并进行扁平化flatten
#再对上一步的数组再转化为数组
immean = immean.flatten()
projected = array([dot(V[:CLUSTER *4], immatrix[i] - immean) for i in range(imnbr)]) # 前4×CLUSTER个主成分
projected = whiten(projected)
centroids, distortion = kmeans(projected, CLUSTER)
code, distance = vq(projected, centroids)
#输出部分
for k in range(CLUSTER):
print('\n') #换行
ind = where(code == k)[0]
print('cluster:', k + 1) #输出类别序号
for i in range(minimum(len(ind), imnbr)):
array2=(immatrix[ind[i]].reshape((240,320))) #将拼接的图片reshape成原来的图片
image1=Image.fromarray(array2)
path1 = 'E:/d15/frame/try1/'
#下面两行是由于图片格式有不同,所以做一下具体转换。如果是RGB的话请查一下对应表述蛤,印象中就是把"L"改成"RGB"就好了
if image1.mode == "F": # F: 32位浮点型像素
image1 = image1.convert('L') # L: 8位黑白像素
#把对应簇的照片保存在对应路径的文件夹下 #文件夹有规律的话可以改成循环,但文件夹要提前生成
if (k+1)==1:
image1.save('E:/d15/frame/try1/cluster1/' + 'cluster1_'+str(i+1) + '.jpg')
elif (k+1)==2:
image1.save('E:/d15/frame/try1/cluster2/' + 'cluster2_'+str(i+1) + '.jpg')
elif (k + 1) == 3:
image1.save('E:/d15/frame/try1/cluster3/' + 'cluster3_'+ str(i+1) + '.jpg')
elif (k + 1) == 4:
image1.save('E:/d15/frame/try1/cluster4/' + 'cluster4_'+str(i+1) + '.jpg')
elif (k + 1) == 5:
image1.save('E:/d15/frame/try1/cluster5/' + 'cluster5_'+str(i+1) + '.jpg')
elif (k + 1) == 6:
image1.save('E:/d15/frame/try1/cluster6/' + 'cluster6_'+str(i+1) + '.jpg')
elif (k + 1) == 7:
image1.save('E:/d15/frame/try1/cluster7/' + 'cluster7_'+str(i+1) + '.jpg')
elif (k + 1) == 8:
image1.save('E:/d15/frame/try1/cluster8/' + 'cluster8_'+str(i+1) + '.jpg')
elif (k + 1) == 9:
image1.save('E:/d15/frame/try1/cluster9/' + 'cluster9_'+str(i+1) + '.jpg')
elif (k + 1) == 10:
image1.save('E:/d15/frame/try1/cluster10/' + 'cluster10_' + str(i + 1) + '.jpg')
else:
print("error")
print ("number of pictures in this cluster:---",i+1,'---') #输出每一类照片的个数