Contents
- default arguments
- ----------------------------------- MODE 1 ------------------------------
- calibration sequence
- load calibration data if not already in memory
- process display output subtracting black-level offset
- Fit the gamma function
- save results or hit cancel to continue without saving
- ----------------------------------- MODE 2 ------------------------------
- Plot Results
- Show how the inverse gamma function transforms linear grey-level values to
- Show how these new non-linear input values compensate for the non-linear display characteristics,
- Demonstrate the difference between uncorrected and corrected images
%function gammaValue = calibDisplay(mode, gammaIn) % function gammaValue = calibDisplay(mode, gammaIn) % Display luminances, collect photometer readings, and derive gamma. % % In mode 1 (default), user is prompted to enter photometer readings for % displays of increasing luminance. Data must then be saved. % Luminances are displayed in a large figure window, which should leave % room at the bottom of the screen for the last lines of the command window. % % In mode 2 (following 1 automatically), user is prompted for an existing % calibration file if mode 1 was skipped. Values are then plotted, and fit % with a gamma function. An inverse gamma function and the resulting % linearized output are also graphed. Corrected and uncorrected demo % graylevel ramps are also displayed. % % mode 1 can be run a second time with gammaIn (default ==1) set to the % value computed in the first instance, just to test whether this gamma does % indeed produce a linear output. Be careful not to overwrite the existing % data though! % % Elliot Freeman 25.10.05 %--------------------------------------------------------------------------
default arguments
if ~exist('mode'), mode = 1; end % 1: calibration sequence; 2: plot and fit data (load calibration file first!) if ~exist('gammaIn'), gammaIn = 1; end % set this to 1 for calibration, or use it to test the linearity of a given gamma correction cIn = [0:16:240 255]'; % range of CLUT entry values cIn = (( cIn/255 ) .^ ( 1/gammaIn )) *255; % CLUT output (with gamma correction for testing whether this gives a linear output) nlevels = length(cIn); cmapLIN = repmat(linspace(0,1,256),3,1)'; % linear RGB look-up-table
----------------------------------- MODE 1 ------------------------------
calibration sequence
Type in photometer reading and hit return. Enter negative to quit.
if mode==1 figure(1); set(1, 'menubar', 'none'); scrsz = get(0,'screensize'); set(1, 'position', scrsz + [0 0 0 150]); % show figure window for calibration leaving bottom lines of command window visible imC = ones(scrsz(4),scrsz(3)); fprintf('For each gray level, enter the photometer reading at the prompt. \nEnter negative value to quit.\n'); for i=1:nlevels lum=[]; while isempty(lum) c=cIn(i); figure(1); image(imC .* cIn(i)); colormap(cmapLIN); axis off; set(gca, 'position', [0 0 1 1]); inputStr = sprintf('Greylevel = %d\t Luminance = ', c); lum = input(inputStr); if ~isnumeric(lum), lum = []; end if lum <0, close all; error('Aborted'); end; end lOut(i) = lum; % record photometer reading of display output end close(1); end
load calibration data if not already in memory
if ~exist('lOut'), uiopen('*.mat'); end
process display output subtracting black-level offset
lumout = lOut' - lOut(1); % display output in cdm-2 lummax = max(lumout); lumpc = lumout./repmat(lummax,nlevels,1); % display output as percentage of maximum luminance
Fit the gamma function
define inline function to calculate sum of square residuals of gamma-corrected data relative to desired linear output; then use leastsquares to find gamma value that minimises this residual.
in = inline('sum( ((lum .^ (1/g)) - lin ) .^2 )', 'g', 'lum', 'lin'); gammaValue = fminbnd(in,1,10,[],lumpc,cIn/255);
save results or hit cancel to continue without saving
if mode == 1 [FILENAME, PATHNAME, FILTERINDEX] = uiputfile('*.mat', 'Save calibration file as...'); calName = fullfile(PATHNAME,FILENAME); if ~isequal(FILENAME, 0) dateStr = date; note = input('Please describe your display\nE.g. \hitachi mc7515; contrast 100% brightness 50%\n', 's'); save(calName, 'lOut', 'note', 'dateStr', 'cIn', 'gammaValue'); fprintf('\nSaved as %s', calName); end end
----------------------------------- MODE 2 ------------------------------
Plot Results
Display Characteristic: Photometer reading as function of grey-level colour value (blue) Also shows goodness of fit of gamma function (red)
figure(2); p(1) = subplot(1,3,1); hold on; title('Display characteristic'); plot(cIn, lOut); % plot photometer readings plot(cIn, lOut(1) + ((cIn/255).^gammaValue) * lOut(end), 'r--'); % plot gamma fit xlabel('uncorrected input value'); ylabel('output luminance'); legend('display output', ['fit with gamma= ' num2str(gammaValue)]); set(gca,'ylim', [0 lummax]); hold off;
Show how the inverse gamma function transforms linear grey-level values to
new non-linear values. New = Old ^ (1/gammaValue) <= this equation performs the transformation
p(2) = subplot(1,3,2); plot(cIn, lOut(1) + (cIn/255) .^ (1/gammaValue) * 255); % plot corrected against uncorrected gray-level values title('Inverse gamma'); xlabel('uncorrected input value'); ylabel('corrected input value'); set(gca,'ytick', cIn(1:4:end), 'xlim', [0 255], 'ylim', [0 255]); legend('y = x\^(1/gamma)')
Show how these new non-linear input values compensate for the non-linear display characteristics,
resulting in a linear range of output luminances.
p(3) = subplot(1,3,3); cOut = lumpc.^(1/gammaValue) * lummax; plot(cIn, cOut + lOut(1)); % plot luminance as a function of corrected values disp([cIn cOut]) % output old and new values to command line title('Linearized'); xlabel('corrected input value'); ylabel('output luminance'); set(gca,'ylim', [0 lummax]); set(p,'xtick', cIn(1:4:end), 'xlim', [0 255]);
Demonstrate the difference between uncorrected and corrected images
Uncorrected
figure(3) subplot(2,1,1); imUncorr = repmat((0:255),256,1); % input consists of 256 values from 0 to 1 (black to white) image(imUncorr); axis off; % Notice that this image is dominated by blacks and dark grays colormap(cmapLIN) title('Uncorrected'); % Corrected subplot(2,1,2); imCorr = ((imUncorr/255) .^ (1/gammaValue)) * 255; % non-linear transformation of input values to produce linear output luminance image(imCorr); axis off; colormap(cmapLIN) image(imCorr); axis off; % Notice that all gray levels are now more fairly represented title('Corrected'); set([2 3], 'menubar', 'none');