function plotBenchmark(fileNames, export) %PLOTBENCHMARK Plots and exports video codec benchmarking results. % PLOTBENCHMARK(FILENAMES, EXPORT) parses the video codec benchmarking result % files given by the cell array of strings FILENAME. It plots the results and % optionally exports each plot to an appropriately named file. % % EXPORT parameter: % 'none' No file exports. % 'eps' Exports to eps files (default). % 'pdf' Exports to eps files and uses the command-line utility % epstopdf to obtain pdf files. % % Example: % plotBenchmark({'H264Benchmark.txt' 'LSVXBenchmark.txt'}, 'pdf') if (nargin < 1) error('Too few input arguments'); elseif (nargin < 2) export = 'eps'; end if ~iscell(fileNames) if ischar(fileNames) % one single file name as a string is ok if size(fileNames,1) > 1 % this is a char matrix, not ok error('First argument must not be a char matrix'); end % wrap in a cell array fileNames = {fileNames}; else error('First argument must be a cell array of strings'); end end if ~ischar(export) error('Second argument must be a string'); end outpath = 'BenchmarkPlots'; [status, errMsg] = mkdir(outpath); if status == 0 error(errMsg); end nCases = 0; testCases = []; % Read each test result file for fileIdx = 1:length(fileNames) if ~isstr(fileNames{fileIdx}) error('First argument must be a cell array of strings'); end fid = fopen(fileNames{fileIdx}, 'rt'); if fid == -1 error(['Unable to open ' fileNames{fileIdx}]); end version = '1.0'; if ~strcmp(fgetl(fid), ['#!benchmark' version]) fclose(fid); error(['Requires benchmark file format version ' version]); end % Parse results file into testCases struct codec = fgetl(fid); tline = fgetl(fid); while(tline ~= -1) nCases = nCases + 1; delim = strfind(tline, ','); name = tline(1:delim(1)-1); % Drop underscored suffix from name underscore = strfind(name, '_'); if ~isempty(underscore) name = name(1:underscore(1)-1); end resolution = tline(delim(1)+1:delim(2)-1); frameRate = tline(delim(2)+1:end); tline = fgetl(fid); delim = strfind(tline, ','); bitrateLabel = tline(1:delim(1)-1); bitrate = sscanf(tline(delim(1):end),',%f'); tline = fgetl(fid); delim = strfind(tline, ','); psnrLabel = tline(1:delim(1)-1); psnr = sscanf(tline(delim(1):end),',%f'); % Default data for the optional lines speedLabel = 'Default'; speed = 0; ssimLabel = 'Default'; ssim = 0; tline = fgetl(fid); delim = strfind(tline, ','); while ~isempty(delim) % More data % Check type of data if strncmp(lower(tline), 'speed', 5) % Speed data included speedLabel = tline(1:delim(1)-1); speed = sscanf(tline(delim(1):end), ',%f'); tline = fgetl(fid); elseif strncmp(lower(tline), 'encode time', 11) % Encode and decode times included % TODO: take care of the data % pop two lines from file tline = fgetl(fid); tline = fgetl(fid); elseif strncmp(tline, 'SSIM', 4) % SSIM data included ssimLabel = tline(1:delim(1)-1); ssim = sscanf(tline(delim(1):end), ',%f'); tline = fgetl(fid); end delim = strfind(tline, ','); end testCases = [testCases struct('codec', codec, 'name', name, 'resolution', ... resolution, 'frameRate', frameRate, 'bitrate', bitrate, 'psnr', psnr, ... 'speed', speed, 'bitrateLabel', bitrateLabel, 'psnrLabel', psnrLabel, ... 'speedLabel', speedLabel, ... 'ssim', ssim, 'ssimLabel', ssimLabel)]; tline = fgetl(fid); end fclose(fid); end i = 0; casesPsnr = testCases; while ~isempty(casesPsnr) i = i + 1; casesPsnr = plotOnePsnr(casesPsnr, i, export, outpath); end casesSSIM = testCases; while ~isempty(casesSSIM) i = i + 1; casesSSIM = plotOneSSIM(casesSSIM, i, export, outpath); end casesSpeed = testCases; while ~isempty(casesSpeed) if casesSpeed(1).speed == 0 casesSpeed = casesSpeed(2:end); else i = i + 1; casesSpeed = plotOneSpeed(casesSpeed, i, export, outpath); end end %%%%%%%%%%%%%%%%%% %% SUBFUNCTIONS %% %%%%%%%%%%%%%%%%%% function casesOut = plotOnePsnr(cases, num, export, outpath) % Find matching specs plotIdx = 1; for i = 2:length(cases) if strcmp(cases(1).resolution, cases(i).resolution) & ... strcmp(cases(1).frameRate, cases(i).frameRate) plotIdx = [plotIdx i]; end end % Return unplotted cases casesOut = cases(setdiff(1:length(cases), plotIdx)); cases = cases(plotIdx); % Prune similar results for i = 1:length(cases) simIndx = find(abs(cases(i).bitrate - [cases(i).bitrate(2:end) ; 0]) < 10); while ~isempty(simIndx) diffIndx = setdiff(1:length(cases(i).bitrate), simIndx); cases(i).psnr = cases(i).psnr(diffIndx); cases(i).bitrate = cases(i).bitrate(diffIndx); simIndx = find(abs(cases(i).bitrate - [cases(i).bitrate(2:end) ; 0]) < 10); end end % Prepare figure with axis labels and so on hFig = figure(num); clf; hold on; grid on; axis([0 1100 20 50]); set(gca, 'XTick', 0:200:1000); set(gca, 'YTick', 20:10:60); xlabel(cases(1).bitrateLabel); ylabel(cases(1).psnrLabel); res = cases(1).resolution; frRate = cases(1).frameRate; title([res ', ' frRate]); hLines = []; codecs = {}; sequences = {}; i = 0; while ~isempty(cases) i = i + 1; [cases, hLine, codec, sequences] = plotOneCodec(cases, 'bitrate', 'psnr', i, sequences, 1); % Stored to generate the legend hLines = [hLines ; hLine]; codecs = {codecs{:} codec}; end legend(hLines, codecs, 4); hold off; if ~strcmp(export, 'none') % Export figure to an eps file res = stripws(res); frRate = stripws(frRate); exportName = [outpath '/psnr-' res '-' frRate]; exportfig(hFig, exportName, 'Format', 'eps2', 'Color', 'cmyk'); end if strcmp(export, 'pdf') % Use the epstopdf utility to convert to pdf system(['epstopdf ' exportName '.eps']); end function casesOut = plotOneSSIM(cases, num, export, outpath) % Find matching specs plotIdx = 1; for i = 2:length(cases) if strcmp(cases(1).resolution, cases(i).resolution) & ... strcmp(cases(1).frameRate, cases(i).frameRate) plotIdx = [plotIdx i]; end end % Return unplotted cases casesOut = cases(setdiff(1:length(cases), plotIdx)); cases = cases(plotIdx); % Prune similar results for i = 1:length(cases) simIndx = find(abs(cases(i).bitrate - [cases(i).bitrate(2:end) ; 0]) < 10); while ~isempty(simIndx) diffIndx = setdiff(1:length(cases(i).bitrate), simIndx); cases(i).ssim = cases(i).ssim(diffIndx); cases(i).bitrate = cases(i).bitrate(diffIndx); simIndx = find(abs(cases(i).bitrate - [cases(i).bitrate(2:end) ; 0]) < 10); end end % Prepare figure with axis labels and so on hFig = figure(num); clf; hold on; grid on; axis([0 1100 0.5 1]); % y-limit are set to 'auto' below set(gca, 'XTick', 0:200:1000); %set(gca, 'YTick', 20:10:60); xlabel(cases(1).bitrateLabel); ylabel(cases(1).ssimLabel); res = cases(1).resolution; frRate = cases(1).frameRate; title([res ', ' frRate]); hLines = []; codecs = {}; sequences = {}; i = 0; while ~isempty(cases) i = i + 1; [cases, hLine, codec, sequences] = plotOneCodec(cases, 'bitrate', 'ssim', i, sequences, 1); % Stored to generate the legend hLines = [hLines ; hLine]; codecs = {codecs{:} codec}; end %set(gca,'YLimMode','auto') set(gca,'YLim',[0.5 1]) set(gca,'YScale','log') legend(hLines, codecs, 4); hold off; if ~strcmp(export, 'none') % Export figure to an eps file res = stripws(res); frRate = stripws(frRate); exportName = [outpath '/psnr-' res '-' frRate]; exportfig(hFig, exportName, 'Format', 'eps2', 'Color', 'cmyk'); end if strcmp(export, 'pdf') % Use the epstopdf utility to convert to pdf system(['epstopdf ' exportName '.eps']); end function casesOut = plotOneSpeed(cases, num, export, outpath) % Find matching specs plotIdx = 1; for i = 2:length(cases) if strcmp(cases(1).resolution, cases(i).resolution) & ... strcmp(cases(1).frameRate, cases(i).frameRate) & ... strcmp(cases(1).name, cases(i).name) plotIdx = [plotIdx i]; end end % Return unplotted cases casesOut = cases(setdiff(1:length(cases), plotIdx)); cases = cases(plotIdx); % Prune similar results for i = 1:length(cases) simIndx = find(abs(cases(i).psnr - [cases(i).psnr(2:end) ; 0]) < 0.25); while ~isempty(simIndx) diffIndx = setdiff(1:length(cases(i).psnr), simIndx); cases(i).psnr = cases(i).psnr(diffIndx); cases(i).speed = cases(i).speed(diffIndx); simIndx = find(abs(cases(i).psnr - [cases(i).psnr(2:end) ; 0]) < 0.25); end end hFig = figure(num); clf; hold on; %grid on; xlabel(cases(1).psnrLabel); ylabel(cases(1).speedLabel); res = cases(1).resolution; name = cases(1).name; frRate = cases(1).frameRate; title([name ', ' res ', ' frRate]); hLines = []; codecs = {}; sequences = {}; i = 0; while ~isempty(cases) i = i + 1; [cases, hLine, codec, sequences] = plotOneCodec(cases, 'psnr', 'speed', i, sequences, 0); % Stored to generate the legend hLines = [hLines ; hLine]; codecs = {codecs{:} codec}; end legend(hLines, codecs, 1); hold off; if ~strcmp(export, 'none') % Export figure to an eps file res = stripws(res); frRate = stripws(frRate); exportName = [outpath '/speed-' name '-' res '-' frRate]; exportfig(hFig, exportName, 'Format', 'eps2', 'Color', 'cmyk'); end if strcmp(export, 'pdf') % Use the epstopdf utility to convert to pdf system(['epstopdf ' exportName '.eps']); end function [casesOut, hLine, codec, sequences] = plotOneCodec(cases, xfield, yfield, num, sequences, annotatePlot) plotStr = {'gx-', 'bo-', 'r^-', 'kd-', 'cx-', 'go--', 'b^--'}; % Find matching codecs plotIdx = 1; for i = 2:length(cases) if strcmp(cases(1).codec, cases(i).codec) plotIdx = [plotIdx i]; end end % Return unplotted cases casesOut = cases(setdiff(1:length(cases), plotIdx)); cases = cases(plotIdx); for i = 1:length(cases) % Plot a single case hLine = plot(getfield(cases(i), xfield), getfield(cases(i), yfield), plotStr{num}, ... 'LineWidth', 1.1, 'MarkerSize', 6); end % hLine handle and codec are returned to construct the legend afterwards codec = cases(1).codec; if annotatePlot == 0 return; end for i = 1:length(cases) % Print the codec name as a text label % Ensure each codec is only printed once sequencePlotted = 0; for j = 1:length(sequences) if strcmp(cases(i).name, sequences{j}) sequencePlotted = 1; break; end end if sequencePlotted == 0 text(getfield(cases(i), xfield, {1}), getfield(cases(i), yfield, {1}), ... [' ' cases(i).name]); sequences = {sequences{:} cases(i).name}; end end % Strip whitespace from string function str = stripws(str) if ~isstr(str) error('String required'); end str = str(setdiff(1:length(str), find(isspace(str) == 1)));