wolffd@0: function varargout = mirnovelty(orig,varargin) wolffd@0: % n = mirnovelty(m) evaluates the novelty score from a similarity matrix. wolffd@0: % [n,m] = mirnovelty(m) also return the similarity matrix. wolffd@0: % Optional argument: wolffd@0: % mirnovelty(...,'Distance',f) specifies the name of a dissimilarity wolffd@0: % distance function, from those proposed in the Statistics Toolbox wolffd@0: % (help pdist). wolffd@0: % default value: f = 'cosine' wolffd@0: % mirnovelty(...,'Similarity',f) specifies the name of a similarity wolffd@0: % measure function. This function is applied to the result of the wolffd@0: % distance function. cf. mirsimatrix wolffd@0: % default value: f = 'exponential' wolffd@0: % corresponding to f(x) = exp(-x) wolffd@0: % mirnovelty(...,'KernelSize',s) or more simply mirnovelty(...,s) wolffd@0: % specifies the length of the gaussian kernel, in samples. wolffd@0: % default value: s = 64. wolffd@0: % mirnovelty(...,'Normal',0) does not normalize the novelty curve wolffd@0: % between the values 0 and 1. wolffd@0: % wolffd@0: % Foote, J. & Cooper, M. (2003). Media Segmentation using Self-Similarity wolffd@0: % Decomposition,. In Proc. SPIE Storage and Retrieval for Multimedia wolffd@0: % Databases, Vol. 5021, pp. 167-75. wolffd@0: wolffd@0: dist.key = 'Distance'; wolffd@0: dist.type = 'String'; wolffd@0: dist.default = 'cosine'; wolffd@0: option.dist = dist; wolffd@0: wolffd@0: sm.key = {'Measure','Similarity'}; wolffd@0: sm.type = 'String'; wolffd@0: sm.default = 'exponential'; wolffd@0: option.sm = sm; wolffd@0: wolffd@0: K.key = {'KernelSize','Width'}; wolffd@0: K.type = 'Integer'; wolffd@0: K.default = 64; wolffd@0: option.K = K; wolffd@0: wolffd@0: transf.type = 'String'; wolffd@0: transf.default = 'TimeLag'; wolffd@0: transf.choice = {'Horizontal','TimeLag'}; wolffd@0: option.transf = transf; wolffd@0: wolffd@0: normal.key = 'Normal'; wolffd@0: normal.type = 'Boolean'; wolffd@0: normal.default = 1; wolffd@0: normal.when = 'After'; wolffd@0: option.normal = normal; wolffd@0: wolffd@0: specif.option = option; wolffd@0: specif.combineframes = @combineframes; wolffd@0: specif.nochunk = 1; wolffd@0: varargout = mirfunction(@mirnovelty,orig,varargin,nargout,specif,@init,@main); wolffd@0: wolffd@0: wolffd@0: function [x type] = init(x,option) wolffd@0: type = 'mirscalar'; wolffd@0: if not(isamir(x,'mirscalar') && strcmp(get(x,'Title'),'Novelty')) wolffd@0: x = mirsimatrix(x,'Distance',option.dist,'Similarity',option.sm,... wolffd@0: 'Width',option.K,option.transf); wolffd@0: end wolffd@0: if isa(x,'mirdesign') wolffd@0: x = set(x,'Overlap',ceil(option.K)); wolffd@0: end wolffd@0: wolffd@0: wolffd@0: function y = main(orig,option,postoption) wolffd@0: if iscell(orig) wolffd@0: orig = orig{1}; wolffd@0: end wolffd@0: if not(isa(orig,'mirscalar')) wolffd@0: s = get(orig,'Data'); wolffd@0: dw = get(orig,'DiagWidth'); wolffd@0: for k = 1:length(s) wolffd@0: if isnumeric(dw) wolffd@0: dwk = dw; wolffd@0: else wolffd@0: dwk = dw{k}; wolffd@0: end wolffd@0: if option.K wolffd@0: cgs = min(option.K,dwk); wolffd@0: else wolffd@0: cgs = dwk; wolffd@0: end wolffd@0: cg = checkergauss(cgs,option.transf); wolffd@0: disp('Computing convolution, please wait...') wolffd@0: for z = 1:length(s{k}) wolffd@0: sz = s{k}{z}; wolffd@0: szm = max(max(sz)); wolffd@0: for i = find(isnan(sz)) wolffd@0: sz(i) = szm; wolffd@0: end wolffd@0: cv = convolve2(sz,cg,'same'); wolffd@0: nl = size(cv,1); wolffd@0: nc = size(cv,2); wolffd@0: if nl == 0 wolffd@0: warning('WARNING IN NOVELTY: No frame decomposition. The novelty score cannot be computed.'); wolffd@0: score{k}{z} = []; wolffd@0: else wolffd@0: sco = cv(floor(size(cv,1)/2),:); wolffd@0: incr = find(diff(sco)>=0); wolffd@0: if not(isempty(incr)) wolffd@0: decr = find(diff(sco)<=0); wolffd@0: sco(1:incr(1)-1) = NaN(1,incr(1)-1); wolffd@0: if not(isempty(decr)) wolffd@0: sco(decr(end)+1:end) = NaN(1,length(sco)-decr(end)); wolffd@0: end wolffd@0: incr = find(diff(sco)>=0); wolffd@0: sco2 = sco; wolffd@0: if not(isempty(incr)) wolffd@0: sco2 = sco2(1:incr(end)+1); wolffd@0: end wolffd@0: decr = find(diff(sco)<=0); wolffd@0: if not(isempty(decr)) && decr(1)>2 wolffd@0: sco2 = sco2(decr(1)-1:end); wolffd@0: end wolffd@0: mins = min(sco2); wolffd@0: rang = find(sco>= mins); wolffd@0: if not(isempty(rang)) wolffd@0: sco(1:rang(1)-1) = NaN(1,rang(1)-1); wolffd@0: sco(rang(end)+1:end) = NaN(1,length(sco)-rang(end)); wolffd@0: end wolffd@0: end wolffd@0: score{k}{z} = sco; wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: else wolffd@0: score = get(orig,'Data'); wolffd@0: end wolffd@0: if not(isempty(postoption)) && postoption.normal wolffd@0: for k = 1:length(score) wolffd@0: for l = 1:length(score{k}) wolffd@0: sco = score{k}{l}; wolffd@0: sco = (sco-min(sco))/(max(sco)-min(sco)); wolffd@0: score{k}{l} = sco; wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: n = mirscalar(orig,'Data',score,'Title','Novelty'); wolffd@0: y = {n orig}; wolffd@0: wolffd@0: wolffd@0: function old = combineframes(old,new) wolffd@0: if not(iscell(old)) wolffd@0: old = {old}; wolffd@0: end wolffd@0: if not(iscell(new)) wolffd@0: new = {new}; wolffd@0: end wolffd@0: for var = 1:length(new) wolffd@0: ov = old{var}; wolffd@0: nv = new{var}; wolffd@0: ofp = get(ov,'FramePos'); wolffd@0: ofp = ofp{1}{1}; wolffd@0: nfp = get(nv,'FramePos'); wolffd@0: nfp = nfp{1}{1}; wolffd@0: od = get(ov,'Data'); wolffd@0: od = od{1}{1}; wolffd@0: onan = find(isnan(od)); wolffd@0: od(onan) = []; wolffd@0: ofp(:,onan) = []; wolffd@0: nd = get(nv,'Data'); wolffd@0: nd = nd{1}{1}; wolffd@0: nnan = find(isnan(nd)); wolffd@0: nd(nnan) = []; wolffd@0: nfp(:,nnan) = []; wolffd@0: [unused omatch nmatch] = intersect(ofp(1,:),nfp(1,:)); wolffd@0: if isempty(omatch) wolffd@0: ov = set(ov,'FramePos',{{[ofp nfp]}},'Data',{{[od nd]}}); wolffd@0: else wolffd@0: lm = length(omatch); wolffd@0: ov = set(ov,'FramePos',{{[ofp(:,1:omatch(1)-1) nfp]}},... wolffd@0: 'Data',{{[od(1:omatch(1)-1),... wolffd@0: (od(omatch).*(lm:-1:1) + nd(nmatch).*(1:lm))/(lm+1),... wolffd@0: nd(nmatch(end)+1:end)]}}); wolffd@0: end wolffd@0: old{var} = ov; wolffd@0: end wolffd@0: wolffd@0: wolffd@0: function y = checkergauss(N,transf) wolffd@0: hN = ceil(N/2); wolffd@0: if strcmpi(transf,'TimeLag') wolffd@0: y = zeros(hN,N); wolffd@0: for j = 1:N wolffd@0: for i = 1:hN wolffd@0: g = exp(-((i/hN)^2 + (((j-hN)/hN)^2))*4); wolffd@0: if j>hN && ji,j>N-i) wolffd@0: y(i,j) = -g; wolffd@0: else wolffd@0: y(i,j) = g; wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: end