2009年1月8日星期四

Playing with Nonlinear Dimensionality Reduction

这学期有一门课程《数学建模案例分析》,讲到了两种经典的非线性降维(Nonlinear Dimensionality Reduction)方法:lleisomap。问题是别人做过的,算法实现也基本都是现成的,我只是拿来"玩一玩"。实验有很多环节,最有趣的一个环节, 是给你698张人脸的图像(64×64灰度),通过isomap降维方法将每张脸当做一个点映到二维平面上,使得横坐标恰好反映人脸左右看的程度,纵坐标反映人脸上下看的程度。

如果你也对这个实验感兴趣,就往下读吧,很简单的~

实验环境Matlab6.5

 

实验步骤

步骤一:准备数据集和工具包

下载

人脸数据集:http://waldron.stanford.edu/~isomap/face_data.mat.Z

并解压缩

 

下载

isomap算法实现:http://waldron.stanford.edu/~isomap/code/

的所有代码

 

步骤二:

准备图片标记的人脸序号集:一共有698张人脸,都画在平面上太拥挤了,所以选了30个人脸(存入posesSelect.matks向量),选取的准则是:30个人脸的姿态尽量不同,也就是希望画在平面上尽量分散。事实上,face_data.mat数据集中,poses是一个2698列的矩阵,第j列就是第j张人脸的客观姿态。

绘制客观姿态分布图:

load face_data

load posesSelect

showFacesOnR2(images,poses,ks)

步骤三:降维

Isomap算法将4096维的人脸数据images降维到2维,并绘制在平面上

load face_data

load posesSelect

D=L2_distance(images,images,1);

options.dims = [2];

[Y, R, E] = IsomapII(D, 'k', 7, options);

showFacesOnR2(images,Y.coords{1},ks);

D是一个距离矩阵,ij列值表示人脸i和人脸j的距离,这里把一个人脸图像数据当做一个向量,使用2范数定义距离。

IsomapII是高性能算法,先把Dk=7近邻打成稀疏矩阵,然后用基于斐波那契堆的Dijkstra算法计算最短路,Dijkstra算法用C实现使用并且编译成了.dll文件为了提高效率。计算结果对我们有用的是Y.coords{1},它保存了降维后的结果,是2698列的矩阵。

观察计算结果发现,以中间那个正的人脸为中心,他左边的都在向左看,而且越是靠左的转动越明显。同理,他右面的都在向右看、上面的都在向下看、下面的在向上看。与客观姿态分布基本吻合。

 

实验细节:

showFacesOnR2.m

%把头像和姿态坐标画在平面上

function showFacesOnR2(images,poses,ks);

%normalize into 1:1

poses(1,:)=poses(1,:)/range(poses(1,:));

poses(2,:)=poses(2,:)/range(poses(2,:));

%draw all points

scatter(poses(1,:),poses(2,:),12,'o','filled');

xlabel('left-right pose');

ylabel('up-down pose');

hold on

%draw selected points

scatter(poses(1,ks),poses(2,ks),24,'ro');

hold on

%draw images on selected points

scale = 0.001;

x=zeros(64,64);

for p=1:size(ks,2)

    k=ks(p);

    for i=1:64

        x(:,i)=images((i-1)*64+1:i*64,k);

    end

    xc=poses(1,k);

    yc=poses(2,k);

    imshow(xc:scale:xc+64*scale,yc:-scale:yc-64*scale,x);

    hold on

end

return

 

 

没有评论: