1818 case ' detection'
1919 whichCalFile = ' ViewSonicG220fb_670.mat' ;
2020 whichCalNumber = 4 ;
21- nDeviceBits = 12 ;
21+ nDeviceBits = 18 ;
2222 whichCones = ' asano' ;
2323 NOAMBIENT = true ;
2424 case ' detectionRaw'
4141CalibrateFitGamma(calObjCones , nDeviceLevels );
4242nPrimaries = calObjCones .get(' nDevices' );
4343
44- % Can change gammaMethod to 1 for unquantized analysis
45- gammaMethod = 2 ;
46- SetGammaMethod(calObjCones ,gammaMethod );
47- SetGammaMethod(calObjCones1 ,gammaMethod );
44+ % Set gamma mode. A value of 2 was used in the experiment
45+ % gammaMode == 0 - search table using linear interpolation via interp1.
46+ % gammaMode == 1 - inverse table lookup. Fast but less accurate.
47+ % gammaMode == 2 - exhaustive search
48+ gammaMode = 2 ;
49+ SetGammaMethod(calObjCones ,gammaMode );
50+ SetGammaMethod(calObjCones1 ,gammaMode );
4851
4952% Set wavelength support.
5053Scolor = calObjCones .get(' S' );
5154
52- % Zero out ambient?
55+ % Zero out ambient? We don't zero out the 1 version of the cal object.
5356if (NOAMBIENT )
5457 calObjCones .set(' P_ambient' ,zeros(size(calObjCones .get(' P_ambient' ))));
5558end
8285
8386% Get gamma correct
8487CalibrateFitGamma(calObjXYZ , nDeviceLevels );
85- SetGammaMethod(calObjXYZ ,gammaMethod );
86- SetGammaMethod(calObjXYZ1 ,gammaMethod );
88+ SetGammaMethod(calObjXYZ ,gammaMode );
89+ SetGammaMethod(calObjXYZ1 ,gammaMode );
8790if (NOAMBIENT )
8891 calObjXYZ .set(' P_ambient' ,zeros(size(calObjCones .get(' P_ambient' ))));
8992end
9699% found it by stepping through the tracking code, and 0.9608 as we found
97100% it by looking at S.stmLE in the detection code saved data. We divide
98101% our maximum gamut contrasts by this to get the real maximum contrast we
99- % report. Not sure why there is a difference.
102+ % report. The difference is that the 0.9221 is the contrast number, while
103+ % the stimulus value represents excitations. We care about contrast for
104+ % this purpose.
100105imageScaleFactor = 0.9221 ; % 0.9221; 0.9608;
101106
102- % XYZ
107+ %% XYZ
103108USE1931XYZ = true ;
104109if (USE1931XYZ )
105110 load T_xyz1931.mat
113118
114119%% Compute ambient
115120ambientCones = SettingsToSensor(calObjCones ,[0 0 0 ]' );
121+ ambientCones1 = SettingsToSensor(calObjCones1 ,[0 0 0 ]' );
116122ambientXYZ = SettingsToSensor(calObjXYZ ,[0 0 0 ' ]' );
123+ ambientXYZ1 = SettingsToSensor(calObjXYZ1 ,[0 0 0 ' ]' );
117124
118125%% Compute the background, taking quantization into account
119126%
120127% The paper says the background was 30.75 cd/m2, x = 0.326, y = 0.372;
128+ % But, it was alayws set via backround linear rgb = [0.5 0.5 0.5]. THe
129+ % xyY values correspond to specified value.
130+ %
131+ % The calculations here account for display quantization.
121132SPECIFIEDBG = false ;
122133if (SPECIFIEDBG )
123134 bgxyYTarget = [0.326 , 0.372 30.75 ]' ;
141152fprintf(' \n NOAMBIENT = %d , cone option %s\n ' ,NOAMBIENT ,whichCones );
142153fprintf(' \n Background x,y = %0.4f , %0.4f\n ' ,bgxyY(1 ),bgxyY(2 ));
143154fprintf(' Background Y = %0.2f cd/m2, ambient %0.3f cd/m2\n ' ,bgXYZ(2 ),ambientXYZ(2 ));
155+ fprintf(' \n Background with ambient x,y = %0.4f , %0.4f\n ' ,bgxyY1(1 ),bgxyY1(2 ));
156+ fprintf(' Background with ambient Y = %0.2f cd/m2, ambient %0.3f cd/m2\n ' ,bgXYZ1(2 ),ambientXYZ1(2 ));
144157
145158% Compute monitor primary xyY to try to understand what drifted
146159primaryXYZ = PrimaryToSensor(calObjXYZ ,[[1 0 0 ]' [0 1 0 ]' [0 0 1 ]' ]);
147160primaryxyY = XYZToxyY(primaryXYZ );
161+ primaryXYZ1 = PrimaryToSensor(calObjXYZ1 ,[[1 0 0 ]' [0 1 0 ]' [0 0 1 ]' ]);
162+ primaryxyY1 = XYZToxyY(primaryXYZ1 );
148163fprintf(' \n Red primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY(1 ,1 ),primaryxyY(2 ,1 ),primaryxyY(3 ,1 ));
149164fprintf(' Green primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY(1 ,2 ),primaryxyY(2 ,2 ),primaryxyY(3 ,2 ));
150165fprintf(' Blue primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY(1 ,3 ),primaryxyY(2 ,3 ),primaryxyY(3 ,3 ));
166+ fprintf(' With ambient: Red primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY1(1 ,1 ),primaryxyY1(2 ,1 ),primaryxyY1(3 ,1 ));
167+ fprintf(' With ambient: Green primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY1(1 ,2 ),primaryxyY1(2 ,2 ),primaryxyY1(3 ,2 ));
168+ fprintf(' With ambient: Blue primary xyY: %0.4f , %0.4f , %0.2f cd/m2\n ' ,primaryxyY1(1 ,3 ),primaryxyY1(2 ,3 ),primaryxyY1(3 ,3 ));
151169
152- % Express background in terms for primaries
170+ % Express background spd in terms of primaries. Not entirely clear this
171+ % means anything important.
153172bgSpd = cal .processedData .P_ambient ;
154173bgWeights = cal .processedData .P_device \ bgSpd ;
155174fprintf(' \n Ambient linear rgb weights: %0.3f %0.3f %0.3f\n ' ,bgWeights(1 ),bgWeights(2 ),bgWeights(3 ));
156175fprintf(' \n ' );
157176
158177%% Max contrast
159178%
160- % Find maximum in gamut contrast for a set of color directions. We
161- % are not going to worry about device quantization since we used
162- % high-bit depth hardware
179+ % Find maximum in gamut contrast for a set of color directions.
180+ % This calculation does not worry about quantization. It is
181+ % done for the main case. Because we care about this primarily
182+ % for the tracking experiment, since the experimental specification
183+ % matched what we intended for tha experiment.
163184nAngles = 1000 ;
164185theAngles = linspace(0 ,2 * pi ,nAngles );
165186for aa = 1 : nAngles
198219 % Get the settings that as closely as possible approximate what we
199220 % want. One of these should be very close to 1 or 0, and none should
200221 % be less than 0 or more than 1.
201- gamutSettings = PrimaryToSettings(calObjCones ,gamutPrimaryDir + bgPrimary );
202- if (any(gamutSettings < 0 ) | any( gamutSettings > 1 ))
222+ [ gamutSettings , badIndex ] = PrimaryToSettings(calObjCones ,gamutPrimaryDir + bgPrimary );
223+ if (any(badIndex ))
203224 error(' Somehow settings got out of gamut\n ' );
204225 end
205226
271292 % Get the settings that as closely as possible approximate what we
272293 % want. One of these should be very close to 1 or 0, and none should
273294 % be less than 0 or more than 1.
274- gamutSettings = PrimaryToSettings(calObjCones ,gamutPrimaryDir + bgPrimary );
275- if (any(gamutSettings < 0 ) | any( gamutSettings > 1 ))
295+ [ gamutSettings , badIndex ] = PrimaryToSettings(calObjCones ,gamutPrimaryDir + bgPrimary );
296+ if (any(badIndex ))
276297 error(' Somehow settings got out of gamut\n ' );
277298 end
278299
287308 theSpecificAngles(aa ),100 * specificGamutContrast(1 ,aa ),100 * specificGamutContrast(2 ,aa ),100 * specificGamutContrast(3 ,aa ), ...
288309 100 * specificVectorLengthContrast(aa ));
289310end
311+
312+ % Look at these variables to get a table of max gamut contrasts in these
313+ % angular directions
290314specificVectorLengthContrast ;
291- theDetectionSpecificAngles = [ 0 90.0000 75.0000 - 75.0000 45.0000 - 45.0000 78.7500 82.5000 86.2000 - 78.7500 - 82.5000 - 86.2000 89.6000 88.6000 87.6000 22.5000 - 1.4000 - 22.5000 ] ;
315+ theSpecificAngles ;
292316clear theSpecficAngles
293317
294318%% Convert cone contrasts with respect to first calibration to second.
295- theDetectionSpecificAngles = [-86.25 - 82.5 - 78.75 - 75 - 45 0 45 75 78.75 82.5 86.25 90 ];
296- theVectorLengthContrasts = [0.05 - 0.03 0.02 - 75 - 45 0 45 75 78.75 82.5 86.25 90 ];
319+ %
320+ % Angles from paper Figure 5 labels, contrasts read off of those graphs
321+ % roughly by eye. If we go to 16 bit depth, the match would have been very
322+ % good, had the detection calibration been used the way it should have
323+ % been.
324+ theDetectionSpecificAngles = [-86.25 - 82.5 - 78.75 - 75 - 45 0 45 75 78.75 82.5 86.25 90 ];
325+ theVectorLengthContrasts = [ 0.05 0.03 0.02 0.017 0.005 0.003 0.004 0.015 0.02 0.03 0.04 0.05 ];
297326for aa = 1 : length(theDetectionSpecificAngles )
298327 fprintf(' Angle %0.1f , vector length contrast %0.1f\n ' ,theDetectionSpecificAngles(aa ),100 * theVectorLengthContrasts(aa ));
299328
319348 obtainedCones1(: ,aa ) = SettingsToSensor(calObjCones1 ,theSettings );
320349 obtainedConeContrast(: ,aa ) = ((obtainedCones(: ,aa )-bgCones ) ./ bgCones );
321350 obtainedConeContrast1(: ,aa ) = ((obtainedCones1(: ,aa )-bgCones1 ) ./ bgCones1 );
351+ obtainedAngle(aa ) = atand(obtainedConeContrast(3 ,aa )/obtainedConeContrast(1 ,aa ));
352+ obtainedAngle1(aa ) = atand(obtainedConeContrast1(3 ,aa )/obtainedConeContrast1(1 ,aa ));
322353 obtainedVectorLength(aa ) = norm(obtainedConeContrast(: ,aa ));
323354 obtainedVectorLength1(aa ) = norm(obtainedConeContrast1(: ,aa ));
355+ angleDeviation(aa ) = obtainedAngle1(aa )-obtainedAngle(aa );
356+ vectorLengthDeviation(aa ) = obtainedVectorLength1(aa ) - obtainedVectorLength(aa );
324357
325358 % Figure out the cone excitations for the settings we computed, and
326359 % then convert to contrast as our maximum contrast in this direction.
327360 %
328361 % Dividing by imageScaleFactor handles the sine phase of the Gabor
329- fprintf(' Target contrasts: L cone contrast %0 .3f%% , M, %0 .3f%% , S %0 .3f%% , vector length %0.1f%%\n ' , ...
362+ fprintf(' Target contrasts: L cone contrast %7 .3f%% , M, %7 .3f%% , S %7 .3f%% , angle %7.1f , vector length %0.1f%%\n ' , ...
330363 100 * targetConeContrast(1 ,aa ),100 * targetConeContrast(2 ,aa ),100 * targetConeContrast(3 ,aa ), ...
331- 100 * theVectorLengthContrasts(aa ));
332- fprintf(' Had ambient/cones used been right: L cone contrast %0 .3f%% , M, %0 .3f%% , S %0 .3f%% , vector length %0.1f%%\n ' , ...
364+ theDetectionSpecificAngles( aa ), 100 * theVectorLengthContrasts(aa ));
365+ fprintf(' Had ambient/cones used been right: L cone contrast %7 .3f%% , M, %7 .3f%% , S %7 .3f%% , angle %7.1f , vector length %0.1f%%\n ' , ...
333366 100 * obtainedConeContrast(1 ,aa ),100 * obtainedConeContrast(2 ,aa ),100 * obtainedConeContrast(3 ,aa ), ...
334- 100 * obtainedVectorLength(aa ));
335- fprintf(' What we actually got: L cone contrast %0 .3f%% , M, %0 .3f%% , S %0 .3f%% , vector length %0.1f%%\n ' , ...
367+ obtainedAngle( aa ), 100 * obtainedVectorLength(aa ));
368+ fprintf(' What we actually got: L cone contrast %7 .3f%% , M, %7 .3f%% , S %7 .3f%% , angle %7.1f , vector length %0.1f%%\n ' , ...
336369 100 * obtainedConeContrast1(1 ,aa ),100 * obtainedConeContrast1(2 ,aa ),100 * obtainedConeContrast1(3 ,aa ), ...
337- 100 * obtainedVectorLength1(aa ));
370+ obtainedAngle1( aa ), 100 * obtainedVectorLength1(aa ));
338371end
372+ fprintf(' \n Max abs angle deviation %0.4f , max abs vector length deviation %0.4f\n ' ,max(abs(angleDeviation )),max(abs(vectorLengthDeviation )));
339373
340-
341- % CF MAB data from Tracking
374+ %% Gamut chromaticity plot for comparisons
342375%
343- % uniqueColorDirs(:)'
344- %
345- % ans =
346- %
347- % 0 90.0000 75.0000 -75.0000 45.0000 -45.0000 78.7500 82.5000 86.2000 -78.7500 -82.5000 -86.2000 89.6000 88.6000 87.6000 22.5000 -1.4000 -22.5000
348- %
349- % matrixContrasts(1,:)
350- %
351- % ans =
352- %
353- % 0.1800 0.8500 0.6500 0.7800 0.2500 0.2600 0.8300 0.8500 0.8500 0.8400 0.8400 0.8400 0.8500 0.8500 0.8500 0.1900 0.1800 0.1900
354- %
355- % cals{1} - August 31 cal, used for tracking experiment
356- % specificVectorLengthContrast =
357- %
358- % 0.1863 0.8513 0.6556 0.7990 0.2569 0.2710 0.8438 0.8734 0.8605 0.8462 0.8442 0.8458 0.8521 0.8542 0.8567 0.1999 0.1865 0.2039
359-
360- %{
361376% This code plots the chromaticities from the tracking experiment, the
362377% detection experiment without the ambient zeroed, and some measurements we
363- % by hand on 8/2/24.
378+ % by hand on 8/2/24. Numbers here were entered by hand.
364379
365380% 'tracking'
366381% Background x,y = 0.3258, 0.3722
423438xlabel(' x chromaticity' );
424439ylabel(' y chromaticity' );
425440xlim([0 1 ]); ylim([0 1 ]);
426- %}
0 commit comments