[Matlab] 3D surface van point cloud

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Ik heb de onderstaande code waarmee ik een point cloud plot in de CIELAB kleurruimte van alle kleuren in de Adobe RGB kleurruimte op basis van een gammawaarde van 2.2 en een kleurdiepte van 5 bits per kleurkanaal. (allcomb-functie nodig van File Exchange om code te runnen)

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
70
71
72
73
74
75
tic
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 (Bruce Lindbloom)
Yw = 1;                                                 % Y-values for CIE Standard Illuminant D65 (Bruce Lindbloom)
Zw = 1.08883;                                               % Z-values for CIE Standard Illuminant D65 (Bruce Lindbloom)
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
clear RGB RGB_norm
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
epsilon = 216/24389 * ones(size(XYZ,1),1);
kappa = 24389/27;
x_r = XYZ(:,1)/XYZ_w(1,1);
y_r = XYZ(:,2)/XYZ_w(2,1);
z_r = XYZ(:,3)/XYZ_w(3,1);
clear XYZ

mask = x_r > epsilon;
x_r( mask ) = x_r( mask ) .^ (1/3);
x_r( ~mask ) = ( kappa * x_r( ~mask ) + 16 ) / 116;

mask = y_r > epsilon;
y_r( mask ) = y_r( mask ) .^ (1/3);
y_r( ~mask ) = ( kappa * y_r( ~mask ) + 16 ) / 116;

mask = z_r > epsilon;
z_r( mask ) = z_r( mask ) .^ (1/3);
z_r( ~mask ) = ( kappa * z_r( ~mask ) + 16 ) / 116;

L = 116*y_r-16;
a = 500*(x_r-y_r);
b = 200*(y_r-z_r);
clear epsilon x_r y_r z_r mask
toc
tic
figure(1);
patchinfo.Vertices = horzcat(a,b,L);
patchinfo.Faces = [1:2^N^3]';
p = patch(patchinfo,'Marker','.','MarkerSize',1,'EdgeColor','interp','FaceVertexCData',RGB_gamma);
axis equal;
axis([min(a)-10 max(a)+10 min(b)-10 max(b)+10 min(L)-10 max(L)+10]);
grid on;
whitebg([0.5,0.5,0.5]);
view(3);
toc


Nu wil ik die point cloud omzetten naar een surface en dat dacht ik te doen met de onderstaande code:

code:
1
2
3
4
5
6
7
8
9
10
11
12
tic
tri = delaunay(a,b,L);
toc
tic
figure(2);
trisurf(tri,a,b,L,'EdgeColor','none','LineStyle','none','FaceLighting','gouraud');
axis equal;
axis([min(a)-10 max(a)+10 min(b)-10 max(b)+10 min(L)-10 max(L)+10]);
grid on;
whitebg([0.5,0.5,0.5]);
view(3);
toc


Maar het resultaat daarvan is niet zoals ik het wil. Ik wil namelijk dat de resulterende surface ook echt door alle buitenste punten snijden, nu is dat bij concave vlakken niet het geval. Daarnaast worden er veel te veel driehoeken berekend. Want "tri" is nu een 205317 x 4 double, terwijl er maar 32768 kleuren zijn. Het aantal driehoeken waar de surface uit bestaat zou juist veel kleiner moeten zijn dan het aantal kleuren. Nu worden er ook driehoeken berekend door de point cloud heen, daarnaast worden sommige driehoeken van de surface juist niet berekend (waarschijnlijk door de volgorde waarin RGB gegenereerd is).

Ook zou ik graag de kleuren van de surface laten overeenkomen met de juiste kleuren (RGB_gamma, zoals ook in de patch-plot).

Geïnstalleerde toolboxes:
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
MATLAB                                                Version 8.3        (R2014a)
Simulink                                              Version 8.3        (R2014a)
Communications System Toolbox                         Version 5.6        (R2014a)
Computer Vision System Toolbox                        Version 6.0        (R2014a)
Control System Toolbox                                Version 9.7        (R2014a)
Curve Fitting Toolbox                                 Version 3.4.1      (R2014a)
DSP System Toolbox                                    Version 8.6        (R2014a)
Data Acquisition Toolbox                              Version 3.5        (R2014a)
Global Optimization Toolbox                           Version 3.2.5      (R2014a)
Image Acquisition Toolbox                             Version 4.7        (R2014a)
Image Processing Toolbox                              Version 9.0        (R2014a)
Instrument Control Toolbox                            Version 3.5        (R2014a)
MATLAB Report Generator                               Version 3.16       (R2014a)
Mapping Toolbox                                       Version 4.0.1      (R2014a)
Neural Network Toolbox                                Version 8.2        (R2014a)
Optimization Toolbox                                  Version 7.0        (R2014a)
Parallel Computing Toolbox                            Version 6.4        (R2014a)
Partial Differential Equation Toolbox                 Version 1.4        (R2014a)
Phased Array System Toolbox                           Version 2.2        (R2014a)
Signal Processing Toolbox                             Version 6.21       (R2014a)
SimDriveline                                          Version 2.6        (R2014a)
SimElectronics                                        Version 2.5        (R2014a)
SimEvents                                             Version 4.3.2      (R2014a)
SimMechanics                                          Version 4.4        (R2014a)
SimPowerSystems                                       Version 6.1        (R2014a)
Simscape                                              Version 3.11       (R2014a)
Simulink 3D Animation                                 Version 7.1        (R2014a)
Simulink Control Design                               Version 4.0        (R2014a)
Simulink Design Optimization                          Version 2.5        (R2014a)
Simulink Report Generator                             Version 3.16       (R2014a)
Stateflow                                             Version 8.3        (R2014a)
Statistics Toolbox                                    Version 9.0        (R2014a)
Symbolic Math Toolbox                                 Version 6.0        (R2014a)
Wavelet Toolbox                                       Version 4.13       (R2014a)


EDIT: de onderstaande afbeelding is zoals ik het zou willen hebben (klik voor groot). Dit heb ik nu gedaan met de patch-plot door een kleurdiepte van 9 bit per kanaal te kiezen (hoogste wat ik met 24 GB RAM kan uitrekenen), zodat het door het grote aantal punten alsnog een oppervlak lijkt. Maar dat wil ik dus graag als echte surface.

Afbeeldingslocatie: http://static.tweakers.net/ext/f/hRktWCjjxGjpvcWSd5b2iaIU/thumb.png

[ Voor 27% gewijzigd door Kid Jansen op 20-03-2015 01:31 ]


Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Inmiddels ben ik iets verder met behulp van Bruce Lindbloom. Doordat ik gewend ben om te werken met chromaticiteitdiagrammen had ik wel gerealiseerd dat elke RGB-combinatie waar minimaal één van de drie gelijk is aan 0 deel uit maakt van het oppervlak, maar niet dat dat ook geld wanneer minimaal één van de drie gelijk is aan 1.

Nu ik dat wel weet heb ik een point cloud kunnen maken van alleen de punten die deel uitmaken van het oppervlak, maar ook dan doet Delaunay triangulation blijkbaar niet wat ik wil. Nog steeds worden concave delen dan recht, nog steeds is het aantal driehoeken veel groter dan het aantal punten en nog steeds gaan er driehoeken door de point cloud heen.

De nieuwe code voor het eerste deel is niet heel anders dan eerst (zie onderstaande), het tweede deel (Delaunay en trisurf) is ongewijzigd gebleven.

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
70
71
72
73
74
75
76
77
78
79
tic
format long                                             % sets number of decimals for doubles to 15
N = 7;                                                  % 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
surface_mask = (RGB_norm(:,1)>0 & RGB_norm(:,1)<1 & RGB_norm(:,2)>0 & RGB_norm(:,2)<1 & RGB_norm(:,3)>0 & RGB_norm(:,3)<1);
RGB_gamma = RGB_norm.^Gamma;                                        % adds gamma encoding to normalized RGB matrix
clear RGB RGB_norm
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
epsilon = 216/24389 * ones(size(XYZ,1),1);
kappa = 24389/27;
x_r = XYZ(:,1)/XYZ_w(1,1);
y_r = XYZ(:,2)/XYZ_w(2,1);
z_r = XYZ(:,3)/XYZ_w(3,1);
clear XYZ

mask = x_r > epsilon;
x_r( mask ) = x_r( mask ) .^ (1/3);
x_r( ~mask ) = ( kappa * x_r( ~mask ) + 16 ) / 116;

mask = y_r > epsilon;
y_r( mask ) = y_r( mask ) .^ (1/3);
y_r( ~mask ) = ( kappa * y_r( ~mask ) + 16 ) / 116;

mask = z_r > epsilon;
z_r( mask ) = z_r( mask ) .^ (1/3);
z_r( ~mask ) = ( kappa * z_r( ~mask ) + 16 ) / 116;

L = 116*y_r-16;
a = 500*(x_r-y_r);
b = 200*(y_r-z_r);
clear epsilon x_r y_r z_r mask
toc
tic
figure(1);
abL = horzcat(a,b,L);
abL(surface_mask,:) = [];
RGB_gamma(surface_mask,:) = [];
patchinfo.Vertices = abL;
patchinfo.Faces = [1:size(abL,1)]';
p = patch(patchinfo,'Marker','.','MarkerSize',1,'EdgeColor','interp','FaceVertexCData',RGB_gamma);
axis equal;
axis([min(a)-10 max(a)+10 min(b)-10 max(b)+10 min(L)-10 max(L)+10]);
grid on;
whitebg([0.5,0.5,0.5]);
view(3);
toc

Het resultaat laat duidelijk zien dat je zo alleen de punten hebt waar het oppervlak uit bestaat:
Afbeeldingslocatie: http://static.tweakers.net/ext/f/SoQvQj60t3fFLALXw3X099Ct/thumb.png

Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Niemand die hier verstand van heeft?