hey,大家好久不见,万圣节快到了,来一期趣味编程叭,这期进行一个文艺复兴。绘制黑人抬棺动画:

本期代码的灵感来自 Cleve Moler 的博客:
该博文讲了 Nikolaus Troje 收集的人类步态数据集的经过和原理(仅展示部分):


大体就是让一批受试者佩戴标记,在跑步机上行走,由动作捕捉系统记录 15 个关键节点的三维运动轨迹。对每个受试者的步态轨迹先用五项傅里叶级数拟合,再对所有受试者的傅里叶系数做主成分分析,提取出 5 个主成分,分别对应静态姿态、前进运动、侧向摇摆和两种弹跳模式。

原版代码有 6 个参数,这里为了简单都使用的默认值,所以黑人抬棺动画的人物动作都一模一样,大家可以自行去查看源代码:
进行修改,这里不再赘述。
完整代码
matlab
function hrtg
% WALKER Human gait. Version: March 5, 2016.
%
% References:
% http://blogs.mathworks.com/cleve/2016/04/11/the-eigenwalker-model-of-the-human-gait
% http://jov.arvojournals.org/article.aspx?articleid=2192503
% http://www.biomotionlab.ca/walking.php
% http://www.biomotionlab.ca/Text/WDP2002_Troje.pdf
% http://www.biomotionlab.ca/Text/trojeChapter07b.pdf
% 图窗及坐标区域创建
fig = figure('Units','normalized', 'Position',[.1,.1,.6,.8], 'Color',[1,1,1]);
ax = axes('Parent',fig, 'Position',[0,0,1,1], 'NextPlot','add', 'DataAspectRatio',[1,1,1], ...
'XColor','none', 'YColor','none', 'ZColor','none');
C = [500, 0; 500, 1500; 500, 3000;
-500, 0; -500, 1500; -500, 3000]; N = size(C, 1);
axis([-750,750,-750,750,0,1650] + ...
[min(C(:,1)), max(C(:,1)), min(C(:,2)), max(C(:,2)), 0, 0])
view(158,20);
% 获取骨骼数据及笑脸数据,这里 getGenderMeans 存的是男性数据与女性数据均值
V = getGenderMeans(); H = getHappyFace();
X = reshape(V(:,1), 15, 3);
L = {[5 12], [2 3 4 5 6 7 8], [9 10 11 12 13 14 15]}; % Links
% 循环绘制 6 个骨架及笑脸
bHdls = gobjects(N, 4); fHdls = gobjects(N, 1);
for i = 1:N
for k = 1:3
bHdls(i, k) = line(ax, X(L{k}, 1) + C(i, 1), X(L{k}, 2) + C(i, 2), X(L{k}, 3), ...
'color','k', 'marker','o', 'markersize',5, 'linewidth',6);
end
bHdls(1).Marker = 'none';
fHdls(i) = line(ax, [H(:,1) + X(1, 1); X(5, 1)] + C(i, 1), ...
[H(:,2) + X(1, 2); X(5, 2)] + C(i, 2), ...
[H(:,3) + X(1, 3); X(5, 3)], 'Color','k', 'LineWidth',2.5);
end
% 绘制棺材:懒,直接拿俩立方体拼一起了
bV1 = [.03 .03 0; .97 .03 0; .97 .97 0; .03 .97 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1];
bV2 = [.05 .04 0; .95 .04 0; .95 .96 0; .05 .96 0; .5 .3 1; .5 .3 1; .5 .7 1; .5 .7 1];
bF = [1 2 3 4; 5 6 7 8; 1 2 6 5; 2 3 7 6; 3 4 8 7; 4 1 5 8];
bV1 = bV1.*repmat([750, 3300, 200], [8,1]) + repmat([-375, -150, 1260], [8,1]);
bV2 = bV2.*repmat([750, 3300, 150], [8,1]) + repmat([-375, -150, 1460], [8,1]);
bP = X(6, :);
pHdl1 = patch(ax, 'Vertices',bV1, 'Faces',bF, ...
'FaceColor',[182,122,99]./255, 'EdgeColor',[108,66,48]./255, 'LineWidth',1.5);
pHdl2 = patch(ax, 'Vertices',bV2, 'Faces',bF, ...
'FaceColor',[182,122,99]./255, 'EdgeColor',[108,66,48]./255, 'LineWidth',1.5);
% 循环刷新动作
period = 151.5751;
omega = 2*pi/period;
for f = 1:1e4
t = f*period/48;
c = [1 sin(omega*t), cos(omega*t), sin(2*omega*t), cos(2*omega*t)]';
X = reshape(V*c, 15, 3);
for i = 1:N
for k = 1:3
set(bHdls(i, k),'XData',X(L{k}, 1) + C(i, 1), 'YData',X(L{k}, 2) + C(i, 2), 'ZData',X(L{k}, 3));
end
set(fHdls(i), 'XData', [H(:,1) + X(1, 1); X(5, 1)] + C(i, 1), ...
'YData', [H(:,2) + X(1, 2); X(5, 2)] + C(i, 2), ...
'ZData', [H(:,3) + X(1, 3); X(5, 3)])
end
set(pHdl1, 'Vertices',bV1 - bP + X(6, :))
set(pHdl2, 'Vertices',bV2 - bP + X(6, :))
pause(.02)
end
% warkers.mat 中的数据,觉得还得单独下载会比较麻烦于是直接放这了
function V = getGenderMeans(~, ~)
V = .1.*[5,-43,-182,0,1; 2064,14,-131,11,39; 2092,-215,-192,28,15;
1660,-72,-173,-1,3; -7,-78,-173,2,1; -1664,-79,-178,4,-3;
-2097,-246,-200,-28,-20; -2016,-36,-168,-19,-49; 536,53,127,0,15;
794,11,83,-3,47; 931,-73,-145,1,-2; 20,-63,-113,1,0;
-883,-74,-146,1,-1; -831,17,74,2,-47; -567,61,125,0,-20;
205,-11,-4,-37,27; 500,-1010,-256,37,9; -686,-606,-174,-11,17;
-59,-153,-52,-57,32; -114,-7,-4,-62,35; -177,139,44,-61,34;
-717,691,170,-12,16; 414,1174,254,36,0; -544,2214,-576,327,-259;
859,1247,170,51,264; -42,-10,-29,-115,80; 78,-10,0,-115,67;
-58,-10,33,-116,79; 832,-1240,-175,56,266; -557,-2227,586,349,-271;
13837,1,0,70,86; 7695,-189,-11,124,6; 9721,61,44,82,59;
12251,-20,22,76,85; 12058,1,0,74,85; 12320,21,-23,78,82;
9774,-65,-39,83,49; 7766,224,17,119,-23; 984,-120,548,-105,266;
4122,250,49,123,30; 7897,-12,-31,70,84; 8766,1,1,70,87;
7889,13,32,70,86; 4157,-249,-52,124,35; 985,127,-548,-116,269];
end
function HF = getHappyFace(~, ~)
HF = [80,0,0; 73.91,0,30.61; 56.57,0,56.57; 30.61,0,73.91; 0,0,80; -30.61,0,73.91; -56.57,0,56.57;
-73.91,0,30.61; -80,0,0; -73.91,0,-30.61; -56.57,0,-56.57; -30.61,0,-73.91; 0,0,-80; 30.61,0,-73.91;
56.57,0,-56.57; 73.91,0,-30.61; 80,0,0; NaN,NaN,NaN; -8,0,32; -9.22,0,38.12; -12.69,0,43.31;
-17.88,0,46.78; -24,0,48; -30.12,0,46.78; -35.31,0,43.31; -38.78,0,38.12; -40,0,32; -38.78,0,25.88;
-35.31,0,20.69; -30.12,0,17.22; -24,0,16; -17.88,0,17.22; -12.69,0,20.69; -9.22,0,25.88; -8,0,32;
NaN,NaN,NaN; 40,0,32; 38.78,0,38.12; 35.31,0,43.31; 30.12,0,46.78; 24,0,48; 17.88,0,46.78;
12.69,0,43.31; 9.22,0,38.12; 8,0,32; 9.22,0,25.88; 12.69,0,20.69; 17.88,0,17.22; 24,0,16;
30.12,0,17.22; 35.31,0,20.69; 38.78,0,25.88; 40,0,32; NaN,NaN,NaN; -48,0,-19.73; -32,0,-38.4;
-16,0,-49.6; 0,0,-53.33; 16,0,-49.6; 32,0,-38.4; 48,0,-19.73; NaN,NaN,NaN; 0,0,-80];
end
end



完
大家万圣节快乐 hiahiahia ~
完整代码网盘: