123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- function map = hdrvdp_visualize( p1, varargin )
- % HDRVDP_VISUALIZE produces color or grayscale visualization of the metric
- % predictions
- %
- % map = HDRVDP_VISUALIZE( P )
- % map = HDRVDP_VISUALIZE( P, context_image )
- % map = HDRVDP_VISUALIZE( P, context_image, target )
- % map = HDRVDP_VISUALIZE( P, context_image, target, colormap )
- % map = HDRVDP_VISUALIZE( 'pmap', P, options )
- % map = HDRVDP_VISUALIZE( 'diff', P, test, reference, options )
- %
- % Creates a colorful visualization from the HDR-VDP-2 results. Depending on
- % whether 'diff' or 'pmap' type is selected, the function visualizes a
- % different aspect of the prediction. The older syntax with the first
- % parameter 'P' is equivalent to 'pmap'.
- %
- % 'pmap' produces the probability of detection map. Such a map shows where
- % and how likely a difference will be noticed. However, It does not
- % show what this differece is.
- %
- % The required argument 'P' is the probability of detection map. P
- % must be within the range 0-1
- %
- % 'diff' shows the contrast-normalized per-pixel difference weighted by the
- % probability of detection. The resulting images do NOT show
- % probabilities. However, they better correspond to the perceived
- % differences and thus are easier to interpret.
- %
- % The required argument 'P' is the probability of detection map. P
- % must be within the range 0-1
- %
- % The two required argumants are the test and references images, the
- % same as passed to the hdrvdp.
- %
- % 'options' a cell array with { 'name', value } pairs. Refer to the examples
- % below. Available options:
- %
- % 'context_image' (default: []) - display context image on top of a
- % colour map. This is usually a 'test' image passed to the hdrvdp.
- %
- %
- % 'target' (default 'screen') - specifies desired output device and can
- % be one of:
- %
- % 'screen' - (default) - the map be shown on a color screen.
- % The map will contain good reproduction of the context
- % image 'img'.
- %
- % 'print' - the map can be printed on a gray-scale printer, so color
- % information will be lost. If this target is selected,
- % the color map will contain luma differences in addition
- % to color differences. To ensure that the context image
- % does not interfere with errors, only low-contrast and
- % high frequency content of the image will be preserved.
- %
- % 'colormap' (default 'trichromatic') parameter can be one of:
- %
- % 'trichromatic' - Errors are represented as multiple colors: blue,
- % cyan, green, yellow and red, which correspond to P equal
- % 0, 0.25, 0.5, 0.75 and 1.
- %
- % 'dichromatic' - more appropriate if observes may be color
- % deficient. The hue changes from cyan (0.0) to gray (0.5)
- % and then yellow (1.0). The look of images for
- % color-deficient observers can be tested at:
- % http://www.colblindor.com/coblis-color-blindness-simulator/
- %
- % 'monochromatic' - use only grayscale. Makes sense only with
- % target='print' or when no context image is specified
- %
- %
- % Tone-mapping is applied to the context image to reduce the dynamic range
- % so that highly saturated colors can be used also in bright image regions.
- % Tone-mapping will enhance contrast if it is lower than the available
- % contrast. This behavior is useful for images that have contrast that is
- % near detection threshold (e.g. ModelFest stimuli).
- %
- % The function returns a gamma-corrected sRGB image.
- %
- % Example:
- %
- % reference = logspace( log10(0.1), log10(1000), 512 )' * ones( 1, 512 );
- % test = reference .* (1 + (rand( 512, 512 )-0.5)*0.02);
- % res = hdrvdp( test, reference, 'luminance', 30 );
- %
- % imshow( hdrvdp_visualize( 'pmap', res.P_map, { 'context_image', test } ) )
- %
- % Legend for the color-scales can be found in the color_scales
- % directory.
- %
- % Copyright (c) 2011, Rafal Mantiuk <mantiuk@gmail.com>
- % Permission to use, copy, modify, and/or distribute this software for any
- % purpose with or without fee is hereby granted, provided that the above
- % copyright notice and this permission notice appear in all copies.
- %
- % THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- % WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- % MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- % ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- % WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- % ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- % OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- if( ischar( p1 ) ) % new syntax
- switch( p1 )
- case 'diff'
- [P, test_img, reference_img, options] = set_params( varargin, 'required', 'required', 'required', {} );
- opt = parse_options( options );
- P = norm_diff_img( test_img, reference_img ) .* P;
- case 'pmap'
- [P, options] = set_params( varargin, 'required', {} );
- opt = parse_options( options );
- otherwise
- error( 'Urecognizaed visuzalization type' );
- end
-
- else % old syntax
- P = p1;
- opt = struct();
- [opt.context_image, opt.target, opt.colormap] = set_params( varargin, [], 'screen', 'trichromatic' );
- end
- if( isempty(opt.context_image) )
- tmo_img = ones(size(P))*0.5;
- elseif( strcmp( opt.target, 'print' ) )
- l = log_luminance( opt.context_image );
- hp_img = (l - blur_gaussian( l, 2 ) + mean(l(:)));
- tmo_img = vis_tonemap(hp_img, 0.1) + 0.5;
- elseif( strcmp( opt.target, 'screen' ) )
- tmo_img = vis_tonemap( log_luminance(opt.context_image), 0.6 );
- else
- error( 'Unknown target: %s', opt.target );
- end
- P(P<0) = 0;
- P(P>1) = 1;
- if( strcmp( opt.colormap, 'trichromatic' ) || strcmp( opt.colormap, 'print' ) )
-
- color_map = [0.2 0.2 1.0;
- 0.2 1.0 1.0;
- 0.2 1.0 0.2;
- 1.0 1.0 0.2;
- 1.0 0.2 0.2];
-
- color_map_in = [0 0.25 0.5 0.75 1];
-
- elseif( strcmp( opt.colormap, 'dichromatic' ) )
-
- color_map = [0.2 1.0 1.0;
- 1.0 1.0 1.0
- 1.0 1.0 0.2];
-
- color_map_in = [0 0.5 1];
- elseif( strcmp( opt.colormap, 'monochromatic' ) )
-
- color_map = [1.0 1.0 1.0;
- 1.0 1.0 1.0];
-
- color_map_in = [0 1];
-
- else
- error( 'Unknown colormap: %s', opt.colormap );
- end
-
- if( strcmp( opt.target, 'screen' ) )
- color_map_l = color_map * [0.2126 0.7152 0.0722]'; %sum(color_map,2);
- color_map_ch = color_map ./ repmat( color_map_l, [1 3] );
- else
- if( strcmp( opt.colormap, 'monochromatic' ) )
- color_map_l = (color_map * [0.2126 0.7152 0.0722]') ./ color_map_in';
- else
- % luminance map start at 0.3, so that colors are visible
- color_map_l = (color_map * [0.2126 0.7152 0.0722]') ./ (color_map_in'*0.8+0.2);
- end
- color_map_ch = color_map ./ repmat( color_map_l, [1 3] );
- end
-
-
- %The line belows display pixel values
- %round(min( color_map_ch*255, 255 ))
-
- map = zeros( size(P,1), size(P,2), 3 );
- map(:,:,1) = interp1( color_map_in, color_map_ch(:,1), P );
- map(:,:,2) = interp1( color_map_in, color_map_ch(:,2), P );
- map(:,:,3) = interp1( color_map_in, color_map_ch(:,3), P );
- %map(:,:,3) = 1 - map(:,:,2) - map(:,:,1);
-
- %map = repmat( tmo_img, [1 1 3] );
- map = map .* repmat( tmo_img, [1 1 3] );
- end
- function l = log_luminance( X )
- if( size(X,3) == 3 )
- Y = X(:,:,1) * 0.212656 + X(:,:,2) * 0.715158 + X(:,:,3) * 0.072186;
- else
- Y = X;
- end
- Y(Y<=0) = min(Y(Y>0));
- l = log(Y);
- end
- function tmo_img = vis_tonemap( b, dr )
-
- t = 3;
-
- b_min = min(b(:));
- b_max = max(b(:));
-
- b_scale = linspace( b_min, b_max, 1024 );
- b_p = hist( b(:), b_scale );
- b_p = b_p / sum( b_p(:) );
-
- sum_b_p = sum( b_p.^(1/t) );
- dy = b_p.^(1/t) / sum_b_p;
-
- v = cumsum( dy )*dr + (1-dr)/2;
-
- tmo_img = interp1( b_scale, v, b );
- end
- function Y = blur_gaussian( X, sigma )
- ksize2 = round(sigma*3);
- gauss_1d = exp( -(-ksize2:ksize2).^2/(2*sigma^2) );
- gauss_1d = gauss_1d/sum(gauss_1d);
- Y = conv2( X, gauss_1d, 'same' );
- Y = conv2( Y, gauss_1d', 'same' );
- end
- function varargout = set_params( vals, varargin )
- for kk=1:length(varargin)
-
- if( length(vals) >= kk )
- varargout(kk) = vals(kk);
- else
- if( ischar( varargin{kk} ) && strcmp( 'required', varargin{kk} ) )
- error( 'Required parameter missing' );
- else
- varargout(kk) = varargin(kk);
- end
- end
-
- end
- end
- function I = norm_diff_img( test, reference )
- % Computer contrast-normalized difference image
- D = get_luminance(test)-get_luminance(reference);
- sigma = 5;
- window = fspecial('gaussian', round(sigma*4), sigma);
- img_mu = filter2(window, D, 'same');
- sigma_sq = max(0, filter2(window, D.^2, 'same' ) - img_mu.^2);
- v = ( sigma_sq ).^(1/2);
- I = min(D./(v+1),1);
- end
- function Y = get_luminance( img )
- % Return 2D matrix of luminance values for 3D matrix with an RGB image
- %dims = sum(nnz( size(img)>1 ));
- dims = find(size(img)>1,1,'last');
- if( dims == 3 )
- Y = img(:,:,1) * 0.212656 + img(:,:,2) * 0.715158 + img(:,:,3) * 0.072186;
- elseif( dims == 1 || dims == 2 )
- Y = img;
- else
- error( 'get_luminance: wrong matrix dimension' );
- end
- end
- function opt = parse_options( options )
- opt = struct();
- valid_opts = { 'colormap', 'trichromatic', 'target', 'screen', 'context_image', [] };
- for kk=1:2:length(options)
-
- opt_found = false;
- for ll=1:2:length(valid_opts)
- if( strcmp( options{kk}, valid_opts{ll} ) )
- opt_found = true;
- valid_opts{ll+1} = 'done';
- break;
- end
- end
- if( ~opt_found )
- error( 'Unrecognized option: %s', options{kk} );
- end
- opt.(options{kk}) = options{kk+1};
- end
- %Insert default options
- for kk=1:2:length(valid_opts)
- if( ~ischar( valid_opts{kk+1} ) || ~strcmp( valid_opts{kk+1}, 'done' ) )
- opt.(valid_opts{kk}) = valid_opts{kk+1};
- end
- end
- end
|