标题
KNN算法
- KNN算法简介
KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较,提取出样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类作为新数据的分类。
说明:KNN没有显示的训练过程,它是“懒惰学习”的代表,它在训练阶段只是把数据保存下来,训练时间开销为0,等收到测试样本后进行处理。 - 实验过程
首先,创建两个不同的二维点集,每个点集有两类,用pickle模块保存,用不同的保存文件运行该脚本两次,得到4个二维数据集文件,每个分布都有两个文件:一个用作训练,一个用作测试。
代码如下:
# -*- coding: utf-8 -*-
from numpy.random import randn
import pickle
from pylab import *
# create sample data of 2D points
n = 200
# two normal distributions两个正态分布的数据集
class_1 = 0.6 * randn(n,2)
class_2 = 1.2 * randn(n,2) + array([5,1])
labels = hstack((ones(n),-ones(n)))
# save with Pickle
#with open('points_normal.pkl', 'w') as f:
#用pickle模块保存
with open('points_normal_test.pkl', 'wb') as f:
pickle.dump(class_1,f)
pickle.dump(class_2,f)
pickle.dump(labels,f)
# normal distribution and ring around it
print("save OK!")
#正态分布,并使数据成环绕状分布
class_1 = 0.6 * randn(n,2)
r = 0.8 * randn(n,1) + 5
angle = 2*pi * randn(n,1)
class_2 = hstack((r*cos(angle),r*sin(angle)))
labels = hstack((ones(n),-ones(n)))
# save with Pickle
#with open('points_ring.pkl', 'w') as f:
with open('points_ring_test.pkl', 'wb') as f:
pickle.dump(class_1,f)
pickle.dump(class_2,f)
pickle.dump(labels,f)
print ("save OK!")
之后,用Pickle模块创建一个kNN分类器模型。载入上面所保存的一个数据集,并测试数据中的数据点。并将分类结果可视化。
# -*- coding: utf-8 -*-
import pickle
from pylab import *
from PCV.classifiers import knn
from PCV.tools import imtools
pklist=['points_normal.pkl','points_ring.pkl']
figure()
# load 2D points using Pickle 用Pickle载入二维数据点
for i, pklfile in enumerate(pklist):
with open(pklfile, 'rb') as f:
class_1 = pickle.load(f)
class_2 = pickle.load(f)
labels = pickle.load(f)
# load test data using Pickle 用Pickle载入测试数据
with open(pklfile[:-4]+'_test.pkl', 'rb') as f:
class_1 = pickle.load(f)
class_2 = pickle.load(f)
labels = pickle.load(f)
model = knn.KnnClassifier(labels,vstack((class_1,class_2)))
# test on the first point
print (model.classify(class_1[0]))
#define function for plotting
def classify(x,y,model=model):
return array([model.classify([xx,yy]) for (xx,yy) in zip(x,y)])
# lot the classification boundary
subplot(1,2,i+1)
imtools.plot_2D_boundary([-6,6,-6,6],[class_1,class_2],classify,[1,-1])
titlename=pklfile[:-4]
title(titlename)
show()
- 实现结果
画出来的结果如图所示,用K临近分类器分类二维数据。每个示例中,不同颜色代表不同的类,正确的用星号“*”表示,错误的用原点“o”表示,曲线是分类器的决策边界。由此可以看出,kNN决策边界适用于没有任何明确模型的类分布。
3.1 当参数k=5时,通过改变点的数量n:
n=100时:
n=200时:
n=500时(跑的非常慢,电脑基本快要炸掉了):
3.2 取n=200,改变k的值
k=3:
k=5:
k=9:
k=13:
可以看出,随着k值不断增大,K临近分类器出现错误的点也不断增多,所以k的取值越小,分类的结果也就越好(但也不能太小,k取3~5时为佳)。
稠密SIFT特征向量
- 稠密SIFT特征向量
该算法首先将表达目标的矩形区域分成相同大小的矩形块,计算每一个小块的SIFT特征,再对各个小块的稠密SIFT特征在中心位置进行采样,建模目标的表达.然后度量两个图像区域的不相似性,先计算两个区域对应小块的距离,再对各距离加权求和作为两个区域间的距离.因为目标所在区域靠近边缘的部分可能受到背景像素的影响,而区域的内部则更一致,所以越靠近区域中心权函数的值越大。 - 实验过程
利用下面的代码可以计算稠密SIFT描述子,并可视化他们的位置:
输入图像,计算出dsift描述子,
# -*- coding: utf-8 -*-
from PCV.localdescriptors import sift, dsift
from pylab import *
from PIL import Image
dsift.process_image_dsift('gesture/empire.jpg','empire.dsift',90,40,True)
l,d = sift.read_features_from_file('empire.dsift')
im = array(Image.open('gesture/empire.jpg'))
sift.plot_features(im,l,True)
title('dense SIFT')
show()
- 实验结果
尚大楼:
图像分类:手势分类
- 图像集:本次试验用稠密SIFT描述子来表示这些手势图像,并建立一个简单的手势识别系统。本次试验的数据库为自己拍摄的静态手势:
1.1 集美大学手势“JMU”:
1.2 “ok”:
1.3 非常6+1:
1.4 数字“4”:
先将图片进行批处理,像素改为50×50:
生成图片dsift描述子并可视化:
将4类手势各18张(共72张)图片进行训练,其余图片进行测试,测试结果:
正确率为88.37%
其中,手势“4”、手势“6+1”、手势“ok”测试结果全部正确,只有手势“jmu”只有两张正确,是因为训练集和测试集中的图片背景颜色不同,由于训练集中手势“jmu”的图片中黑色背景较多,导致测试集中只有“jmu”是黑色背景图片的被判定为是正确的,其余背景被判定为其他手势。
将图片换为相同背景:
正确率达到97.56%,只有一张判断错误。
因此,训练集和测试集的照片背景应尽可能拍摄同一色调,才不会因为背景导致识别出错。
附代码:
# -*- coding: utf-8 -*-
from PCV.localdescriptors import dsift
import os
from PCV.localdescriptors import sift
from pylab import *
from PCV.classifiers import knn
def get_imagelist(path):
""" Returns a list of filenames for
all jpg images in a directory. """
return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]
def read_gesture_features_labels(path):
# create list of all files ending in .dsift
featlist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.dsift')]
# read the features
features = []
for featfile in featlist:
l,d = sift.read_features_from_file(featfile)
features.append(d.flatten())
features = array(features)
# create labels
labels = [featfile.split('/')[-1][0] for featfile in featlist]
return features,array(labels)
def print_confusion(res,labels,classnames):
n = len(classnames)
# confusion matrix
class_ind = dict([(classnames[i],i) for i in range(n)])
confuse = zeros((n,n))
for i in range(len(test_labels)):
confuse[class_ind[res[i]],class_ind[test_labels[i]]] += 1
print ('Confusion matrix for')
print (classnames)
print (confuse)
filelist_train = get_imagelist('gesture/mytrain/')
filelist_test = get_imagelist('gesture/mytest/')
imlist=filelist_train+filelist_test
# process images at fixed size (50,50)
for filename in imlist:
featfile = filename[:-3]+'dsift'
dsift.process_image_dsift(filename,featfile,10,5,resize=(50,50))
features,labels = read_gesture_features_labels('gesture/mytrain/')
test_features,test_labels = read_gesture_features_labels('gesture/mytest/')
classnames = unique(labels)
# test kNN
k = 1
knn_classifier = knn.KnnClassifier(labels,features)
res = array([knn_classifier.classify(test_features[i],k) for i in
range(len(test_labels))])
# accuracy
acc = sum(1.0*(res==test_labels)) / len(test_labels)
print ('Accuracy:', acc)
print_confusion(res,test_labels,classnames)