1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
function SimpleHDRDemo(imfilename)
% SimpleHDRDemo([imfilename]) - Load and show a high dynamic range (HDR) image
% on a compatible HDR display setup.
%
% Press any key to terminate the demo.
%
% 'imfilename' - Optional filename of the HDR image to load. This will load
% a standard HDR demo image bundled with Matlab, if omitted, or abort if
% the default demo image is missing. Currently only '.hdr' RGBE images are
% supported.
%
% See "help PsychHDR" for system requirements and setup instructions for HDR
% display. Once these are satisfied, converting a standard Psychtoolbox visual
% stimulation script into a HDR script is straightforward, as shown in this simple
% demo. Modify your scripts in the following manner:
%
% 1. Use (as most minimal setup) the sequence ...
%
% PsychImaging('PrepareConfiguration');
% PsychImaging('AddTask', 'General', 'EnableHDR');
% win = PsychImaging('OpenWindow', screenid);
%
% ... instead of ...
%
% win = Screen('OpenWindow', screenid);
%
% ... to open a fullscreen onscreen window on a HDR capable display device,
% which is attached to a HDR capable graphics card.
%
% 2. Use HDRRead(imfilename) instead of imread(imfilename) to load HDR
% image files as double() precision matrices.
%
% 3. Optional: Set the optional 'floatprecision' flag of Screen('MakeTexture', ...)
% to 1 or 2 to enforce creation of floating point precision HDR textures
% of a specific precision from your image matrix.
%
% By default, 'floatprecision' will be selected as 2 for single
% precision float fp32 format, which is the maximum precision for
% processing and displaying HDR images.
%
%
% See the section 'EnableHDR' of "help PsychImaging" for more optional parameters
% to pass to PsychImaging('AddTask', 'General', 'EnableHDR'); for customizing the
% HDR display mode. See "help PsychHDR" for more helper subfunctions to customize
% HDR display further at runtime, once the fullscreen onscreen HDR display window
% has been opened and initially set up by PsychImaging('AddTask', 'General', 'EnableHDR').
%
% History:
%
% 21-Jul-2020 mk Written.
% Make sure we run on Psychtoolbox-3. Abort otherwise. Use unified key names for
% keyboard input across all supported operating systems. Use normalized color range,
% not the old 0-255 8 bit color convention:
PsychDefaultSetup(2);
% imfilename provided?
if nargin < 1 || isempty(imfilename)
% No: Try some default file from our bundled OpenEXR sample images:
imfilename = [PsychtoolboxRoot 'PsychDemos/OpenEXRImages/Desk.exr'];
end
% Does imfilename exist?
if ~exist(imfilename, 'file')
error('Specified HDR image file does not exist under path %s.', imfilename);
end
% Read HDR file, abort on error. Must be in a file format recognized by HDRRead:
[img, info] = HDRRead(imfilename);
% Show metadata:
disp(info);
% Find screen to display on: We choose the one with the highest number,
% assuming this is the HDR display:
screenid = max(Screen('Screens'));
% Set a cleanup function: If the variable 'canary' goes out of scope due to
% script termination (error or user abort), call "sca" which will close the display:
canary = onCleanup(@sca);
% Open a double-buffered fullscreen onscreen window in HDR mode on the HDR
% display, with black background color. Color values will be specified in
% units of nits, the display is done according to HDR10 standard, ie.
% Color space is BT2020, SMPTE ST-2084 PQ encoding is used to drive the
% display, output color signals have 10 bpc precision.
PsychImaging('PrepareConfiguration');
PsychImaging('AddTask', 'General', 'EnableHDR', 'Nits', 'HDR10');
% Note: This would also work, as above settings are used by default:
% PsychImaging('AddTask', 'General', 'EnableHDR');
win = PsychImaging('OpenWindow', screenid, 0);
HideCursor(win);
% Convert img from its source colorspace to the display colorspace of the
% HDR onscreen window. info.ColorGamut is the color gamut parsed from the
% image file, or a default color gamut as mandated by the image file format
% spec for the image file. win is the onscreen window handle, and the
% function will query win for the color gamut of its associated colorspace:
[~, img] = ConvertRGBSourceToRGBTargetColorSpace(info.ColorGamut, win, img);
switch info.format
case 'rgbe'
% HACK: Multiply by 179.0 as a crude approximation of Radiance
% units to nits: This is not strictly correct, but will do to get a
% nice enough picture for demo purpose. See 'help HDRRead' for the
% motivation for the 179 multiplicator for Radiance images:
% This is always RGB, no alpha channel to deal with.
img = img * 179;
case 'openexr'
% Known scaling factor for scaling pixel values into units of nits?
% Otherwise it is best to just leave it as is:
if info.sampleToNits > 0
% Only scale RGB channels, not the alpha channel.
img(:,:,1:3) = img(:,:,1:3) * info.sampleToNits;
end
otherwise
error('Unknown image format. Do not know how to convert into units of Nits.');
end
% Compute maximum and max mean luminance of the image:
[maxFALL, maxCLL] = ComputeHDRStaticMetadataType1ContentLightLevels(img);
% Tell the HDR display about maximum frame average light level and maximum
% content light level of the image:
PsychHDR('HDRMetadata', win, 0, maxFALL, maxCLL);
% Build a 32 bpc single-precision float texture from the image
% array by setting the (optional) 'floatprecision' flag to 2.
% texid = Screen('MakeTexture', win, img, [], [], 2);
%
% Or simply don't, because the 'floatprecision' flag defaults to 2
% in HDR display mode anyway if omitted, for your convenience:
texid = Screen('MakeTexture', win, img);
% Some variable rotation angle for the image, for some simplistic animation:
rotAngle = 0;
% Some framecounter for stats:
framecounter = 0;
% Initial Flip to sync us to retrace:
vbl = Screen('Flip', win);
tstart = vbl;
% Animation loop: Show a rotating HDR image, until key press:
while ~KbCheck
% Draw our HDR texture at specified rotation angle, centered in the window:
Screen('DrawTexture', win, texid, [], [], rotAngle);
% Draw some 2D filled oval, with a bounding box of [left,top,right,bottom]
% = [500 500 600 600], and a color value of [R, G, B] = [300 nits, 300 nits, 0 nits],
% ie. a yellow oval with 300 nits:
Screen('FillOval', win, [300 300 0], [500 500 600 600]);
% And some text, 30 pixels high, centered, in a 200 nits green:
Screen('TextSize', win, 30);
DrawFormattedText(win, 'If it works, it works.\nIf it doesn''t, it doesn''t.\n(Quoc Vuong, 2006)', 'center', 'center', [0 200 0]);
% Show updated HDR framebuffer at next vertical retrace:
vbl = Screen('Flip', win);
% Increase rotation angle to make it a bit more interesting:
rotAngle = rotAngle + 0.1;
% Count our frames:
framecounter = framecounter + 1;
end
% We are done. Release all textures, close all windows, shutdown:
sca;
% Print the stats:
duration = vbl - tstart;
averagefps = framecounter / duration;
fprintf('Displayed %i frames in %f seconds, for an average framerate of %f fps.\n', framecounter, duration, averagefps);
fprintf('Bye bye!\n');
|