function [t, s, e] = mset( pred, ground, varargin ); % [t, s, e] = mset(pred, ground, varargin) % % continuous context evaluation method which % fills out a Multiclass Segment Error Table (SET) % written by Jamie Ward, 2005 % % input: % pred, ground = [start_time stop_time label] % with all labels mapped contiguously onto % 0*,1,2,3,.. % % Any times which are not explicitly covered by a label (e.g. between % segments) is regarded as NULL. This is automatically assigned the label 0 % * You can specify NULL explicity by using the label 0. % If, however, you wish to use label 1 for NULL then set varargin='NULL_ONE' % % ( Bug/Feature: the evaluation covers time 0 until the last stop_time in % the ground truth.) % % varargin => % The default number of classes is taken from the ground and prediction information, however if % these inputs do not contain representatives of all classes, then you can % specify, for example: 'nClasses', number (note: includes NULL class) % % % output: % t== time based result % s== segment result % .T = Total % .ID = Insertion Deletion, etc.. % .IU % .IF % .OD % .OU % .MD % .Conf - regular confusion matrix % % e==event based result % .T = total % .I, .D, .M, .F % (e. also has event timing errors) % .Pre = preemption (overfill) % .Pro = prolongation (overfill) % .Short = shortening (underfill) % .Delay = delay (underfill) % % %%%%%%%%%%%%%%% % Uses: mset_segments.m % NLL=0; nClasses=0; if ~isempty(varargin) for n=1:length(varargin) if findstr(varargin{n},'NULL_ONE') NLL=1; end if findstr(varargin{n},'nClasses') if length(varargin)==n error('nClasses needs an argument'); end nClasses=varargin{n+1}; end end end if NLL==0 % Shift all labels so that NULL (assumed to be 0) is moved to '1' if ~isempty(pred) pred(:,3)=pred(:,3)+1; end ground(:,3)=ground(:,3)+1; NLL=1; end nClasses = max( [nClasses; max(ground(:,3))] ); % initialise the outputs t.Conf = zeros(nClasses,nClasses); t.ID=t.Conf; t.IU=t.Conf; t.IF=t.Conf; t.OD=t.Conf; t.OU=t.Conf; t.MD=t.Conf; s.Conf=t.Conf; s.ID=s.Conf; s.IU=s.Conf; s.IF=s.Conf; s.OD=s.Conf; s.OU=s.Conf; s.MD=s.Conf; %e.Conf = t.Conf; e.ID=t.Conf; e.IU=t.Conf; e.IF=t.Conf; e.OD=t.Conf; e.MD=t.Conf; e.T = zeros(nClasses,1); e.I = e.T; e.D = e.T; e.M = e.T; e.F = e.T; e.Corr=e.T; e.Short = e.T; e.Delay = e.T; e.Pre = e.T; e.Pro = e.T; % error codes from mset_segments MATCH = 0; DEL = 2^1; % 2 UNDER = 2^2; % 4 FRAG = 2^3; % 8 INS = 2^4; % 16 OVER = 2^5; % 32 MERGE = 2^6; % 64 ID = INS+DEL; %18; IU = INS+UNDER; %20; IF = INS+FRAG; %24; OD = OVER+DEL; %34; OU = OVER+UNDER; %36; MD = MERGE+DEL; % 66; %[r lab] = mset_segments( pred, ground, 'nClasses',nClasses,'NULL',NLL); [r lab] = mset_segments( pred, ground, 'NULL_ONE' ); segD = r(:,2)-r(:,1); for n=1:length(segD) % read each segment info into the appropriate table grL = lab(n,1); prL = lab(n,2); switch(r(n,3)) case ID t.ID(prL,grL) = t.ID(prL,grL) + segD(n); s.ID(prL,grL) = s.ID(prL,grL) + 1; case IU t.IU(prL,grL) = t.IU(prL,grL) + segD(n); s.IU(prL,grL) = s.IU(prL,grL) + 1; case IF t.IF(prL,grL) = t.IF(prL,grL) + segD(n); s.IF(prL,grL) = s.IF(prL,grL) + 1; case OD t.OD(prL,grL) = t.OD(prL,grL) + segD(n); s.OD(prL,grL) = s.OD(prL,grL) + 1; case OU t.OU(prL,grL) = t.OU(prL,grL) + segD(n); s.OU(prL,grL) = s.OU(prL,grL) + 1; case MD t.MD(prL,grL) = t.MD(prL,grL) + segD(n); s.MD(prL,grL) = s.MD(prL,grL) + 1; otherwise % Match %disp(strcat(num2str(r(n,3)), num2str(prL),num2str(grL))); end % Fill out regular confusion matrix t.Conf(prL,grL) = t.Conf(prL,grL) + segD(n); s.Conf(prL,grL) = s.Conf(prL,grL) + 1; end % Overall sum t.T = sum(t.Conf); s.T = sum(s.Conf); %%% Counting events % Make segment times into a single column, i.e.[start1 stop1 start2 stop2]' gndT=ground(:,1:2)'; gndT=gndT(:); gndT(:,2)=ones(length(gndT),1); gndT(2:2:end,2) = ground(:,3) ; % add the labels - mark label corresponding to stop time! if isempty(pred) predT(1,1:2) = [0 NLL]; else predT=pred(:,1:2)'; predT=predT(:); predT(:,2)=ones(length(predT),1); predT(2:2:end,2) = pred(:,3) ; % add the labels end % Ensure prediction and ground have the same length if gndT(end,1) > predT(end,1) predT = [predT; [gndT(end,1) NLL]]; elseif gndT(end,1) < predT(end,1) gndT = [gndT; [predT(end,1) NLL]]; else % Ok. end [nGnd, col] = size( gndT ); [nPred, col] = size( predT ); % Go through all the ground truth events start=0; for i = 1:nGnd; stop = gndT(i); if stop-start > 0 % Find index of all segments within this event isegs = find( start < r(:,2) & r(:,2) <= stop ); numIsegs = length(isegs); % Deleted; or fragmented - how many times? del = 0; frag = 0; for n=1:numIsegs grL = lab(isegs(n),1); switch(r(isegs(n),3)) case {ID,MD,OD} del = del + 1; case IF frag = frag + 1; otherwise % Correct.. end end % Negative timing error (Underfill)? delay = 0; shortening = 0; if del==0 for n=1:numIsegs switch(r(isegs(n),3)) case {IU,OU} if n==1 % at beginning delay = delay+1; elseif n==numIsegs % at end shortening = shortening+1; else end otherwise % No negative timing error end end end e.T(grL) = e.T(grL) + 1; if del>0 e.D(grL) = e.D(grL) + 1; elseif frag>0 e.F(grL) = e.F(grL) + 1;%frag; else e.Corr(grL) = e.Corr(grL) + 1; end if delay > 0 e.Delay(grL) = e.Delay(grL) + 1; end if shortening > 0 e.Short(grL)= e.Short(grL) + 1; end end start=stop; end % Go through all the prediction events start=0; for i = 1:nPred; stop = predT(i); if stop-start > 0 % Find index of all segments within this event isegs = find( start < r(:,2) & r(:,2) <= stop ); numIsegs = length(isegs); ins=0;merg=0; % Insertion; or merge - how many? for n=1:numIsegs prL = lab(isegs(n),2); switch(r(isegs(n),3)) case {ID,IU,IF} ins = ins + 1; case MD merg = merg + 1; otherwise % Correct. end end % Positive timing error (Overfill)? pre = 0; pro = 0; if ins==0 for n=1:numIsegs switch(r(isegs(n),3)) case {IU,OU} if n==1 % at beginning pre = pre+1; elseif n==numIsegs % at end pro = pro+1; else end otherwise % No positive timing error end end end if ins>0 e.I(prL) = e.I(prL) + 1; elseif merg>0 e.M(prL) = e.M(prL) + 1;% merg; end if pre > 0 e.Pre(prL) = e.Pre(prL) + 1; end if pro > 0 e.Pro(prL)= e.Pro(prL) + 1; end end start=stop; end