本篇文章内容

KNN

1、介绍

2、算法步骤

3、度量方法

(1)距离度量

(2)相似度度量

(3)总结

4、K的大小

5、优缺点

6、代码实现

Dense SIFT

1、介绍

2、原理

3、代码实现

手势识别

1、实现及结果分析

(1)读出手势含义

(2)识别手势

参考文章


KNN

1、介绍

KNN即K最近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它最接近的K个邻居来代表。KNN是通过测量不同特征值之间的距离进行分类。它的思路是:如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。在分类中选择K个最相似数据中出现次数最多的分类作为新数据的分类,即“投票法”。它的核心思想可以用一句话来概括:物以类聚,人以群分。KNN算法主要涉及3个因素:样本集、距离或相似的衡量、K的大小

如上图,求绿色圆圈的所属类别,正方形和三角形都是样本数据。假设k=3,则绿色圆圈的邻居有两个三角形和一个正方形,按照投票法,绿色圆圈所属类别应该是红色三角形。若k=5,则绿色圆圈的邻居有两个三角形和三个正方形,则绿色圆圈所属类别是蓝色正方形。

2、算法步骤

(1)计算测试对象和训练集每个对象之间的距离;

(2)按递增顺序对距离进行排序;

(3)把距离最近的K个点作为测试对象的最近邻;

(4)找到这些邻居中的绝大多数类;

(5)将绝大多数类返回作为我们对测试对象归属类的预测;

在第二步排序之后 ,采用字典存储邻近标记,用文本字符串或者数字表示标记。

3、度量方法

(1)距离度量

距离度量(Distance)用于衡量个体在空间上存在的距离,距离越远说明个体间的差异越大。

欧氏距离是最常见的距离度量,衡量的是多维空间中各个点之间的绝对距离。公式如下:

因为计算是基于各维度特征的绝对数值,所以欧氏度量需要保证各维度指标在相同的刻度级别,比如对身高(cm)和体重(kg)两个单位不同的指标使用欧式距离可能使结果失效。

特征空间中的两个实例点的距离是两个实例点相似程度的反映。K近邻法的特征空间一般是n维实数向量空间。使用的距离是欧氏距离,但也可以是其他距离,如Minkowski Distance(明考斯基距离)或者Manhattan Distance(曼哈顿距离)等。

(2)相似度度量

相似度度量(Similarity),即计算个体间的相似程度,与距离度量相反,相似度度量的值越小,说明个体间相似度越小,差异越大。

余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。公式如下:

还有皮尔森相关系数(Pearson Correlation Coefficient),即相关分析中的相关系数r,分别对X和Y基于自身总体标准化后计算空间向量的余弦夹角。公式如下:

虽然余弦相似度对个体间存在的偏见可以进行一定的修正,但是因为只能分辨个体在维之间的差异,没法衡量每个维数值的差异。

(3)总结

根据欧氏距离和余弦相似度各自的计算方式和衡量特征,分别适用于不同的数据分析模型。欧氏距离能够体现个体数值特征的绝对差异,所以更多的用于需要从维度的数值大小中体现差异的分析;而余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感。

4、K的大小

K太小,分类结果易受噪声点影响;

K太大,近邻中又可能包含太多的其它类别的点。(对距离加权,可以降低k值设定的影响)

所以K值通常采用交叉经验来确定(经验规则:K一般低于训练样本数的平方根)

5、优缺点

缺点:属于懒惰算法,时间复杂度较高,训练集很大的时候搜索速度慢

优点:简单,易于理解,易于实现,无需估计参数,无需训练,可以采用任意距离度量

6、代码实现

此脚本创建两个不同的正态分布数据集,利用Pickle模块保存(数据均采用随机生成的方式)

# -*- coding: utf-8 -*-
# 创建数据
from numpy.random import randn
import pickle
from pylab import *# 创建二维样本数据
n = 100   # 100个点
# 两个正态分布数据集
class_1 = 0.4 * randn(n, 2)   # 100个二维点
class_2 = 1.9 * randn(n, 2) + array([6, 1])
labels = hstack((ones(n), -ones(n)))
# 用Pickle模块保存
with open('points_normal.pkl', 'w') as f:  # 可以用来训练
# with open('points_normal_test.pkl', 'w') as f:    #用来测试pickle.dump(class_1, f)pickle.dump(class_2, f)pickle.dump(labels, f)
print "save OK!"# 第二个分布
# 正态分布,并使数据成环绕状分布
class_1 = 0.4 * randn(n, 2)
r = 0.7 * 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)))with open('points_ring.pkl', 'w') as f:
# with open('points_ring_test.pkl', 'w') as f:pickle.dump(class_1, f)pickle.dump(class_2, f)pickle.dump(labels, f)print "save OK!"

用不同的保存文件名运行此脚本两次,得到四个数据集文件,两个测试,两个训练。

# -*- coding: utf-8 -*-
# 导入数据并分类
import pickle
from pylab import *
from PCV.classifiers import knn
from PCV.tools import imtoolspklist = ['points_normal.pkl', 'points_ring.pkl']  #figure()# load 2D points using Pickle二维数据点导入
for i, pklfile in enumerate(pklist):   # 导入pklist里的pkl文件with open(pklfile, 'r') 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)))  # 分类器# load test data using Pickle载入测试数据with open(pklfile[:-4]+'_test.pkl', 'r') as f:class_1 = pickle.load(f)class_2 = pickle.load(f)labels = pickle.load(f)# 测试 测试数据集的第一个数据点print model.classify(class_1[0])# 绘图def classify(x, y, model=model):return array([model.classify([xx, yy]) for (xx, yy) in zip(x, y)])# 绘制边界subplot(1, 2, i+1)imtools.plot_2D_boundary([-8, 8, -8, 8], [class_1, class_2], classify, [1, -1])    # 定义最大范围最小范围(画分界线)titlename = pklfile[:-4]title(titlename)
show()

这是用Pickle模块创建KNN分类器模型,并绘制出分类边界。绘图函数实在一个网格上进行评估,画出决策函数的边界,并用表示分类正确的点,o表示分类不正确的点。

令n=100时                                                                             n=400时

                  

分析:由上面两幅图对比,改变n的值运行时间不同,n越大运行时间越久,证明了KNN算法在样本数据集较大时,由于要逐个计算样本与测试点的欧式距离,导致运行时间加长。 但分类的结果大致还是相似的,除了出现个别错误分类外,分类界线都大抵相同。这说明数据的多少并不干扰KNN的分类,KNN适用于大多数的分类。

Dense SIFT

1、介绍

在对图像进行分类过程中,我们需要一个特征向量来表示一幅图像,这里我们采用稠密SIFT(即Dense SIFT)特征向量作为特征值向量。传统的SIFT算法即Sparse SIFT,不能很好地表征不同类之间的特征差异,达不到所需的分类要求。而Dense SIFT算法,是一种对输入图像进行分块处理,再进行SIFT运算的特征提取过程,提取我们感兴趣的patches中的每个位置的SIFT特征。Dense SIFT根据可调的参数大小,来适当满足不同分类任务下对图像的特征表征能力。Sparse SIFT则是对整幅图像的处理,得到感兴趣区域或者图像上若干个稳定的关键点的SIFT特征。所以通常来讲图像分类识别任务更经常使用Dense SIFT,而Sparse SIFT更适用于图像检索分割的任务。

2、原理

Dense SIFT是Sparse SIFT的一种变种,它在每个位置产生SIFT描述符。 在使用方向梯度直方图(HOG)描述这些兴趣点之前,SIFT使用高斯滤波差异(DoG)识别兴趣点,但是Dense SIFT不识别兴趣点,它只是在使用HOG描述之前将图像划分为重叠的单元格他们。因为它们都使用HOG,所以它们都产生128维特征向量。它与Sparse SIFT最大的不同在于关键点的选取是稠密且同规格的。

Dense SIFT的原理和SIFT原理(见SIFT算法原理)是相同的,不同的是在process_image()函数,为了使命令行处理,用savetext()函数将创建的帧保存在临时文件中,并含有对图像的大小、特征描述子的大小(网格大小)进行调整的参数。

Dense SIFT:

 def process_image_dsift(imagename,resultname,size=20,steps=10,force_orientation=False,resize=None)

输入分别是输入图像名称、输出名称、特征的大小、位置之间的步长、是否强迫计算描述子的方位(True则提取出来的描述子会基于局部主梯度方向归一化;False则所有描述子的方向都是朝上的)、图像大小

SIFT:

def process_image(imagename,resultname,params="--edge-thresh 10 --peak-thresh 5")

输入只是输入图像名称、输出名称

3、代码实现

此脚本分别将同一张图像提取dense SIFT特征及SIFT特征

# -*- coding: utf-8 -*-
from PCV.localdescriptors import sift, dsift
from pylab import *
from PIL import Imagedsift.process_image_dsift('E:/study_work/python/image/48.jpg', 'yz.dsift', 10, 10, True)
l, d = sift.read_features_from_file('yz.dsift')
im = array(Image.open('E:/study_work/python/image/48.jpg'))
sift.plot_features(im, l, True)
title('dense SIFT')
show()
sift.process_image('E:/study_work/python/image/48.jpg', 'yz.sift')
l1, d1 = sift.read_features_from_file('yz.sift')
sift.plot_features(im, l1, circle=False)
title('SIFT')
show()

        

由上图可以看出dense SIFT提取的特征是稠密的并且同等大小的,而SIFT提取的特征是部分感兴趣的区域。而图像分类识别更注重于整幅图像,所以dense SIFT更适合用于图像分类识别。

手势识别

手势识别是图像分类技术的应用,在此应用中,我们用dense SIFT描述子表示手势图像,并建立一个简单的手势识别系统。

1、实现及结果分析

(1)读出手势含义

# -*- coding: utf-8 -*-
import os
from PCV.localdescriptors import sift, dsift
from pylab import *
from PIL import Imageimlist = ['E:/study_work/python/gesture/L-uniform1.ppm', 'E:/study_work/python/gesture/O-uniform1.ppm','E:/study_work/python/gesture/V-uniform1.ppm', 'E:/study_work/python/gesture/E-uniform1.ppm','E:/study_work/python/gesture/Y-uniform1.ppm', 'E:/study_work/python/gesture/U-uniform1.ppm','E:/study_work/python/gesture/Point-uniform1.ppm', 'E:/study_work/python/gesture/Lu-uniform1.ppm', ]figure()
for i, im in enumerate(imlist):print imdsift.process_image_dsift(im, im[:-3] + 'dsift', 10, 10, True)# 对每一幅图像创建一个特征文件,90指代特征的大小,40是位置之间的步长,True表示提取出来的描述子会基于局部主梯度方向归一化l, d = sift.read_features_from_file(im[:-3] + 'dsift')dirpath, filename = os.path.split(im)im = array(Image.open(im))# 显示手势含义titletitlename = filename[:-13]   # 从文件名可以读出手势定义subplot(2, 4, i+1)  # 两行三列sift.plot_features(im, l, True)title(titlename)
show()

结果如下,我个人觉得这个方法比较麻烦的就是你要设置文件名然后它才能读出你的这个手势所代表的含义

(2)识别手势

此脚本是先读取训练集和测试集中的ppm文件,提取它们的dsift描述子,然后进行KNN分类,得出准确率和混淆矩阵。准确率是显示测试集中有多少图象是正确分类的。混淆矩阵显示每类有多少个样本被分在每一类中的矩阵,它可以显示错误的分布情况和那些类是经常相互“混淆”的。

# -*- coding: utf-8 -*-
from PCV.localdescriptors import dsift
import os
from PCV.localdescriptors import sift
from pylab import *
from PCV.classifiers import knndef get_imagelist(path):"""    Returns a list of filenames forall jpg images in a directory. """return [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.ppm')]   # 返回这个目录下所有ppm文件名def read_gesture_features_labels(path):# 对所有以.dsift结尾的文件创建一个列表featlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.dsift')]# 读取特征features = []for featfile in featlist:l, d = sift.read_features_from_file(featfile)features.append(d.flatten())   # flatten向量化features = array(features)# 创建标记labels = [featfile.split('/')[-1][0] for featfile in featlist]return features, array(labels)def print_confusion(res, labels, classnames):# 打印标记及相应的混淆矩阵n = len(classnames)# 混淆矩阵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]]] += 1print 'Confusion matrix for'print classnamesprint confusefilelist_train = get_imagelist('gesture/train')   # 训练集
filelist_test = get_imagelist('E:/study_work/python/Test-g')
imlist = filelist_train+filelist_test# 将图像尺寸调为(50,50)进行处理
for filename in imlist:featfile = filename[:-3]+'dsift'dsift.process_image_dsift(filename, featfile, 10, 5, resize=(50, 50))  # 调整图像尺寸为(50,50)features, labels = read_gesture_features_labels('gesture/train/')   # 读取特征、标签
test_features, test_labels = read_gesture_features_labels('E:/study_work/python/Test-g/')
classnames = unique(labels)# 测试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))])
# 准确率
acc = sum(1.0*(res==test_labels)) / len(test_labels)   # 相等乘1求和
print 'Accuracy:', accprint_confusion(res, test_labels, classnames)

训练集:静态手势数据库

多张手势图像测试:

识别结果:

分析:结果得出识别出来的手势只有C,其他都是未识别出来,所以准确率为1/8即0.375。这说明通过比较测试集中手势的dsift并进行knn分类后无法得出正确的结果。但在混淆矩阵中可以看出,是已经有识别出包含“A”、“B”、“C”。

测试图像:

识别结果:

分析:结果得出的准确率为0.25,但识别出的内容却全部为”F“,即未知。但混淆矩阵中有显示出”A“、”B“、和V”存在的可能。

单张手势进行识别:

分别测试"C"和"A"手势图像:

                     

训练集中“C”和“A”手势图像:

                        

结果:

                        

分析:“C”手势是比较相像的,所以通过两幅图像的dsift文件进行knn分类后可以找到归属类,而“A”手势较为不同,通过knn分类后得出错误的归类,所以准确率为0,混淆矩阵中也有显示此手势可能为“A”。

总结:

经以上这些实验可以看出,训练集和测试集背景不同加上手势有些许区别所能分类识别出的准确度不高,很多时候识别出的内容都被当作混淆内容而存放在混淆矩阵中,被作为错误的分类。在本次实验过程中KNN分类采用的是欧式距离度量方法,可以尝试其他的度量方法进行度量,比较准确率。如果准确率并没有改变,那考虑下是否是训练集不够大的问题。

参考文章

1、knn距离公式比较

KNN+Dense SIFT+手势识别相关推荐

  1. 计算机视觉——KNN算法以及手势识别应用

    文章目录 概述 KNN算法原理 KNN二维分类器模型 DSIFT 手势识别应用 手势识别具体流程 概述 本文介绍了KNN算法的基本原理,以及配合dfift(稠密sift)进行一个手势识别方面的应用 K ...

  2. KNN分类法与手势识别

    K邻近分类法(KNN) 1. 在分类算法中,最简单且最常用的一种方法之一就是KNN算法.这种算法把要分类的对象与训练集中已知类标定的所有对象进行对比,并由k近邻对指派到哪个类进行投票.但knn属于懒惰 ...

  3. dense sift matlab,一个 Dense SIFT 算法的 matlab 实现 | 学步园

    Ce Liu, Jenny Yuen, Antonio Torralba,JosefSivic, andWilliam T. Freeman 版权所有. 修改的部分函数与变量的名字,使其好懂了一些.不 ...

  4. 计算机视觉--KNN算法和稠密SIFT实现图像识别(手势识别)

    KNN算法 一.KNN算法概述 kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性.该方法在确定分类决策上只依 ...

  5. knn可视化、稠密dsift原理、手势识别

    一.knn可视化: 1.knn算法简单介绍: KNN是一种监督学习算法,通过计算新数据与训练数据特征值之间的距离,然后选取K(K>=1)个距离最近的邻居进行分类判(投票法)或者回归.若K=1,新 ...

  6. python-KNN简单数据分类+dsift+手势识别

    一.基本介绍 (一)K邻近分类法(KNN) KNN算法在分类方法中,是属于简单且应用得最多的方法之一,它把要分类的对象与训练几种已知类标记的所有对象进行对比,并由k近邻对指派到哪个类进行投票. KNN ...

  7. 基于SIFT+Kmeans+SVM的场景识别,参数需注意的问题(Matlab实现)

    具体细节请参考我的论文 http://download.csdn.net/detail/m0_37393277/9895391 1.试验目的: 实现20类的建筑图片分类. 2.实现方法及正确率: 可参 ...

  8. Imagenet FoW类数据集 SIFT特征

    原文地址http://www.image-net.org/download-features We currently provide densely sampled SIFT[1] features ...

  9. Python计算机视觉:第八章 图像类容分类

    第八章 图像类容分类 8.1 K最近邻 8.1.1 一个简单的二维例子 8.1.2 图像稠密(dense)sift特征) 8.1.3 图像分类--手势识别 8.1 session 和登录失败 8.1. ...

最新文章

  1. java coverage exclude使用
  2. tablednd保存 php,jqgrid中使用tableDnd插件,jqgridtablednd插件
  3. mysql 单表多字段查询_单表多字段MySQL模糊查询的实现
  4. 双系统安装 Windows8和Windows Server2012
  5. oracle优质图书,经典Oracle图书推荐(之四)_oracle
  6. Git入门及上传项目到github中
  7. Pandas+Pyecharts 数据分析与可视化 3D地图+柱状图
  8. C# 把list中的数据转成规定格式的json格式
  9. idle点开没反应_翟天临、靳东,一个人越是没文化越是喜欢装
  10. 【Java】函数使用
  11. Android 应用程序之间数据共享—ContentProvider
  12. 最新nodejs的开发学习实战(1)从一个博客开始
  13. 学习笔记——物联网知识
  14. python执行js之pyexecjs
  15. 用python祝福父亲节_python 计算 父亲节
  16. 远程桌面链接怎么共享本地磁盘
  17. RocketMQ 优雅停机技巧
  18. Git 拉取远程仓库失败
  19. 微信小程序checkbox调整大小
  20. truncate table很慢之enq: RO - fast object reuse和local write wait等待分析

热门文章

  1. 交通预测论文翻译:Deep Learning on Traffic Prediction: Methods,Analysis and Future Directions
  2. 年后跳槽如何准备?(转)
  3. 从数字化过渡到智能制造
  4. CocoaLumberjack的ios应用开发使用指南
  5. mysql面试-01
  6. ubuntu 更新系统源
  7. android 友盟统计功能,在Android工程中集成友盟统计
  8. 【Linux】电子词典
  9. 国产设计软件都有哪些,国产设计工具推荐
  10. Unicast RPF,单播逆向转发