File: SimpleHDRDemo.m

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (179 lines) | stat: -rw-r--r-- 7,245 bytes parent folder | download | duplicates (2)
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');