我正在尝试提高在MATLAB图形中绘制和更新动画的速率。我希望通过使用gpuarray
或parfor
循环,可以更新图形上的许多变量,但是显然不是这样,图形的句柄在被这些函数解析后会失去连接。是否存在另一种改善和加速动画的方法。我将附加我的代码并简要说明。我还将附上2个GIF,以显示我要做什么。
这是代码。我将动画作为对象编写,因为我将插入各种程序。我定义了类,使用第一个函数构建对象,然后使用第二个函数运行刺激。为了降低速度,我将所有转换和XY数据复制到单独的容器中,以便可以对位置数据执行cellfun
或其他计算强度大的计算,然后覆盖对象的位置数据。
classdef StimBud<handle
properties
Window % holds figure
ObjectList % holds object handles
ObjectTransformation % holds object transformation
ObjectLocX
ObjectLocY
ObjectRotation
end
methods
function gh = StimBud()
end
function buildobjects(gh,numofObj)
gh.Window = figure('MenuBar','none', ... % Build Window for stimulus
'Color',[0,0,0]);
for aa = 1:numofObj
gh.ObjectTransformation{aa} = hgtransform; % Add object to end of transformation list
gh.ObjectList{aa} = patch(... % Add object to end of Object list, bind to transformation list
'Parent', gh.ObjectTransformation{aa}, ...
'XData',[0,0,1,1], 'YData',[0,1,1,0],...
'Facecolor', [1,1,0], 'EdgeColor', [1,1,0], ...
'visible','on');
end
% define transforamtion and position variables
parse = 360/numofObj;
rotationcalculation = 0;
XData = repmat(10,1,numofObj);
YData = zeros(1,numofObj);
TmpXdata = cell(numofObj,1); % container to hold all X location data
TmpRot = zeros(numofObj,1); % container to hold the Rotation data
TmpYdata = cell(numofObj,1); % container to hold all Y location data
% Adjust position & rotation of all available objects
for aa = 1:numofObj
% Rotate objects to change direction of movement
gh.ObjectTransformation{aa}.Matrix = makehgtform('zrotate',(deg2rad(aa*parse)+rotationcalculation));
% move object to proper position
gh.ObjectList{aa}.XData = gh.ObjectList{aa}.XData + XData(aa);
gh.ObjectList{aa}.YData = gh.ObjectList{aa}.YData + YData(aa);
TmpXdata{aa} = gh.ObjectList{aa}.XData;
TmpYdata{aa} = gh.ObjectList{aa}.YData;
TmpRot(aa) = (deg2rad(aa*parse)+rotationcalculation);
end
% store variable out of objects for threading
gh.ObjectLocX = TmpXdata;
gh.ObjectLocY = TmpYdata;
gh.ObjectRotation = TmpRot;
end
function RunStim(gh)
figure(gh.Window);
TrialLength = 10; % Length of trial to be run
Framerate = 60;
ObjSpeed = 10;
% pull variables into function
ObjList = gh.ObjectList;
ObjLocX = gh.ObjectLocX;
ObjLocY = gh.ObjectLocY;
ObjRotation = gh.ObjectRotation;
NumofObj = length(ObjList); % Number of Objects in stim system
timer = tic(); % Timer for the stimulus
moveforward = .03*.1*ObjSpeed; % Distance to move in figure
while toc(timer) < TrialLength % Run stimulus through length of project
NextStepX = cellfun(@(x) x+moveforward,ObjLocX);
NextStepY = cellfun(@(x) x+moveforward,ObjLocY);
NextRot = ObjRotation + moveforward;
for aa = 1:NumofObj %% parfor does not work here %%
ObjList{aa}.XData = NextStepX{aa};
end
ObjLocX = NextStepX; % Update X location matrix for next step
ObjLocY = NextStepY; % Update Y location matrix for next step
ObjRotation = NextRot; % Update Rotation matrix for next step
pause(1/Framerate) % Pause window briefly to allow for drawing
end
end
end
end
要创建动画:
s = StimBud;
s.buildobjects(5)
s.RunStim
此GIF显示了我使用上面的代码构建的动画,该代码有5个对象。即使我使用for循环,它也可以快速显示和设置动画。
这是当我增加对象数量时发生的事情(由于for循环而显而易见)。动画的速度大大降低,不像平滑的运动那样快,并且移动的距离与具有较少对象的动画的移动距离不同。
我希望使用多线程来纠正此问题,但这似乎不是一个可行的选择(至少从我所学到的)。如何在MATLAB图形中改善动画效果?我是在错误地考虑这个问题,根本不应该使用figure
吗?
答案 0 :(得分:3)
您的方法的主要问题是您的代码忽略了更新工程图需要时间的事实。因此,您设置的帧速率不是实际的帧速率,我将使用profiler进行解释:
我们在这里看到标记的线,它既负责绘图又负责等待,花了8.57
秒而不是350*1/60 = 5.83
秒,增加了近50% !好的,可能暗示我们想要的帧率可能太高。我们可以尝试对较小的帧率进行硬编码-但这只会推迟问题,并不能真正解决问题。
这就是为什么我认为最好的方法是自适应帧速率,它会根据当前的工作量增加或减少。这是一个粗略的实现,以显示我的意思:
% same as yours until line 72 including
tmp = [ObjList{:}];
skipNext = 0;
while true % Run stimulus through length of project
t1 = toc(timer);
if t1 >= TrialLength, break; end
NextStepX = cellfun(@(x) x+moveforward, ObjLocX, 'UniformOutput', false);
NextStepY = cellfun(@(x) x+moveforward, ObjLocY, 'UniformOutput', false);
NextRot = ObjRotation + moveforward;
if ~skipNext
[tmp.XData] = NextStepX{:};
end
ObjLocX = NextStepX; % Update X location matrix for next step
ObjLocY = NextStepY; % Update Y location matrix for next step
ObjRotation = NextRot; % Update Rotation matrix for next step
t2 = toc(timer);
if t2-t1 < max(1,skipNext)/Framerate
% if we have some time left, update the plot
drawnow;
skipNext = 0;
% if we still have time left, increase the framerate and wait
t = 1/Framerate - (toc(timer) - t1);
if t > 0
Framerate = Framerate * 1.1;
java.lang.Thread.sleep( 1E3 * t );
end
else
skipNext = skipNext + 1;
Framerate = Framerate * 0.75;
disp("Frame skipped!");
end
disp("Framerate is now: " + Framerate);
end
这还包括一些日志记录,以显示帧率发生了什么。在我的系统上,对于n=10
,帧速率最终为227.85
,对于n=50
,帧速率最终为72.6
,对于n=1000
,帧速率最终为18.98
,依此类推。在最后一种情况下动画不流畅,至少看起来没有卡住。
展望未来,我认为您应该尝试用其他实体替换补丁,也许是使用一些大的正方形标记(可能会模仿正方形补丁,但速度更快)的line
或scatter
图)。如果这些都不适合您的使用,我只想说这是MATLAB的局限性,尽管我不是这些方面的专家,但您可能想研究一些专用的图形库,因此很遗憾,我不能提出一个建议。 / p>
请注意,我如何进行坐标更新,而不是您的for
循环:
[tmp.XData] = NextStepX{:};