diff --git a/Test/Interactive/rtbCompareManyRenderings.m b/Test/Interactive/rtbCompareManyRenderings.m new file mode 100644 index 0000000000000000000000000000000000000000..205202249aff76603eb47afcde5d843e99fe4025 --- /dev/null +++ b/Test/Interactive/rtbCompareManyRenderings.m @@ -0,0 +1,111 @@ +function [comparisons, matchInfo] = rtbCompareManyRenderings(folderA, folderB, varargin) +%% Compare paris of renderings across two folders. +% +% comparisons = rtbCompareManyRenderings(folderA, folderB) finds rendering +% data files in the given folderA and folderB and attempts to match up +% pairs of renderings that came from the same recipe and renderer. +% For each pair, computes difference images and statistics. +% +% Returns a struct array of image comparisons, as returned from +% rtbCompareRenderings(). +% +% rtbCompareManyRenderings( ... 'fetchReferenceData', fetchReferenceData) +% specify whether to use Remote Data Toolbox to fetch reference data for +% comparison. The default is true, fetch reference data when there is a +% recipe in folderA that was not found in folderB, and cache the fetched +% data in folderB. +% +%%% RenderToolbox4 Copyright (c) 2012-2017 The RenderToolbox Team. +%%% About Us://github.com/RenderToolbox/RenderToolbox4/wiki/About-Us +%%% RenderToolbox4 is released under the MIT License. See LICENSE file. + +parser = inputParser(); +parser.KeepUnmatched = true; +parser.addRequired('folderA', @ischar); +parser.addRequired('folderB', @ischar); +parser.addParameter('fetchReferenceData', true, @islogical); +parser.parse(folderA, folderB, varargin{:}); +folderA = parser.Results.folderA; +folderB = parser.Results.folderB; +fetchReferenceData = parser.Results.fetchReferenceData; + + +%% Identify renderings and recipes to compare. +renderingsA = rtbFindRenderings(folderA, varargin{:}); +recipeNames = unique({renderingsA.recipeName}); +nRecipes = numel(recipeNames); + +renderingsB = rtbFindRenderings(folderB, varargin{:}); + +%% Compare one recipe at a time, fetch data as necessary. +comparisonsCell = cell(1, nRecipes); +matchInfoCell = cell(1, nRecipes); +for rr = 1:nRecipes + recipeName = recipeNames{rr}; + fprintf('Comparing renderings for recipe <%s>.\n', recipeName); + + isRecipeA = strcmp({renderingsA.recipeName}, recipeName); + recipeRenderingsA = renderingsA(isRecipeA); + + % fetch missing recipe for B? + isRecipeB = strcmp({renderingsB.recipeName}, recipeName); + if any(isRecipeB) + recipeRenderingsB = renderingsB(isRecipeB); + elseif fetchReferenceData + recipeRenderingsB = rtbFetchReferenceData(recipeName, varargin{:}); + if isempty(recipeRenderingsB) + fprintf(' Could not fetch reference data for set B, skipping this recipe.\n'); + continue; + end + else + fprintf(' Could not find local data for set B. Skipping this recipe.\n'); + continue; + end + + % match pairs of renderings for recipes A and B + info = matchRenderingPairs(recipeRenderingsA, recipeRenderingsB); + fprintf(' Found %d matched pairs of renderings.\n', info.nPairs); + + % run a comparison for each matched pair + pairsCell = cell(1, info.nPairs); + for pp = 1:info.nPairs + fprintf(' %s.\n', info.matchedA(pp).identifier); + pairsCell{pp} = rtbCompareRenderings(info.matchedA(pp), info.matchedB(pp), varargin{:}); + end + comparisonsCell{rr} = [pairsCell{:}]; + matchInfoCell{rr} = info; + + % report on unmatched renderings + if ~isempty(info.unmatchedA) + nUnmatched = info.unmatchedA; + fprintf(' %d renderings in A were not matched in B:\n', nUnmatched); + for uu = 1:nUnmatched + fprintf(' %s\n', info.info.unmatchedA(uu).identifier); + end + end + + if ~isempty(info.unmatchedB) + nUnmatched = info.unmatchedB; + fprintf(' %d renderings in B were not matched in A:\n', nUnmatched); + for uu = 1:nUnmatched + fprintf(' %s\n', info.info.unmatchedB(uu).identifier); + end + end +end +comparisons = [comparisonsCell{:}]; +matchInfo = [matchInfoCell{:}]; + + +%% For pairs of comparable renderings from two sets. +function info = matchRenderingPairs(renderingsA, renderingsB) +identifiersA = {renderingsA.identifier}; +identifiersB = {renderingsB.identifier}; +[~, indexA, indexB] = intersect(identifiersA, identifiersB, 'stable'); +[~, unmatchedIndexA] = setdiff(identifiersA, identifiersB); +[~, unmatchedIndexB] = setdiff(identifiersB, identifiersA); + +info.nPairs = numel(indexA); +info.matchedA = renderingsA(indexA); +info.matchedB = renderingsB(indexB); +info.unmatchedA = renderingsA(unmatchedIndexA); +info.unmatchedB = renderingsB(unmatchedIndexB); diff --git a/Test/Interactive/rtbCompareRenderings.m b/Test/Interactive/rtbCompareRenderings.m index d9e7a283aab643b6151eba4cb74ef292b1311245..471a7fb162968b50f436c3c8ab1f6970ca81ebe9 100644 --- a/Test/Interactive/rtbCompareRenderings.m +++ b/Test/Interactive/rtbCompareRenderings.m @@ -28,6 +28,7 @@ function comparison = rtbCompareRenderings(renderingA, renderingB, varargin) %%% RenderToolbox4 is released under the MIT License. See LICENSE file. parser = inputParser(); +parser.KeepUnmatched = true; parser.addRequired('renderingA', @isstruct); parser.addRequired('renderingB', @isstruct); parser.addParameter('denominatorThreshold', 0.2, @isnumeric); diff --git a/Test/Interactive/rtbFetchReferenceData.m b/Test/Interactive/rtbFetchReferenceData.m index 8b400f66c862002c233f8a601277efbe7a9f58aa..adca9695739b4a1568e18a11029764114c8b1172 100644 --- a/Test/Interactive/rtbFetchReferenceData.m +++ b/Test/Interactive/rtbFetchReferenceData.m @@ -30,6 +30,7 @@ function [renderings, referenceRoot, artifact] = rtbFetchReferenceData(recipeNam %%% RenderToolbox4 is released under the MIT License. See LICENSE file. parser = inputParser(); +parser.KeepUnmatched = true; parser.addRequired('recipeName', @ischar); parser.addParameter('rdtConfig', 'render-toolbox'); parser.addParameter('remotePath', 'reference-data', @ischar); @@ -42,12 +43,17 @@ remotePath = parser.Results.remotePath; referenceVersion = parser.Results.referenceVersion; referenceRoot = parser.Results.referenceRoot; - %% Get a whole recipe from the server. artifactPath = fullfile(remotePath, recipeName); -[fileName, artifact] = rdtReadArtifact(rdtConfig, artifactPath, recipeName, ... - 'version', referenceVersion, ... - 'type', 'zip'); +try + [fileName, artifact] = rdtReadArtifact(rdtConfig, artifactPath, recipeName, ... + 'version', referenceVersion, ... + 'type', 'zip'); +catch err + renderings = []; + artifact = []; + return; +end if isempty(fileName) renderings = []; @@ -58,6 +64,9 @@ end %% Explode renderings it into the destination folder. destination = fullfile(referenceRoot, recipeName); +if 7 ~= exist(destination, 'dir') + mkdir(destination); +end unzip(fileName, destination); % scan for rendering records diff --git a/Test/Interactive/rtbFindRenderings.m b/Test/Interactive/rtbFindRenderings.m index cdde19cb50fced1a4ba722f4c9b6fd6ca2b2adaa..d6b7b2285111b338df45ead07be55d9e3fbaed77 100644 --- a/Test/Interactive/rtbFindRenderings.m +++ b/Test/Interactive/rtbFindRenderings.m @@ -32,6 +32,7 @@ function renderings = rtbFindRenderings(rootFolder, varargin) %%% RenderToolbox4 is released under the MIT License. See LICENSE file. parser = inputParser(); +parser.KeepUnmatched = true; parser.addRequired('rootFolder', @ischar); parser.addParameter('filter', '\.mat$', @ischar); parser.addParameter('renderingsFolderName', 'renderings', @ischar); diff --git a/Test/Interactive/rtbPlotRenderingComparison.m b/Test/Interactive/rtbPlotRenderingComparison.m index 60a89741bc038b7f56b1660f3b661ac8f2983682..b5526fae0c212a393a8980d9059ae6ab20ab3e2a 100644 --- a/Test/Interactive/rtbPlotRenderingComparison.m +++ b/Test/Interactive/rtbPlotRenderingComparison.m @@ -10,6 +10,7 @@ function fig = rtbPlotRenderingComparison(comparison, varargin) %%% RenderToolbox4 is released under the MIT License. See LICENSE file. parser = inputParser(); +parser.KeepUnmatched = true; parser.addRequired('comparison', @isstruct); parser.addParameter('isScale', true, @islogical); parser.addParameter('toneMapFactor', 0, @isnumeric); @@ -34,7 +35,10 @@ rgbBminusA = rtbMultispectralToSRGB(comparison.bMinusA, S, ... %% Make the plot. -name = sprintf('RGB isScale %d toneMapFactor %.2f', isScale, toneMapFactor); +name = sprintf('%s isScale %d toneMapFactor %.2f', ... + comparison.renderingA.identifier, ... + isScale, ... + toneMapFactor); set(fig, 'Name', name, ... 'NumberTitle', 'off');