梯度直方图特征、phash特征的k-means聚类以及层次聚类

《将图片转化为向量并使用K-means进行聚类》

https://blog.csdn.net/gusui7202/article/details/88081072

使用了原始图像数据进行聚类,现在先提取图像的特征然后再进行聚类。

首先使用的是梯度直方图特征,代码如下:主要还是修改地址和聚类数目

#!/usr/bin/python
# coding=utf-8
'''
基于直方图特征的图片聚类实现
'''
import numpy as np
import os
from PIL import Image
#coding=utf-8
from numpy import *

def loadDataSet(fileName):
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = map(float, curLine)
        dataMat.append(fltLine)
    return dataMat
    
#计算两个向量的距离,用的是欧几里得距离
def distEclud(vecA, vecB):
    return np.sqrt(sum(np.power(vecA - vecB, 2)))

#随机生成初始的质心(ng的课说的初始方式是随机选K个点)    
def randCent(dataSet, k):
    n = np.shape(dataSet)[1]
    centroids = np.mat(np.zeros((k,n)))
    for j in range(n):
        minJ = min(dataSet[:,j])
        rangeJ = float(max(np.array(dataSet)[:,j]) - minJ)
        centroids[:,j] = minJ + rangeJ * np.random.rand(k,1)
    return centroids
    
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    m =np.shape(dataSet)[0]
    clusterAssment = np.mat(np.zeros((m,2)))#create mat to assign data points 
                                      #to a centroid, also holds SE of each point
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(m):#for each data point assign it to the closest centroid
            minDist = np.inf
            minIndex = -1
            for j in range(k):
                distJI = distMeas(centroids[j,:],dataSet[i,:])
                if distJI < minDist:
                    minDist = distJI; minIndex = j
            if clusterAssment[i,0] != minIndex: 
                clusterChanged = True
            clusterAssment[i,:] = minIndex,minDist**2
        #print centroids
        for cent in range(k):#recalculate centroids
            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]#get all the point in this cluster
            centroids[cent,:] = mean(ptsInClust, axis=0) #assign centroid to mean 
    return centroids, clusterAssment
    
def show(dataSet, k, centroids, clusterAssment):
    from matplotlib import pyplot as plt  
    numSamples, dim = dataSet.shape  
    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '

然后是层次聚类方法,使用了PCV的clustering包,里面有现成的层次聚类算法可以使用。

 # -*- coding: utf-8 -*-
import os
from PIL import Image
from PCV.clustering import hcluster
from matplotlib.pyplot import *
from numpy import *
 
# create a list of images
path = 'C:/Users/nansbas/Desktop/julei/'
imlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.jpg')]
# extract feature vector (8 bins per color channel)
features = zeros([len(imlist), 512])#特征长度512
for i, f in enumerate(imlist):
    im = array(Image.open(f))#Image不是image包,是PIL里的Image模块
    # multi-dimensional histogram
    h, edges = histogramdd(im.reshape(-1, 3), 8, normed=True, range=[(0, 255), (0, 255), (0, 255)])#reshape函数要导入Numpy 用其进行平整,将图像拉成一个三维数据。
#print(len(h))=8
#print(edges)=三个数组,每个数组8个数值,一共24个数据
    features[i] = h.flatten()
tree = hcluster.hcluster(features)#聚类分析
# visualize clusters with some (arbitrary) threshold
clusters = tree.extract_clusters(20 * tree.distance)
print(len(clusters))
# plot images for clusters with more than 3 elements
for c in clusters:
    elements = c.get_cluster_elements()
    nbr_elements = len(elements)
    if nbr_elements > 50:
        figure()
        for p in range(minimum(nbr_elements,20)):
            subplot(4, 5, p + 1)
            im = array(Image.open(imlist[elements[p]]))
            imshow(im)
            axis('off')
show()
 
hcluster.draw_dendrogram(tree,imlist,filename='sunset.pdf')

最后,就是phash特征的聚类了。我用的都是k-means,代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans  
from math import log ,sqrt,pow
import math
import random
 
 
"""
数据预处理
"""
datanumber=1000 #图像个数
print('读入图片')
def unpickle(file):
    import pickle
    with open(file,'rb')as fo:
        dict =pickle.load(fo,encoding='bytes')
    return dict
path='C:/Users/nansbas/Desktop/julei/'#路径可以自己定义
a=unpickle(path+'data_batch_1')
temp=np.zeros((10000,3072))
data_label=np.zeros(50000)
data_array=np.zeros((50000,3072))
for i in range(5):
    cur_dict=unpickle(path+'data_batch_'+str(i+1))
    for j in range(10000):
        data_array[i*10000+j]=cur_dict[b'data'][j][:]
        data_label[i*10000+j]=cur_dict[b'labels'][j]
data_array=data_array.reshape(50000,3,32,32).transpose(0,2,3,1).astype('float32')
data_label=data_label.astype('float32')
 
    
"""
phash图像特征
"""
def pHash(img):
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#创建二维列表
    h,w=gray.shape[:2]
    vis0=np.zeros((h,w),np.float32)
    vis0[:h,:w]=gray
    
#二维DCT变换
    vis1=cv2.dct(cv2.dct(vis0))
    img_list=vis1.flatten()
 
# 计算均值
    avg=sum(img_list)*1./len(img_list)
    avg_list=['0' if i 

因为这几个算法的结果我都没有保存,但都做了可视化模块,都是可以用的。

放一个结论:

为什么图像的聚类要提取特征?难道就是因为直接使用图像来进行聚类的实验效果不好?

理论上这个问题就和为什么要进行特征提取一样:

为什么要特征提取?有多个方面的因素:

1.我们的目的是找到某一种特点,从原图到这个特点的对应关系,是一种有特点的模式,所以其实我们需要去提取图片中的模式对应的数据内容并进行考量。比如,颜色:图片是什么颜色?颜色就是图片的一种模式。在数据上的体现为图像三个通道数值的大小。那么这个图片里面有什么几何图像?这就和图像数值的结构有关系了。是另一种模式。

即:我们需要的结果,是图像相关的一个方面,我们要得到这个结果,就要从图像的这个方面来考虑。

计算机是如何实现从图像的某个方面考虑的?特征。

2.冗余和干扰:在上面一点知道特征是图像的一个方面,既然他本来就有,那么我们为什么一定要提取出来?不提取出来就它就没有了吗?对。它还真的没有了。我们定义了是哪个方面,而图像本身是不会定义自己有多少个方面的,分析的量,都是我们定义好的量,那么不提取出来,图像这个方面就不成型,混在原始图像丰富的信息中,收到其他信息的干扰。

3.滤波器:特征提取就是一个过滤的过程。过滤到上面第2点说的干扰,也是特征形成的过程,表达的过程。而我们定义了滤波器的形状。

4. 从哲学上讲:原始图像数据包含了各个方面的丰富信息。

我们不可能没有目的处理图像而得到满足我们目的的结果,哪怕结果看起来很舒服。

以上。图像的聚类依赖数据的预处理,特别是特征提取。

你可能感兴趣的:(聚类)