function VignettingCorrectionDemo(docolor, precision) % Demonstrate how to do display devignetting aka per-pixel gain correction. % % Usage: VignettingCorrectionDemo([docolor=0][, precision=max]); % % 'docolor' if set to non-zero will compute and apply per-color channel % gains instead of the default luminance gain. % % 'precision' selects the precision vs. speed tradeoff: 2 = max precision, % min speed, 1 = balanced, 0 = max speed and minimum precision. % % Because gain correction is memory and compute intense, per-color % correction is slower than global luminance only correction. Higher % precisions for the definition of the gainmatrix are slower, and higher % display resolutions are slower. % % The demo runs until a key is hit twice. % % On modern graphics cards, Psychtoolbox allows to automatically apply a % luminance- or color gainfield to all presented stimuli. Each pixel % location can get individually gain corrected. This is useful to correct % for spatial luminance or color inhomogenities of display devices, e.g., % video projectors (due to lens vignetting effects), or flat panels (with % their contrast and color view dependency). % % You need recent graphics hardware for this to work and to work at a % decent speed. % % See "help PsychImaging" under subsection 'ColorCorrection' and "help % PsychColorCorrection" under subsection 'GainMatrix' for explanation of % the math, the parameters and other notable things of interest about gain % correction. % % History: % 6.3.2010 mk Written. % % Assign parameters or defaults: if nargin < 1 || isempty(docolor) docolor = 0; end if nargin < 2 precision = []; end % Check for properly installed Psychtoolbox: AssertOpenGL; % Output to max screen: screenid = max(Screen('Screens')); % Use imaging pipeline for visual processing and display: PsychImaging('PrepareConfiguration'); % Request per-pixel 2D gain correction for display: PsychImaging('AddTask', 'FinalFormatting', 'DisplayColorCorrection', 'GainMatrix'); % Open window with gray background (128 aka 50% gray), return handle 'win': win = PsychImaging('OpenWindow', screenid, 128); try Screen('TextSize', win, 48); % Build a simple luminance gain matrix, the size of the window, with a % simple linear gradient of increasing gain values from left to right, here % in the gain range from 0.0 to 1.5: [width, height] = Screen('WindowSize', win); % Test support for display gain correction: % Try to read from default configuration file: filename = [PsychtoolboxConfigDir('ShadingCalibration') 'VignetCalibration' sprintf('_%i_%i_%i', screenid, width, height) '.mat']; if exist(filename, 'file') load(filename, 'gainMatrix'); else % gainmatrix is a linear "gain gradient" from 0.0 at the left border to % 1.5 at the right border of the display: gainMatrix = (meshgrid(1:width, 1:height) / width) * 1.5; end % If per-colorchannel correction is requested... if docolor % Replicate linear gains into all three color gain channels... gainMatrix = repmat(gainMatrix, [1 1 3]); % ... and invert the gradient in the green channel to make it % visually more interesting: gainMatrix(:,:,2) = (1.5 - 1.5 * meshgrid(1:width, 1:height) / width); end % Apply gain correction matrix to display: This will take effect at the % next Screen('Flip'). We pass in a 'precision' flag as well, to choose % the tradeoff between accuracy and speed: PsychColorCorrection('SetGainMatrix', win, gainMatrix, [], precision); KbReleaseWait; fc = 0; tstart = GetSecs; % Repeat redraw loop until keypress. while ~KbCheck fc = fc + 1; cl = mod(fc, 170); % Draw a yellow oval to the screen which changes brightness periodically: Screen('FillOval', win, [cl cl 0]); % Text drawing is time consuming, btw... DrawFormattedText(win, 'Hit any key twice to finish!', 'center', 'center', [0 0 128]); % Show updated image at next refresh cycle: Screen('Flip', win); end % Some stats... fprintf('\n\nAvg redraw rate was %f Hz.\n\n', fc / (GetSecs - tstart)); % Wait for keyboard stroke before closing down... KbStrokeWait; % Done. Close everything down and terminate: sca; catch % Usual error handling... sca; psychrethrow(psychlasterror); end return;