我正在使用MATLAB的PsychToolbox进行实验,在该实验中,我必须实时收集扫视信息,同时还要逐帧渲染视频。我遇到的问题是,给定视频和显示的帧速率(~24fps),这意味着我有大约 40 毫秒的时间窗口来呈现查询并渲染我之前存储在内存中的每一帧。这很好,但由于这个过程需要额外的时间,它通常意味着我有大约 ~20 毫秒的时间从头到尾持续轮询扫视。
这是一个问题,因为当我轮询扫视时,我通常所做的(比如静止图像,只需要显示一次),是等待注视的开始和结束,给定来自眼动追踪机的一致轮询,检测到观察者的视线突然从一个点转移到另一个点,并带有
超过速度:35度/秒
和一个
加速度超过:9500 度/秒^2
但是,如果扫视的开始或结束发生在渲染帧时(大多数情况下),那么如果不将渲染和轮询过程拆分为两个单独的 MATLAB 线程,就不可能实时获取数据。
我的代码(相关部分)如下所示:
while GetSecs-t.stimstart(sess,tc)<fixation_time(stimshownorder(tc))
x =evt.gx(1);
y =evt.gy(1);
pa = evt.pa(1);
x_vec = [x_vec; x];
y_vec = [y_vec; y];
pa_vec = [pa_vec; pa];
evta=Eyelink('NewestFloatSample');
evtype=Eyelink('GetNextDataType');
#%% Ideally this block should detect saccades
#%% It works perfect in still images but it can't do anything here
#%% since it conflicts the main for loop ahead.
if evtype==el.ENDSACC
sacdata=Eyelink('GetFloatData',evtype);
sac.startx(sess,tc,sacc)=sacdata.gstx;
sac.starty(sess,tc,sacc)=sacdata.gsty;
sac.endx(sess,tc,sacc)=sacdata.genx;
sac.endy(sess,tc,sacc)=sacdata.geny;
sac.start(sess,tc,sacc)=sacdata.sttime;
sac.end(sess,tc,sacc)=sacdata.entime;
sacc=sacc+1;
end
#%Main loop where we render each frame:
if (GetSecs-t.space(sess,tc)>lag(tc))
z = floor((GetSecs-t.space(sess,tc)-lag(tc))/(1/24))+1;
if z > frame_number
z = frame_number;
end
Screen('DrawTexture',win,stimTex{z});
Screen('Flip',win);
#DEBUG:
#disp(z);
#%disp(frame_number);
end
end
理想情况下,我想要一个 MATLAB 函数,它可以在后端的一个单独线程中独立渲染视频,同时仍然在主线程中轮询扫视。理想情况下是这样的:
#% Define New thread to render video
#% Some new function that renders video in parallel in another thread
StartParallelThread(1);
#%Play video:
Playmovie(stimTex);
#%Now start this main loop to poll for eye movements.
while GetSecs-t.stimstart(sess,tc)<fixation_time(stimshownorder(tc))
x =evt.gx(1);
y =evt.gy(1);
pa = evt.pa(1);
x_vec = [x_vec; x];
y_vec = [y_vec; y];
pa_vec = [pa_vec; pa];
evta=Eyelink('NewestFloatSample');
evtype=Eyelink('GetNextDataType');
if evtype==el.ENDSACC
sacdata=Eyelink('GetFloatData',evtype);
sac.startx(sess,tc,sacc)=sacdata.gstx;
sac.starty(sess,tc,sacc)=sacdata.gsty;
sac.endx(sess,tc,sacc)=sacdata.genx;
sac.endy(sess,tc,sacc)=sacdata.geny;
sac.start(sess,tc,sacc)=sacdata.sttime;
sac.end(sess,tc,sacc)=sacdata.entime;
sacc=sacc+1;
end
end
运行屏幕('翻转',win)命令所需的时间似乎也约为16ms。这意味着,如果在此时间间隔内发生任何扫视,我将无法检测或轮询它们。请注意,最后我有 42 毫秒(帧刷新率)减去 16 毫秒(查询和显示帧所需的时间),因此每帧总共有 ~26 毫秒的探测时间用于获取眼球运动和计算任何实时处理。
一个可能的解决方案可能是不断轮询凝视,而不是检查眼球运动是否是扫视。但是我仍然会遇到一个问题,即无法捕捉到每帧大约三分之一的内容,只是因为加载它需要时间。
你需要重新组织你的代码。完成这项工作的唯一方法是知道翻转需要多长时间,并知道提交下一个视频帧需要多长时间。然后循环轮询眼动仪,直到您有足够的时间在下一个屏幕垂直空白之前执行绘图命令。
你不能在 matlab 中进行任何形式的可靠的多线程处理