Ik wil graag voor een bepaalde kleurdiepte, gammawaarde en kleurruimte van RGB naar XYZ, zodat ik van XYZ naar xyY en L*a*b* kan. Ik heb inmiddels de onderstaande code geschreven om dat te doen na heel wat gepuzzel en van RGB naar XYZ naar xyY gaat nu goed (t/m regel 43).
Wat alleen nog niet goed gaat is van XYZ naar L*a*b*. Ik doe iets fout in de code van regel 52 t/m 66, want f_xyz blijft alleen maar nullen en daardoor is Lab in de eerste kolom overal -16 en in de tweede en derde kolom overal 0.
Wat de code zou moeten doen is de 32768x3 matrix XYZ omzetten in de 32768x3 matrix Lab volgens de formules op deze pagina.
Wat doe ik fout en hoe los ik het op?
Wat alleen nog niet goed gaat is van XYZ naar L*a*b*. Ik doe iets fout in de code van regel 52 t/m 66, want f_xyz blijft alleen maar nullen en daardoor is Lab in de eerste kolom overal -16 en in de tweede en derde kolom overal 0.
Wat de code zou moeten doen is de 32768x3 matrix XYZ omzetten in de 32768x3 matrix Lab volgens de formules op deze pagina.
Wat doe ik fout en hoe los ik het op?
code:
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
| format long % sets number of decimals for doubles to 15 N = 5; % color depth per channel in bits Gamma = 2.2; % Gamma Rx = 0.64; % x-coordinate of red primary of Adobe RGB Ry = 0.33; % y-coordinate of red primary of Adobe RGB Gx = 0.21; % x-coordinate of green primary of Adobe RGB Gy = 0.71; % y-coordinate of green primary of Adobe RGB Bx = 0.15; % x-coordinate of blue primary of Adobe RGB By = 0.06; % y-coordinate of blue primary of Adobe RGB Xw = 0.95047; % X-values for CIE Standard Illuminant D65 (Wikipedia) Yw = 1; % Y-values for CIE Standard Illuminant D65 (Wikipedia) Zw = 1.08883; % Z-values for CIE Standard Illuminant D65 (Wikipedia) max_lvl = 2^N-1; % highest value for channel for selected color depth R = 0:1:max_lvl; % creates red channel row vector R = transpose(R); % transpose row vector to column vector G = R; % creates green channel column vector B = R; % creates blue channel column vector RGB = allcomb(R,G,B); % creates matrix with all possible RGB combinations (m-file for allcomb function attached) RGB_norm = RGB/max_lvl; % normalizes RGB matrix so that the values range from 0 to 1 RGB_gamma = RGB_norm.^Gamma; % adds gamma encoding to normalized RGB matrix Xr = Rx/Ry; Yr = 1; Zr = (1-Rx-Ry)/Ry; Xg = Gx/Gy; Yg = 1; Zg = (1-Gx-Gy)/Gy; Xb = Bx/By; Yb = 1; Zb = (1-Bx-By)/By; XYZ_rgb = [Xr Xg Xb; Yr Yg Yb; Zr Zg Zb]; XYZ_rgb_inv = inv(XYZ_rgb); XYZ_w = [Xw; Yw; Zw]; % simple version using built-in values for D65 is XYZ_w = transpose(whitepoint('d65')); S_rgb = XYZ_rgb_inv * XYZ_w; M= zeros(size(XYZ_rgb)); M(:,1) = XYZ_rgb(:,1) * S_rgb(1,1); M(:,2) = XYZ_rgb(:,2) * S_rgb(2,1); M(:,3) = XYZ_rgb(:,3) * S_rgb(3,1); XYZ = transpose(M * transpose(RGB_gamma)); % creates XYZ matrix from RGB matrix using transformation matrix M xyY = zeros(size(XYZ)); % create empty xyY matrix equal in size to the XYZ matrix (and therefore also the three RGB matrices) XYZ_dem = sum(XYZ,2); % create denominator vector X+Y+Z used for x=X/(X+Y+Z) and y=Y/(X+Y+Z) xyY(:,1) = XYZ(:,1)./XYZ_dem; % sets first column (the x value in xyY) to x=X/(X+Y+Z) by elementwise division of first column in XYZ (X) by the denominator vector xyY(:,2) = XYZ(:,2)./XYZ_dem; % sets second column (the y value in xyY) to y=Y/(X+Y+Z) by elementwise division of second column in XYZ (Y) by the denominator vector xyY(:,3) = XYZ(:,2); % sets third column (the Y value in xyY) to second colum in XYZ (naturally also Y) Lab = zeros(size(XYZ)); epsilon = 216/24389; kappa = 24389/27; xyz_r = zeros(size(XYZ)); xyz_r(:,1) = XYZ(:,1)/XYZ_w(1,1); xyz_r(:,2) = XYZ(:,2)/XYZ_w(2,1); xyz_r(:,3) = XYZ(:,3)/XYZ_w(3,1); f_xyz = zeros(size(XYZ)); if xyz_r(:,1) > epsilon f_xyz(:,1) = xyz_r(:,1)^(1/3); elseif xyz_r(:,1) <= epsilon f_xyz(:,1) = (kappa*xyz_r(:,1)+16)/116; end if xyz_r(:,2) > epsilon f_xyz(:,2) = xyz_r(:,2)^(1/3); elseif xyz_r(:,2) <= epsilon f_xyz(:,2) = (kappa*xyz_r(:,2)+16)/116; end if xyz_r(:,3) > epsilon f_xyz(:,3) = xyz_r(:,3)^(1/3); elseif xyz_r(:,3) <= epsilon f_xyz(:,3) = (kappa*xyz_r(:,3)+16)/116; end Lab(:,1) = 116*f_xyz(:,2)-16; Lab(:,2) = 500*(f_xyz(:,1)-f_xyz(:,2)); Lab(:,3) = 200*(f_xyz(:,2)-f_xyz(:,3)); |