/usr/share/psychtoolbox-3/PsychCal/CalibrateMonSpd.m is in psychtoolbox-3-common 3.0.14.20170103+git6-g605ff5c.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | % CalibrateMonSpd
%
% Calling script for monitor calibration. Assumes
% you have CMCheckInit/MeasSpd functions that initialize
% measurement hardware and return a measured spectral
% power distribution respectively.
%
% NOTE (dhb, 8/19/12). This code is a bit dusty, as it is not
% being actively maintained. In particular, the PTB display
% control has evolved since this was last looked at carefully.
% In general, you want to calibrate through the same set of
% display calls you'll use in your experiment. Below is some
% prose written by Mario Kleiner that describes how the PTB
% currently wants you to control and restore your clut. In
% an ideal world, this routine would be updated to match. But
% more generally, if you use this code you may want to modify
% to make sure it is displaying colors the same way you will in
% your experiments. The actual work is done in CalibrateMonDrvr
% and CalibrateAmbDrvr so that is where you would look.
%
% We have two functions for this. LoadIdentityClut() for loading an
% identity clut and configuring the GPU for identity pixel passthrough,
% and RestoreCluts, which restores to the state before
% LoadIdentityClut(). I think "sca" calls that, as well as showing the
% cursor and other cleanup actions.
%
% LoadIdentityClut is also automatically called by PsychImaging etc. if
% the image processing pipeline is used for
% Bits++/Datapixx/Viewpixx,video attenuators etc.
%
% It is important to always use LoadIdentityClut() instead of self-made
% code. Many (most?) graphics cards on most operating systems have
% graphics driver bugs and hardware quirks which cause the self-made
% identity clut to actually not turn out to be an identity clut in the
% hardware. LoadIdentityClut() has heuristics to detect os/gpu combo
% and select an appropriately fudged lut to actually get an identity
% mapping. In case of new hardware with new quirks we should update
% that files detection logic to cope. Additionally there is
% SaveIdentityClut() to save a known good lut for automatic use with
% LoadIdentityClut, overriding its choice. And there is
% BitsPlusIdentityClutTest to test a Bits+ or Datapixx device
% thoroughly for problems and aid in fixing them. It is easy to get
% fooled into thinking you got it right, even when using a photometer,
% because some of the problems are subtle and not detectable without
% use of dynamic test patterns like in BitsPlusIdentityClutTest with
% Mono++ mode, or special debug functionality as in the
% DataPixx/ViewPixx devices.
%
% I use a DataPixx to test such stuff and PTB has builtin diagnostic to
% utilize that hardware to make sure that the video signal is really
% untampered.
%
% LoadIdentityClut also calls special functions in Screen that try to
% workaround or fix other hardware interference. E.g., in addition to
% cluts messing with pixel passthrough, there is also display dithering
% on any digital video output, and some new pre- and post-gamma
% corrections in latest generation hardware -- Screen can fix this for
% some cards on some operating systems, but only when used through
% LoadIdentityClut.
%
% E.g., almost all AMD cards will cause trouble on OSX when the
% PsychtoolboxKernelDriver and LoadIdentityClut etc. is not used,
% almost all NVidia cards on OSX will cause trouble unless you use some
% special NVidia kernel driver which is somewhere referenced on the
% Bits+ pages on our wiki. We have/need similar hacks on Windows, e.g.,
% PsychGPUControl() for AMD cards. On Linux either PTB's low-level
% fixes apply or they are not neccessary.
%
% So the CalibrateMonSpd etc. should be fixed to use
% LoadIdentityClut/RestoreCluts, everything else is just begging for
% trouble.
%
% 7/7/98 dhb Wrote from generic.
% dhb dacsize/driver filled in by hand, Screen fails to return it.
% 4/7/99 dhb NINEBIT -> NBITS.
% dhb Wrote version for Radius 10 bit cards.
% 4/23/99 dhb Change wavelength sampling to 380 4 101, PR-650 native.
% 9/22/99 dhb, mdr Define boxSize.
% 8/11/00 dhb Save mon in rawdata.
% 8/18/00 dhb More descriptive information saved.
% 8/20/00 dhb Automatic check for RADIUS and number of DAC bits.
% 9/10/00 pbe Added option to blank another screen while measuring.
% 2/27/02 dhb Various small fixes, including Radeon support.
% dhb Change noMeterAvail to whichMeterType.
% 11/08/06 cgb, dhb OS/X.
% 9/27/08 dhb Default primary bases is 1 now. Use RefitCalLinMod to change later if desired.
% 8/19/12 mk Ask user for choice of display output device.
global g_usebitspp;
% Unified key mapping, no unit color range by default:
PsychDefaultSetup(1);
% If the global flag for using Bits++ is empty, then it hasn't been
% initialized and we ask user what to use:
if isempty(g_usebitspp)
g_usebitspp = input('Which high-res display device? [0=None, 1=Bits++, 2=DataPixx/ViewPixx]');
switch(g_usebitspp)
case 0
fprintf('Using standard graphics card with 8 bpc framebuffer.\n');
case 1
fprintf('Using Bits++ device in Bits+ CLUT mode.\n');
case 2
fprintf('Using DataPixx/ViewPixx et al. in L48 CLUT mode.\n');
otherwise
error('Unsupported display device. Aborted.');
end
end
% Create calibration structure;
cal = [];
% Script parameters
whichScreen = max(Screen('Screens'));
whichMeterType = 1;
cal.describe.leaveRoomTime = 10;
cal.describe.nAverage = 2;
cal.describe.nMeas = 30;
cal.describe.boxSize = 400;
cal.nDevices = 3;
cal.nPrimaryBases = 1;
switch whichMeterType
case {0,1}
cal.describe.S = [380 4 101];
case 2
cal.describe.S = [380 1 401];
otherwise
cal.describe.S = [380 4 101];
end
cal.manual.use = 0;
% Enter screen
defaultScreen = whichScreen;
whichScreen = input(sprintf('Which screen to calibrate [%g]: ', defaultScreen));
if isempty(whichScreen)
whichScreen = defaultScreen;
end
cal.describe.whichScreen = whichScreen;
% Blank screen
defaultBlankOtherScreen = 0;
blankOtherScreen = input(sprintf('Do you want to blank another screen? (1 for yes, 0 for no) [%g]: ', defaultBlankOtherScreen));
if isempty(blankOtherScreen)
blankOtherScreen = defaultBlankOtherScreen;
end
if blankOtherScreen
defaultBlankScreen = 2;
whichBlankScreen = input(sprintf('Which screen to blank [%g]: ', defaultBlankScreen));
if isempty(whichBlankScreen)
whichBlankScreen = defaultBlankScreen;
end
cal.describe.whichBlankScreen = whichBlankScreen;
end
% Find out about screen
cal.describe.dacsize = ScreenDacBits(whichScreen);
nLevels = 2^cal.describe.dacsize;
% Prompt for background values. The default is a guess as to what
% produces one-half of maximum output for a typical CRT.
defBgColor = [190 190 190]'/255;
thePrompt = sprintf('Enter RGB values for background (range 0-1) as a row vector [%0.3f %0.3f %0.3f]: ',...
defBgColor(1), defBgColor(2), defBgColor(3));
while 1
cal.bgColor = input(thePrompt)';
if isempty(cal.bgColor)
cal.bgColor = defBgColor;
end
[m, n] = size(cal.bgColor);
if m ~= 3 || n ~= 1
fprintf('\nMust enter values as a row vector (in brackets). Try again.\n');
elseif (any(defBgColor > 1) || any(defBgColor < 0))
fprintf('\nValues must be in range (0-1) inclusive. Try again.\n');
else
break;
end
end
% Get distance from meter to screen.
defDistance = .80;
theDataPrompt = sprintf('Enter distance from meter to screen (in meters): [%g]: ', defDistance);
cal.describe.meterDistance = input(theDataPrompt);
if isempty(cal.describe.meterDistance)
cal.describe.meterDistance = defDistance;
end
% Fill in descriptive information
computerInfo = Screen('Computer');
hz = Screen('NominalFrameRate', cal.describe.whichScreen);
cal.describe.caltype = 'monitor';
if isfield(computerInfo, 'consoleUserName')
cal.describe.computer = sprintf('%s''s %s, %s', computerInfo.consoleUserName, computerInfo.machineName, computerInfo.system);
else
% Better than nothing:
cal.describe.computer = OSName;
end
cal.describe.monitor = input('Enter monitor name: ','s');
cal.describe.driver = sprintf('%s %s','unknown_driver','unknown_driver_version');
cal.describe.hz = hz;
cal.describe.who = input('Enter your name: ','s');
cal.describe.date = sprintf('%s %s',date,datestr(now,14));
cal.describe.program = sprintf('CalibrateMonSpd, background set to [%g,%g,%g]',...
cal.bgColor(1), cal.bgColor(2), cal.bgColor(3));
cal.describe.comment = input('Describe the calibration: ','s');
% Get name
defaultFileName = 'monitor';
thePrompt = sprintf('Enter calibration filename [%s]: ',defaultFileName);
newFileName = input(thePrompt,'s');
if isempty(newFileName)
newFileName = defaultFileName;
end
% Fitting parameters
cal.describe.gamma.fitType = 'crtPolyLinear';
cal.describe.gamma.contrastThresh = 0.001;
cal.describe.gamma.fitBreakThresh = 0.02;
% Initialize
switch whichMeterType
case 0
case 1
CMCheckInit;
case 2
CVIOpen;
otherwise
error('Invalid meter type');
end
ClockRandSeed;
% Calibrate monitor
USERPROMPT = 1;
cal = CalibrateMonDrvr(cal, USERPROMPT, whichMeterType, blankOtherScreen);
% Calibrate ambient
USERPROMPT = 0;
cal = CalibrateAmbDrvr(cal, USERPROMPT, whichMeterType, blankOtherScreen);
% Signal end
Snd('Play', sin(0:10000)); WaitSecs(.75); Snd('Play', sin(0:10000)); WaitSecs(.75); Snd('Play', sin(0:20000));
% Save the structure
fprintf(1, '\nSaving to %s.mat\n', newFileName);
SaveCalFile(cal, newFileName);
% Put up a plot of the essential data
figure(1); clf;
plot(SToWls(cal.S_device), cal.P_device);
xlabel('Wavelength (nm)', 'Fontweight', 'bold');
ylabel('Power', 'Fontweight', 'bold');
title('Phosphor spectra', 'Fontsize', 13, 'Fontname', 'helvetica', 'Fontweight', 'bold');
axis([380, 780, -Inf, Inf]);
figure(2); clf;
plot(cal.rawdata.rawGammaInput, cal.rawdata.rawGammaTable, '+');
xlabel('Input value', 'Fontweight', 'bold');
ylabel('Normalized output', 'Fontweight', 'bold');
title('Gamma functions', 'Fontsize', 13, 'Fontname', 'helvetica', 'Fontweight', 'bold');
hold on
plot(cal.gammaInput, cal.gammaTable);
hold off
figure(gcf);
drawnow;
% Reenable screen saver.
%ScreenSaver(1);
% Close down meter
switch whichMeterType
case 0
case 1
CMClose;
case 2
CVIClose;
otherwise
error('Invalid meter type');
end
|