function varargout = videoscore(varargin) % VIDEOSCORE M-file for videoscore.fig % % Skriatok VIDEOSCORE 1.0 % S Shepherd % Platt Laboratory of Cognitive Neuroethology % 2004.03.23 % % (requires videoscore_addtarg .m and .fig) % (numlock must be off for keyboard input) % % Skriatok VIDEOSCORE is a GUI gaze-track analysis program. This program % allows one of annotate short video clips with ethological notes and % target information. Three types of targets can be recorded: % TRACKERS are used to track the movement of objects in the visual field. % The point of regard should always be the first TRACKED target. % MARKERS are used to mark static environmental anchors defining the space % surrounding the gaze-tracked subject. % BOOLEANS do not have associated positions and are used to denote % environmental conditions on a frame-by-frame basis. % NOTES non-boolean ethological variables can also be noted here. % Video clips should be 30fps 240x352 .avi files of under 1 minute. % 0--------------->352 % | | % | | % V V % 240i-------------->352+240i % Core data are: % handles.vidname name of video clip and saved data .mat file % handles.start timestamp at start of clip, in [h m s s'] format % handles.end length of clip in 30 hz frames % handles.notes handles.notes{handles.frame} = 'notes on this frame' % handles.tracIDs handles(handles.frame,trac) = x+i*y postition in pixels (default NaN*i) % handles.tracs handles{trac} = 'tracname' % handles.markIDs handles(handles.frame,mark) = x+i*y postition in pixels (default NaN*i) % handles.marks handles{mark} = 'markname' % handles.boolIDs handles(handles.frame,bool) = 0 (no) or 1 (yes) % handles.bools handles{bool} = 'boolname' % REMEMBER: the y axis is flipped, w/ origin at upper left. % % Program internal data include: % handles.LOWMEM 0 to load video into memory, 1 to work from HD % handles.video video data in handles.video.cdata % handles.frame current frame % handles.vidtitle ('string' = vidname) % handles.timestamp ('string' = current timestamp (from frame, start)) % handles.currentframe ('string' = handles.frame) % handles.endframe ('string' = handles.end) % handles.addnote ('string' = handles.notes{handles.frame}) % handles.step define_targ stepsize % handles.showmode [Xhr, Prev, Next] booleans % % Low-memory mode activated by switching % handles.LOWMEM=0; to handles.LOWMEM=1; % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @videoscore_OpeningFcn, ... 'gui_OutputFcn', @videoscore_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if (nargin & isstr(varargin{1})) gui_State.gui_Callback = str2func(varargin{1}); end if (nargout) [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % just for tidiness... warning off MATLAB:mir_warning_variable_used_as_function % --- Executes just before videoscore is made visible. function videoscore_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to videoscore (see VARARGIN) %% Low Memory mode handles.LOWMEM=0; %% Choose clip to analyze, load previously saved data handles.base=hObject; handles.vidname=input('Enter name of clip: ', 's'); set(handles.vidtitle,'string',handles.vidname); if(exist([handles.vidname '.mat'])==2) load([handles.vidname '.mat']); handles.start=startime; handles.end=lastframe; handles.notes=notes; handles.tracIDs=tracIDs; handles.tracs=tracs; handles.markIDs=markIDs; handles.marks=marks; handles.boolIDs=boolIDs; handles.bools=bools; if handles.LOWMEM==1 if(exist([handles.vidname '.avi'])~=2), error('cannot find videoclip'); end else if(exist([handles.vidname '.avi'])==2) handles.video = aviread(handles.vidname); else error('cannot find videoclip'); end end handles.allsaved=1; elseif(exist([handles.vidname '.avi'])==2) handles.start=input('Enter clip start time [h m s s`]: '); if handles.LOWMEM~=1, handles.video = aviread(handles.vidname); handles.end=length(handles.video); else ans=aviinfo(handles.vidname); handles.end=ans.NumFrames; end handles.notes{handles.end,1}=[]; handles.tracIDs{1}='xhr'; handles.tracs(1:handles.end,1)=NaN*i; handles.markIDs={}; handles.marks=[]; handles.boolIDs={}; handles.bools=[]; handles.allsaved=0; else error('bad filename'); end handles.step=1; handles.showmode=[0 0 0]; handles.acTARG=[1 1]; set(handles.endframe,'string',num2str(handles.end)); set(handles.timeslider,'Min',1,'Max',handles.end); handles.output=hObject; % Choose default command line output for videoscore guidata(handles.base, handles); % Update handles structure frameUpdate(handles, 1); % --- Outputs from this function are returned to the command line. function varargout = videoscore_OutputFcn(hObject, eventdata, handles) % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get default command line output from handles structure varargout{1} = handles.output; % --- Executes during object creation, after setting all properties. function timeslider_CreateFcn(hObject, eventdata, handles) % hObject handle to timeslider (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: slider controls usually have a light gray background, change % 'usewhitebg' to 0 to use default. See ISPC and COMPUTER. usewhitebg = 1; if usewhitebg set(hObject,'BackgroundColor',[.9 .9 .9]); else set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor')); end % --- Executes on slider movement. function timeslider_Callback(hObject, eventdata, handles) % hObject handle to timeslider (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) newframe=round(get(hObject,'Value')); set(hObject,'Value',newframe); frameUpdate(handles,newframe); function goto_Callback(hObject, eventdata, handles) % hObject handle to goto (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) goto=str2double(get(hObject,'string')); if isnan(goto) errordlg('"Go To Frame" must be numeric','Bad Input','modal') elseif (goto<1 | goto>handles.end | mod(goto,1)~=0) errordlg(['"Go To Frame" must be a whole number on [1, ' num2str(handles.end) ']'],'Bad Input','modal') else frameUpdate(handles,goto); end set(hObject,'string',[]); % --- Executes on button press in go. function go_Callback(hObject, eventdata, handles) % hObject handle to go (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) goto=str2double(get(handles.goto,'string')); if isnan(goto) errordlg('"Go To Frame" must be numeric','Bad Input','modal') elseif (goto<1 | goto>handles.end | mod(goto,1)~=0) errordlg(['"Go To Frame" must be a whole number on [1, ' num2str(handles.end) ']'],'Bad Input','modal') else frameUpdate(handles,goto); end set(handles.goto,'string',[]); function keypress_Callback(hObject, eventdata, handles) switch get(gcf,'CurrentCharacter'); case '4' frameUpdate(handles,max(handles.frame-1,1)); case '6' frameUpdate(handles,min(handles.frame+1,handles.end)); case '8' frameUpdate(handles,max(handles.frame-handles.step,1)); case '2' frameUpdate(handles,min(handles.frame+handles.step,handles.end)); case '0' if(handles.acTARG(1)==3) handles.bools(handles.frame:min(handles.frame-1+handles.step),handles.acTARG(2))=0; frameUpdate(handles,min(handles.frame+handles.step,handles.end)); end case '1' if(handles.acTARG(1)==3) handles.bools(handles.frame:min(handles.frame-1+handles.step),handles.acTARG(2))=1; frameUpdate(handles,min(handles.frame+handles.step,handles.end)); end case '.' nullpoint_Callback(hObject, eventdata, handles); end % --- Executes on button press in save. function save_Callback(hObject, eventdata, handles) % hObject handle to save (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if(exist(['.\' handles.vidname '.mat'])==2) movefile([handles.vidname '.mat'],[handles.vidname '_bak.mat']); end startime=handles.start; lastframe=handles.end; notes=handles.notes; tracIDs=handles.tracIDs; tracs=handles.tracs; markIDs=handles.markIDs; marks=handles.marks; boolIDs=handles.boolIDs; bools=handles.bools; save([handles.vidname '.mat'], 'startime', 'lastframe', 'notes', 'tracIDs', 'tracs', 'markIDs', 'marks', 'boolIDs', 'bools'); handles.allsaved=1; guidata(handles.base,handles); % Update handles structure function confirmclosereq_Callback(hObject, eventdata, handles) if handles.allsaved==1 closereq elseif handles.allsaved==0 selection = questdlg('Close without saving?','Confirm Close Request','Yes','No','No'); switch selection, case 'Yes', closereq case 'No' return end end % --- Executes on button press in showXHR. function showXHR_Callback(hObject, eventdata, handles) % hObject handle to showXHR (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.showmode(1)=get(hObject,'Value'); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes on button press in showPREV. function showPREV_Callback(hObject, eventdata, handles) % hObject handle to showPREV (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.showmode(2)=get(hObject,'Value'); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes on button press in showNEXT. function showNEXT_Callback(hObject, eventdata, handles) % hObject handle to showNEXT (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.showmode(3)=get(hObject,'Value'); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes during object creation, after setting all properties. function targets_CreateFcn(hObject, eventdata, handles) % hObject handle to targets (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: listbox controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc set(hObject,'BackgroundColor','white'); else set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor')); end % --- Executes on selection change in targets. function targets_Callback(hObject, eventdata, handles) % hObject handle to targets (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) clickTARG=get(hObject,'Value'); if clickTARG<=length(handles.tracIDs) handles.acTARG=[1 clickTARG]; elseif clickTARG<=(length(handles.tracIDs)+length(handles.markIDs)) handles.acTARG=[2 clickTARG-length(handles.tracIDs)]; else handles.acTARG=[3 clickTARG-length(handles.tracIDs)-length(handles.markIDs)]; if strcmp(get(handles.base,'SelectionType'),'open')==1 if isnan(handles.bools(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2)))==1 handles.bools(handles.frame,handles.acTARG(2))=0; else handles.bools(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=~handles.bools(handles.frame,handles.acTARG(2)); end end end guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes on button press in addtarg. function addtarg_Callback(hObject, eventdata, handles) % hObject handle to addtarg (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) newtarg=videoscore_addtarg; if ~isempty(newtarg) switch newtarg{1} case 1 handles.tracs(1:handles.end,end+1)=NaN*i; handles.tracIDs{end+1}=newtarg{2}; case 2 handles.marks(1:handles.end,end+1)=NaN*i; handles.markIDs{end+1}=newtarg{2}; case 3 handles.bools(1:handles.end,end+1)=NaN*i; handles.boolIDs{end+1}=newtarg{2}; end handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); end % --- Executes on button press in deltarg. function deltarg_Callback(hObject, eventdata, handles) % hObject handle to deltarg (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) switch handles.acTARG(1) case 1 if handles.acTARG(2)==1; selection=questdlg(['Clear xhr? (Delete unavailable)'],'Clear Point-of-Regard?','Yes','No','No'); switch selection case 'Yes' handles.tracs(:,handles.acTARG(2))=NaN*i; handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); case 'No' return end else selection=questdlg(['Delete ' handles.tracIDs{handles.acTARG(2)} '?'],'Delete Tracker?','Yes','No','No'); switch selection case 'Yes' handles.tracs(:,handles.acTARG(2))=[]; handles.tracIDs(handles.acTARG(2))=[]; handles.acTARG=[1 1]; set(handles.targets,'Value',1); handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); case 'No' return end end case 2 selection=questdlg(['Delete ' handles.markIDs{handles.acTARG(2)} '?'],'Delete Marker?','Yes','No','No'); switch selection case 'Yes' handles.marks(:,handles.acTARG(2))=[]; handles.markIDs(handles.acTARG(2))=[]; handles.acTARG=[1 1]; set(handles.targets,'Value',1); handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); case 'No' return end case 3 selection=questdlg(['Delete ' handles.boolIDs{handles.acTARG(2)} '?'],'Delete Boolean?','Yes','No','No'); switch selection case 'Yes' handles.bools(:,handles.acTARG(2))=[]; handles.boolIDs(handles.acTARG(2))=[]; handles.acTARG=[1 1]; set(handles.targets,'Value',1); handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles, handles.frame); case 'No' return end end % --- Executes on mousepress over axes background. function coordpoint(hObject, eventdata, handles) % hObject handle to vidaxes % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if (handles.acTARG(1)~=3) current_point=get(handles.vidaxes,'CurrentPoint'); newcoords=current_point(2,1:2)*[1;i]; if (handles.acTARG(1)==1) handles.tracs(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=newcoords; elseif (handles.acTARG(1)==2) handles.marks(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=newcoords; end handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles,min(handles.frame+handles.step,handles.end)); end % --- Executes on button press in nullpoint. function nullpoint_Callback(hObject, eventdata, handles) % hObject handle to nullpoint (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if (handles.acTARG(1)==1) handles.tracs(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=NaN*i; end if (handles.acTARG(1)==2) handles.marks(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=NaN*i; end if (handles.acTARG(1)==3) handles.bools(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2))=NaN*i; end handles.allsaved=0; guidata(handles.base,handles); % Update handles structure frameUpdate(handles,min(handles.frame+handles.step,handles.end)); % --- Executes during object creation, after setting all properties. function addnote_CreateFcn(hObject, eventdata, handles) % hObject handle to addnote (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc set(hObject,'BackgroundColor','black'); else set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor')); end function addnote_Callback(hObject, eventdata, handles) % hObject handle to addnote (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.notes{handles.frame}=get(handles.addnote,'string'); if strcmp(handles.notes{handles.frame},'notes') handles.notes{handles.frame}=[]; end handles.allsaved=0; guidata(handles.base, handles); % Update handles structure % --- Executes on button press in setnote. function setnote_Callback(hObject, eventdata, handles) % hObject handle to setnote (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.notes{handles.frame}=get(handles.addnote,'string'); if strcmp(handles.notes{handles.frame},'notes') handles.notes{handles.frame}=[]; end handles.allsaved=0; guidata(handles.base, handles); % Update handles structure % --- Executes on button press in radio1step. function radio1step_Callback(hObject, eventdata, handles) % hObject handle to radio2step (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.step=1; set(handles.radio1step,'Value',1); set(handles.radio2step,'Value',0); set(handles.radio5step,'Value',0); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes on button press in radio2step. function radio2step_Callback(hObject, eventdata, handles) % hObject handle to radio2step (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.step=2; set(handles.radio1step,'Value',0); set(handles.radio2step,'Value',1); set(handles.radio5step,'Value',0); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Executes on button press in radio5step. function radio5step_Callback(hObject, eventdata, handles) % hObject handle to radio5step (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.step=5; set(handles.radio1step,'Value',0); set(handles.radio2step,'Value',0); set(handles.radio5step,'Value',1); guidata(handles.base, handles); % Update handles structure frameUpdate(handles, handles.frame); % --- Internal frame updater function frameUpdate(handles, newframe) % handles structure with handles and user data (see GUIDATA) % this is an internal function to update the currently viewed frame handles.frame=newframe; set(handles.currentframe,'string',num2str(handles.frame)); newtime=mod(floor((handles.start*[60*60*60;60*60;60;1]+2*(handles.frame-1))*ones(4,1)./[60*60*60;60*60;60;1]),60)'; set(handles.timestamp,'string',[num2str(newtime(1)) ':' num2str(newtime(2)) ':' num2str(newtime(3:4)*[1;1/60])]); set(handles.timeslider,'Value',handles.frame); if ~isempty(handles.notes{handles.frame}) set(handles.addnote,'string',handles.notes{handles.frame}); else set(handles.addnote,'string','notes'); end if handles.LOWMEM==1 axes(handles.vidaxes); video=aviread(handles.vidname, handles.frame); imhandle=image(video.cdata); set(imhandle,'ButtonDownFcn',{@coordpoint,handles}); else axes(handles.vidaxes); imhandle=image(handles.video(handles.frame).cdata); set(imhandle,'ButtonDownFcn',{@coordpoint,handles}); end for ind=1:length(handles.tracIDs)+length(handles.markIDs)+length(handles.boolIDs) if ind<=length(handles.tracIDs) if isnan(handles.tracs(handles.frame,ind)) targlist{ind}=['t ' handles.tracIDs{ind}]; else targlist{ind}=['* ' handles.tracIDs{ind}]; end elseif ind<=(length(handles.tracIDs)+length(handles.markIDs)) if isnan(handles.marks(handles.frame,ind-length(handles.tracIDs))) targlist{ind}=['m ' handles.markIDs{ind-length(handles.tracIDs)}]; else targlist{ind}=['x ' handles.markIDs{ind-length(handles.tracIDs)}]; end else if isnan(handles.bools(handles.frame,ind-(length(handles.tracIDs)+length(handles.markIDs)))) targlist{ind}=['b ' handles.boolIDs{ind-(length(handles.tracIDs)+length(handles.markIDs))}]; else targlist{ind}=[num2str(handles.bools(handles.frame,ind-(length(handles.tracIDs)+length(handles.markIDs)))) ' ' handles.boolIDs{ind-(length(handles.tracIDs)+length(handles.markIDs))}]; end end end set(handles.targets,'string',targlist); if handles.showmode(1)==1 axes(handles.vidaxes); hold on; xht=plot(handles.tracs(max(1,handles.frame-handles.step*handles.showmode(2)):min(handles.frame-1+handles.step+handles.step*handles.showmode(3),handles.end),1),':y'); %xhair trace if (handles.showmode(2)==1) xhp=plot(handles.tracs(max(1,handles.frame-handles.step),1),'g.'); set([xhp],'ButtonDownFcn',{@coordpoint,handles}); end %xhair prevmost xhc=plot(handles.tracs(handles.frame:min(handles.frame-1+handles.step,handles.end),1),'gx'); %xhair current if (handles.showmode(3)==1) xhn=plot(handles.tracs(min(handles.frame-1+2*handles.step,handles.end),1),'go'); set([xhn],'ButtonDownFcn',{@coordpoint,handles}); end %xhair nextmost set([xht xhc],'ButtonDownFcn',{@coordpoint,handles}); end if handles.acTARG(1)==1 axes(handles.vidaxes); hold on; tgt=plot(handles.tracs(max(1,handles.frame-handles.step*handles.showmode(2)):min(handles.frame-1+handles.step+handles.step*handles.showmode(3),handles.end),handles.acTARG(2)),':r'); %tracker trace if (handles.showmode(2)==1) tgp=plot(handles.tracs(max(1,handles.frame-handles.step),handles.acTARG(2)),'b.'); set([tgp],'ButtonDownFcn',{@coordpoint,handles}); end %tracker prevmost tgc=plot(handles.tracs(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2)),'b*'); %tracker current if (handles.showmode(3)==1) tgn=plot(handles.tracs(min(handles.frame-1+2*handles.step,handles.end),handles.acTARG(2)),'bo'); set([tgn],'ButtonDownFcn',{@coordpoint,handles}); end %tracker nextmost set([tgt tgc],'ButtonDownFcn',{@coordpoint,handles}); elseif handles.acTARG(1)==2 axes(handles.vidaxes); hold on; tgt=plot(handles.marks(max(1,handles.frame-handles.step*handles.showmode(2)):min(handles.frame-1+handles.step+handles.step*handles.showmode(3),handles.end),handles.acTARG(2)),':m'); %marker trace if (handles.showmode(2)==1) tgp=plot(handles.marks(max(1,handles.frame-handles.step),handles.acTARG(2)),'c.'); set([tgp],'ButtonDownFcn',{@coordpoint,handles}); end %marker prevmost tgc=plot(handles.marks(handles.frame:min(handles.frame-1+handles.step,handles.end),handles.acTARG(2)),'c+'); %marker current if (handles.showmode(3)==1) tgn=plot(handles.marks(min(handles.frame-1+2*handles.step,handles.end),handles.acTARG(2)),'co'); set([tgn],'ButtonDownFcn',{@coordpoint,handles}); end %marker nextmost set([tgt tgc],'ButtonDownFcn',{@coordpoint,handles}); end hold off; guidata(handles.base,handles); % Update handles structure