• 一个 Dense SIFT 算法的 matlab 实现
2021-04-20 02:31:43

Ce Liu, Jenny Yuen, Antonio Torralba,JosefSivic, andWilliam T. Freeman 版权所有。

修改的部分函数与变量的名字，使其好懂了一些。不过这个算法由于没有salient keypoint detection和rotation normalization，所以对尺度以及旋转这些affine transform没有移不变的性质。

function [ SIFTFeatureVector, locationX, locationY ] = DenseSIFT( image, nPatchSize, nGridSpacing )

image = double( image );

image = mean( image, 3 );

image = image / max( image( : ) );

% parameters

nAngleNums = 8;

nBinNums = 4;

nSampleNums = nBinNums * nBinNums;

alpha = 9; %% parameter for attenuation of angles (must be odd)

if nargin < 5

sigmaGuassian = 1;

end

angleStep = 2 * pi / nAngleNums;

angles = 0 : angleStep : 2 * pi;

angles( nAngleNums + 1 ) = [ ]; % bin centers

[ nRow nCol ] = size( image );

[ gaussianX, gaussianY ] = genDeltaGaussian( sigmaGuassian );

imageVerticalEdges = filter2( gaussianX, image, 'same' ); % vertical edges

imageHorizontalEdges = filter2( gaussianY, image, 'same' ); % horizontal edges

imageTheta = atan2( imageHorizontalEdges, imageVerticalEdges );

imageTheta( isnan( imageTheta ) ) = 0; % replace illegal result with 0

% descriptor locations

locationX = nPatchSize / 2 : nGridSpacing : nCol - nPatchSize / 2 + 1;

locationY = nPatchSize / 2 : nGridSpacing : nRow - nPatchSize / 2 + 1;

% make orientation images

imageOrientation = zeros( [ nRow, nCol, nAngleNums ], 'single' );

% for each histogram angle

imageCos = cos( imageTheta );

imageSin = sin( imageTheta );

for index = 1 : nAngleNums

% compute each orientation channel

tmp = ( imageCos * cos( angles( index ) ) + imageSin * sin( angles( index ) ) ).^ alpha;

tmp = tmp .* ( tmp > 0 );

% weight by magnitude

imageOrientation( :, :, index ) = tmp .* imageGradientMagnitude;

end

% Convolution formulation:

nHalfPatchSize = nPatchSize / 2;

nHalfPatchSizeMinusDotFive = nHalfPatchSize - 0.5;

sampleResolution = nPatchSize / nBinNums;

weightX = abs( ( 1 : nPatchSize ) - nHalfPatchSizeMinusDotFive ) / sampleResolution;

weightX = ( 1 - weightX ) .* ( weightX <= 1 );

for index = 1 : nAngleNums

imageOrientation( :, :, index ) = conv2( weightX, weightX', imageOrientation( :, :, index ), 'same' );

end

% Sample SIFT bins at valid locations (without boundary artifacts)

% find coordinates of sample points (bin centers)

[ samplePosX, samplePosY ] = meshgrid( linspace( 1, nPatchSize + 1, nBinNums + 1 ) );

samplePosX = samplePosX( 1 : nBinNums, 1 : nBinNums ); samplePosX = samplePosX( : ) - nPatchSize / 2;

samplePosY = samplePosY( 1 : nBinNums, 1 : nBinNums ); samplePosY = samplePosY( : ) - nPatchSize / 2;

SIFTFeatureVector = zeros( [ length( locationY ) length( locationX ) nAngleNums * nSampleNums ] , 'single' );

nOffset = 0;

for n = 1 : nBinNums * nBinNums

SIFTFeatureVector( :, :, nOffset + 1 : nOffset + nAngleNums ) = imageOrientation( locationY + samplePosY(n), locationX + samplePosX(n), : );

nOffset = nOffset + nAngleNums;

end

clear imageOrientation

% Outputs:

[ locationX, locationY ] = meshgrid( locationX, locationY );

[ nrows, ncols, cols ] = size( SIFTFeatureVector );

% normalize SIFT descriptors

SIFTFeatureVector = reshape( SIFTFeatureVector, [nrows * ncols nAngleNums * nSampleNums ] );

SIFTFeatureVector = SIFTNormalization( SIFTFeatureVector );

SIFTFeatureVector = reshape( SIFTFeatureVector, [ nrows ncols nAngleNums * nSampleNums] );

function [ GX, GY ] = genDeltaGaussian( sigma )

% laplacian of size sigma

G = genGaussian(sigma);

[ GX, GY ] = gradient( G );

GX = GX * 2 ./ sum( sum( abs( GX ) ) );

GY = GY * 2 ./ sum( sum( abs( GY ) ) );

function G = genGaussian( sigma )

if all( size( sigma ) == [ 1, 1 ] )

% isotropic gaussian

filterWindow = 4 * ceil( sigma ) + 1;

G = fspecial( 'gaussian', filterWindow, sigma );

else

% anisotropic gaussian

filterWindowX = 2 * ceil( sigma( 1 ) ) + 1;

filterWindowY = 2 * ceil( sigma( 2 ) ) + 1;

GaussianX = normpdf( -filterWindowX: filterWindowX, 0, sigma( 1 ) );

GaussianY = normpdf( -filterWindowY: filterWindowY, 0, sigma( 2 ) );

G = GaussianY' * GaussianX;

end

function SIFTFeatureVector = SIFTNormalization( SIFTFeatureVector )

% normalize SIFT descriptors (after Lowe)

% find indices of descriptors to be normalized (those whose norm is larger than 1)

tmp = sqrt( sum( SIFTFeatureVector.^2, 2 ) );

normalizeIndex = find( tmp > 1 );

SiftFeatureVectorNormed = SIFTFeatureVector( normalizeIndex, : );

SiftFeatureVectorNormed = SiftFeatureVectorNormed ./ repmat( tmp( normalizeIndex, : ), [ 1 size( SIFTFeatureVector, 2 ) ] );

SiftFeatureVectorNormed( SiftFeatureVectorNormed > 0.2 ) = 0.2;

% finally, renormalize to unit length

tmp = sqrt( sum( SiftFeatureVectorNormed.^2, 2 ) );

SiftFeatureVectorNormed = SiftFeatureVectorNormed ./ repmat( tmp, [ 1 size( SIFTFeatureVector, 2 ) ] );

SIFTFeatureVector( normalizeIndex, : ) = SiftFeatureVectorNormed;

更多相关内容
• 本文提出了一种基于密集尺度不变特征变换(SIFT)的多聚焦图像融合方法。本文的主要新颖之处在于它显示了图像局部特征的巨大潜力，如被用于图像融合的密度筛选。特别地，局部特征描述不仅可以作为活动水平的测量，而且...
• ## denseSift

热门讨论 2014-05-05 18:28:00
此文件是稠密尺度不变特征提取（dense Sift），用于图像特征提取 , 大家注意是matlab版本的
• Multi-focus image fusion with dense SIFT一文的文章，很不错，值得学习
• python3 Dense SIFT算法的应用与实现 Dense SIFT 因为课题的需求，传统的SIFT算法即Sparse SIFT，不能很好地表征不同类之间的特征差异，达不到所需的分类要求。而Dense SIFT算法，是一种对输入图像进行分块处理，...

## python3 Dense SIFT算法的应用与实现

1. Dense SIFT
因为课题的需求，传统的SIFT算法即Sparse SIFT，不能很好地表征不同类之间的特征差异，达不到所需的分类要求。而Dense SIFT算法，是一种对输入图像进行分块处理，再进行SIFT运算的特征提取过程。Dense SIFT根据可调的参数大小，来适当满足不同分类任务下对图像的特征表征能力。而Sparse SIFT则是对整幅图像的处理，得到一系列特征点(keypoints)。如下图所示：

在此背景下，通常来讲Dense SIFT更适用于图像分类识别的任务，而Sparse SIFT更适用于图像检索分割的任务。

2. Dense SIFT的代码实现

原代码为python2，现用python3重新编译：

import numpy as np
from scipy import signal
from matplotlib import pyplot
import matplotlib

# sift features
Nangles = 8
Nbins = 4
Nsamples = Nbins**2
alpha = 9.0
angles = np.array(range(Nangles))*2.0*np.pi/Nangles

def gen_dgauss(sigma):
'''
generating a derivative of Gauss filter on both the X and Y
direction.//在X和Y方向上生成高斯滤波器的导数。
'''
fwid = np.int(2*np.ceil(sigma))
G = np.array(range(-fwid,fwid+1))**2
G = G.reshape((G.size,1)) + G
G = np.exp(- G / 2.0 / sigma / sigma)
G /= np.sum(G)
GH *= 2.0/np.sum(np.abs(GH))
GW *= 2.0/np.sum(np.abs(GW))
return GH,GW

class DsiftExtractor:
'''
The class that does dense sift feature extractor.//进行密集筛选的类提取器
Sample Usage:
extractor = DsiftExtractor(gridSpacing,patchSize,[optional params])
feaArr,positions = extractor.process_image(Image)
'''
def __init__(self, gridSpacing, patchSize,
nrml_thres = 1.0,\
sigma_edge = 0.8,\
sift_thres = 0.2):
'''
gridSpacing: the spacing for sampling dense descriptors//密集描述符的采样间隔
patchSize: the size for each sift patch//每个sift patch的尺寸
nrml_thres: low contrast normalization threshold//低对比度归一化阈值
sigma_edge: the standard deviation for the gaussian smoothing//高斯平滑的标准差
sift_thres: sift thresholding (0.2 works well based on
Lowe's SIFT paper)//sift阈值化(0.2基于Lowe's sift paper效果很好)
'''
self.gS = gridSpacing
self.pS = patchSize
self.nrml_thres = nrml_thres
self.sigma = sigma_edge
self.sift_thres = sift_thres
# compute the weight contribution map
sample_res = self.pS / np.double(Nbins)
sample_p = np.array(range(self.pS))
sample_ph, sample_pw = np.meshgrid(sample_p,sample_p)
sample_ph.resize(sample_ph.size)
sample_pw.resize(sample_pw.size)
bincenter = np.array(range(1,Nbins*2,2)) / 2.0 / Nbins * self.pS - 0.5
bincenter_h, bincenter_w = np.meshgrid(bincenter,bincenter)
bincenter_h.resize((bincenter_h.size,1))
bincenter_w.resize((bincenter_w.size,1))
dist_ph = abs(sample_ph - bincenter_h)
dist_pw = abs(sample_pw - bincenter_w)
weights_h = dist_ph / sample_res
weights_w = dist_pw / sample_res
weights_h = (1-weights_h) * (weights_h <= 1)
weights_w = (1-weights_w) * (weights_w <= 1)
# weights is the contribution of each pixel to the corresponding bin center
self.weights = weights_h * weights_w
#pyplot.imshow(self.weights)
#pyplot.show()

def process_image(self, image, positionNormalize = True,\
verbose = True):
'''
processes a single image, return the locations
and the values of detected SIFT features.//处理单个图像，返回检测到的SIFT特征的位置和值。
image: a M*N image which is a numpy 2D array. If you
pass a color image, it will automatically be converted
to a grayscale image.//一个M*N的图像，它是一个numpy二维数组。如果您传递一个彩色图像，它将自动转换为灰度图像。
positionNormalize: whether to normalize the positions
to [0,1]. If False, the pixel-based positions of the
top-right position of the patches is returned.//是否将位置规范化为[0,1]。如果为False，则返回补丁右上角的基于像素的位置。

Return values:
feaArr: the feature array, each row is a feature//特征数组，每一行都是一个特征
positions: the positions of the features//特征的位置
'''

image = image.astype(np.double)
if image.ndim == 3:
# we do not deal with color images.
image = np.mean(image,axis=2)
# compute the grids
H,W = image.shape
gS = self.gS
pS = self.pS
remH = np.mod(H-pS, gS)
remW = np.mod(W-pS, gS)
offsetH = remH//2
offsetW = remW//2
gridH,gridW = np.meshgrid(range(offsetH,H-pS+1,gS), range(offsetW,W-pS+1,gS))

gridH = gridH.flatten()
gridW = gridW.flatten()
if verbose:
print('Image: w {}, h {}, gs {}, ps {}, nFea {}'.\
format(W,H,gS,pS,gridH.size))
feaArr = self.calculate_sift_grid(image,gridH,gridW)
feaArr = self.normalize_sift(feaArr)
if positionNormalize:
positions = np.vstack((gridH / np.double(H), gridW / np.double(W)))
else:
positions = np.vstack((gridH, gridW))
return feaArr, positions

def calculate_sift_grid(self,image,gridH,gridW):
'''
This function calculates the unnormalized sift features
It is called by process_image().//此函数计算未规范化的sift特性。
//它被process_image()调用。
'''
H,W = image.shape
Npatches = gridH.size
feaArr = np.zeros((Npatches,Nsamples*Nangles))

GH,GW = gen_dgauss(self.sigma)
IH = signal.convolve2d(image,GH,mode='same')
IW = signal.convolve2d(image,GW,mode='same')
Imag = np.sqrt(IH**2+IW**2)
Itheta = np.arctan2(IH,IW)
Iorient = np.zeros((Nangles,H,W))
for i in range(Nangles):
Iorient[i] = Imag * np.maximum(np.cos(Itheta - angles[i])**alpha,0)
#pyplot.imshow(Iorient[i])
#pyplot.show()
for i in range(Npatches):
currFeature = np.zeros((Nangles,Nsamples))
for j in range(Nangles):
currFeature[j] = np.dot(self.weights,\
Iorient[j,gridH[i]:gridH[i]+self.pS, gridW[i]:gridW[i]+self.pS].flatten())
feaArr[i] = currFeature.flatten()
return feaArr

def normalize_sift(self,feaArr):
'''
This function does sift feature normalization
following David Lowe's definition (normalize length ->
thresholding at 0.2 -> renormalize length)
'''
siftlen = np.sqrt(np.sum(feaArr**2,axis=1))
hcontrast = (siftlen >= self.nrml_thres)
siftlen[siftlen < self.nrml_thres] = self.nrml_thres
# normalize with contrast thresholding
feaArr /= siftlen.reshape((siftlen.size,1))
feaArr[feaArr>self.sift_thres] = self.sift_thres
# renormalize high-contrast ones
feaArr[hcontrast] /= np.sqrt(np.sum(feaArr[hcontrast]**2,axis=1)).\
reshape((feaArr[hcontrast].shape[0],1))
return feaArr

class SingleSiftExtractor(DsiftExtractor):
'''
The simple wrapper class that does feature extraction, treating
the whole image as a local image patch.//一个简单的封装类，它能把整个图像当作一个局部图像补丁
'''
def __init__(self, patchSize,
nrml_thres = 1.0,\
sigma_edge = 0.8,\
sift_thres = 0.2):
# simply call the super class __init__ with a large gridSpace
DsiftExtractor.__init__(self, patchSize, patchSize, nrml_thres, sigma_edge, sift_thres)

def process_image(self, image):
return DsiftExtractor.process_image(self, image, False, False)[0]

if __name__ == '__main__':
# ignore this. I only use this for testing purpose...
from scipy import misc
extractor = DsiftExtractor(8,16,1)
image = np.mean(np.double(image),axis=2)
feaArr,positions = extractor.process_image(image)
#pyplot.hist(feaArr.flatten(),bins=100)
#pyplot.imshow(feaArr[:256])
#pyplot.plot(np.sum(feaArr,axis=0))
pyplot.imshow(feaArr[np.random.permutation(feaArr.shape[0])[:256]])

# test single sift extractor
extractor = SingleSiftExtractor(16)
feaArrSingle = extractor.process_image(image[:16,:16])
pyplot.figure()
pyplot.plot(feaArr[0],'r')
pyplot.plot(feaArrSingle,'b')
pyplot.show()



代码e.g.
如果你的输入图像像素大小是200 * 200，设定步长参数为8，patch块大小为16 * 16，输入图像转换为24 * 24=576个patch块，每个patch块进行SIFT提取关键点，最后得到576个特征点。这样输入图像就转换为了576 * 128维的矩阵向量。
继续添加一个批量处理函数，处理好数据集，就可以进行后续的分类识别工作了。

展开全文
• ## DenseSIFT

万次阅读 2014-05-05 16:02:13
在此，我们引出dense SIFT与做特征匹配所用到的SIFT的不同点。 dense SIFT是提取我们感兴趣的patches中的 每个位置 的SIFT特征。而通常做特征匹配的SIFT算法只是得到感兴趣区域或者图像上 若干个稳定 的关键点的SIFT...

参考网址:http://www.scholarpedia.org/article/Scale_Invariant_Feature_Transform

dense SIFT在目标分类和场景分类有重要的应用。接触较多文献的朋友可以发现，dense SIFT经常会用在bag of words 模型中[1]。在近年关于场景分类的论文中，我们可能会看到如下的细节。如以16×16 pixel大小的size和8 pixels的stepsize提取dense SIFT特征，然后做max pooling……。在此，我们引出dense SIFT与做特征匹配所用到的SIFT的不同点。dense SIFT是提取我们感兴趣的patches中的每个位置的SIFT特征。而通常做特征匹配的SIFT算法只是得到感兴趣区域或者图像上若干个稳定的关键点的SIFT特征。

如图所示，目前关于dense SIFT提取比较流行的做法是，拿一个size固定的掩模或者bounding box，以一定的步长（stepsize）在图像上自左向右、从上到下提取dense SIFT的patch块。

图 denseSIFT提取示意图

关于dense SIFT的代码网上能够比较容易地搜到，vlfeat上有dense SIFT的c++和matlab版本代码。

参考文献：

[1] Yang J, Yu K, Gong Y, et al. Linear spatial pyramid matching using sparse coding for image classification[C]//Computer Vision and Pattern Recognition, 2009. CVPR 2009. IEEE Conference on. IEEE, 2009: 1794-1801.

展开全文
• • 使用SIFTDense SIFT 和SURF 从图像中提取特征。 将这些特征应用于立体视觉匹配。 • 该项目是使用 WPF、C# 和 OpenCVSharp 的桌面应用程序。 • 该项目是南安普敦大学人工智能理学硕士“高级计算机视觉”课程...
• 基于深度学习与Dense SIFT融合的人脸表情识别.pdf
• Dense SIFT 1、介绍 2、原理 3、代码实现 手势识别 1、实现及结果分析 （1）读出手势含义 （2）识别手势 参考文章 KNN 1、介绍 KNN即K最近邻，就是K个最近的邻居的意思，说的是每个样本都...

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）用于衡量个体在空间上存在的距离，距离越远说明个体间的差异越大。

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

$dist(X,Y)=\sqrt{\sum_{i=1}^{n}(x_{i}-y_{i})^{2}}$

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

特征空间中的两个实例点的距离是两个实例点相似程度的反映。K近邻法的特征空间一般是n维实数向量空间$R_{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 imtools

pklist = ['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:

model = knn.KnnClassifier(labels, vstack((class_1, class_2)))  # 分类器
# load test data using Pickle载入测试数据
with open(pklfile[:-4]+'_test.pkl', 'r') as 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 Image

dsift.process_image_dsift('E:/study_work/python/image/48.jpg', 'yz.dsift', 10, 10, True)
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')
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 Image

imlist = ['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 im
dsift.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))
# 显示手势含义title
titlename = 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 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('.ppm')]   # 返回这个目录下所有ppm文件名

# 对所有以.dsift结尾的文件创建一个列表
featlist = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.dsift')]
# 读取特征
features = []
for featfile in featlist:
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]]] += 1
print 'Confusion matrix for'
print classnames
print confuse

filelist_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/')   # 读取特征、标签
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:', acc

print_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分类采用的是欧式距离度量方法，可以尝试其他的度量方法进行度量，比较准确率。如果准确率并没有改变，那考虑下是否是训练集不够大的问题。

# 参考文章

展开全文
• ## DenseSift

万次阅读 2013-11-30 22:13:29
Dense SIFT:不构建高斯尺度空间，只在a single scale上提取SIFT特征，可以得到每一个位置的SIFT descriptor SIFT:需要构建高斯尺度空间，只能得到Lowe算法计算得到的点的SIFT descriptor 代码：Matlab代码 C++代码
• KNN算法和Dense SIFT 摘要： KNN Dense Sift 1.KNN算法 kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别，则该样本也属于这个类别，并具有这个类别上样本的...
• Dense SIFT算法，是一种对输入图像进行分块处理，再对每一块进行SIFT运算的特征提取过程。Dense SIFT根据可调的参数大小，来适当满足不同分类任务下对图像的特征表征能力；而传统的SIFT算法则是对整幅图像的处理，...
• Dense SIFT是图像特征描述子SIFT的快版变体，即稠密SIFT特征向量。当研究目标是对同样的物体或者场景寻找对应关系（correspondence）时， SIFT更好。而研究目标是图像表示或者场景理解时，Dense SIFT更好，因为即使...
• 基于自适应Dense-SIFT的大规模图像检索
• 有个博友问SIFTDense-SIFT在应用上的区别。这个问题可以放大到Sparse feature和Dense feature的使用场景上（不然现在说Dense-SIFT估计没人鸟了）。之前自己也考虑过这个问题，今天不妨写出来。这些都是对基本问题...
• 上一篇博客中，我们已经介绍了图像检索的原理与实现，这篇要介绍图像分类，什么是图像分类呢？图像分类就是输入一张图像，找到它属于哪一类。比如拍照识花，我们拍一张花的图像上传系统，...二、dense SIFT算法 1....
• Dense SIFT.pngVLFeat implements a fast dense version of SIFT, called vl_dsift. The function is roughly equivalent to running SIFT on a dense gird of locations at a fixed scale and orientation. This ty...
• end % Sample SIFT bins at valid locations (without boundary artifacts) % find coordinates of sample points (bin centers) [ samplePosX, samplePosY ] = meshgrid( linspace( 1, nPatchSize + 1, nBinNums +...
• 一、Dense-sift（稠密SIFT）原理 图像检索总是用SIFT（利用了检测子） 大多数情况下我们并没有训练样本。因此，我们需要利用人的经验过滤区分性低的点（除此之外还引入了IDF进一步加权）。因此，大部分检索问题都...
• dense SIFT与做特征匹配所用到的SIFT的不同点：dense SIFT是提取我们感兴趣的patches中的每个位置的SIFT特征。而通常做特征匹配的SIFT算法只是得到感兴趣区域或者图像上若干个稳定的关键点的SIFT特征。因此Dense ...
• ## Dense-sift的理解

千次阅读 2018-02-06 11:45:19
Dense-SIFTsift的密集采样板，由于SIFT的实时性差，目前特征提取多采用密集采样（源自李菲菲的A Bayesian Hierarchical Model for Learning Natural Scene Categories），代码好理解，但是有一个疑问SPM中采用...
• SIFT算法出现的问题： 在处理牙齿有关的数据时，由于牙齿的特征较少，用一般的SIFT算法求得的特征点是...dense SIFT算法可以得到相对稠密的特征点，则可以通过检测到的足够多的特征点进行特征匹配，并通过RANSAC方
• title('dense SIFT') show()   # -*- coding: utf-8 -*- import os from PCV.localdescriptors import sift, dsift from pylab import * from PIL import Image imlist=['gesture/example/C-uniform01.ppm...
• ## SIFT vs Dense-SIFT

万次阅读 2014-10-16 20:53:44
有个博友问SIFTDense-SIFT在应用上的区别。这个问题可以放大到Sparse feature和Dense feature的使用场景上。之前自己也考虑过这个问题，今天不妨写出来。
• title('dense SIFT') show() 图像分类之手势识别 1.用稠密SIFT函数来对图像进行处理，可以得到所有图像的特征向量，还要对所有图像做好标记。 2.用训练数据及其标记作为输入，创建分类器对象(使用了KNN方法)...
• dense sift(稠密sift)原理。③手势识别一.K邻近分类法(KNN)目前存在很多分类方法，其中最简单且用的最多的一种方法就是KNN(K-Nearest Neighbor,K邻近分类法)，这种算法把要分类的对象，比如我们后面要用到的特征...
• dense sift(稠密sift)原理。③手势识别一.K邻近分类法(KNN)目前存在很多分类方法，其中最简单且用的最多的一种方法就是KNN(K-Nearest Neighbor,K邻近分类法)，这种算法把要分类的对象，比如我们后面要用到的特征...
• dense sift（稠密sift）原理。③手势识别一.K邻近分类法(KNN)目前存在很多分类方法，其中最简单且用的最多的一种方法就是KNN（K-Nearest Neighbor,K邻近分类法），这种算法把要分类的对象，比如我们后面要用到的...
• sift提取特征描述子，对图像进行处理，利用os.system()函数执行sift.exe文件
• VLFeat是一个很好用的开源库，其中实现了计算机视觉常用的...1，Dense Sift 在文章《sift特征提取算法》中提到，提取图像的sift特征分4步：构建DOG尺度空间；关键点定位；关键点方向赋值；生成描述子。 这里产生的s

...