[Matlab] RGB to XYZ to xyY and L*a*b*

Pagina: 1
Acties:

Onderwerpen


  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
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?

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));

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je vergelijk hier een range met een scalar: if xyz_r(:,1) > epsilon. Volgens mij werkt dat niet zo (matlab tijdje geleden...). Zie ook http://stackoverflow.com/...or-if-statement-in-matlab bv. Dus die vergelijkingen zullen wel altijd false zijn.

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Was ik eigenlijk al bang voor. Ik weet wel hoe ik het met een for loop op kan lossen, maar hoopte eigenlijk dat het ook vectorized kon, omdat dat veel sneller gaat.

Volgens mij zou het dan wel een oplossing zijn om een 32768x1 column vector te maken van epsilon met gewoon in elke rij weer dezelfde waarde. Maar dat is niet echt een mooie oplossing.

Dus gewoon de regel "epsilon = 216/24389;" vervangen door "epsilon = 216/24389 * ones(size(XYZ,1),1);"

EDIT: bovenstaande en dan epsilon in if statements vervangen door epsilon(:,1) werkt ook niet. Nog ideeën? (anders dan for loop)

[ Voor 12% gewijzigd door Kid Jansen op 13-02-2014 09:40 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

matlab kan volgens mij geen masked vectorized ifs. cuda wel bv.

  • naitsoezn
  • Registratie: December 2002
  • Niet online

naitsoezn

Nait Soez'n!

beter splits je het even in vectoren ipv matrices; hoef je ook geen for-loop te gebruiken. Tevens zijn er goede toolboxes te vinden die dit soort kleur-berekeningen kunnen doen.

Maar ehm.... weet je zeker dat je van rgb (welke rgb trouwens?) naar xyz naar lab wilt? Kan een heel epistel schrijven over waarom dit vaak niet zo verstandig is :)

't Het nog nooit, nog nooit zo donker west, of 't wer altied wel weer licht


  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
In rijvectoren bedoel je? Want als ik het in kolomvectoren splits heb ik toch nog steeds hetzelfde probleem? Hoe zou die code er dan uitzien?

In bovenstaand voorbeeld is het overigens Adobe RGB, maar wil het voor elke RGB kunnen doen, ook met imaginaire primairen (zoals ProPhoto RGB of ACES RGB). Reden ervoor is dat ik wilde kijken wat het effect van kleurdiepte en gamma is op de uniformiteit van de kleurafdekking van een kleurruimte.

Dat had ik eerst gedaan door simpelweg RGB te plotten in een arbitraire driehoek zonder gamma met 5 bit kleurdiepte per kanaal:

Afbeeldingslocatie: http://tweakers.net/ext/f/au0cnUA7FwK8FIIY5toQjuLy/full.png

Vervolgens gamma toegevoegd (nog steeds 5 bit kleurdiepte per kanaal):

gamma 1.4
Afbeeldingslocatie: http://tweakers.net/ext/f/BGiC0s8LvAn6R7Q04RyJX3IK/full.png

gamma 2.2
Afbeeldingslocatie: http://tweakers.net/ext/f/8hocrTSbg5UB3NjV59q4SeOc/full.png

gamma 4.0
Afbeeldingslocatie: http://tweakers.net/ext/f/nnRQoDXHaZNAkrUhjgrR9ygP/full.png

En vervolgens heb ik de RGB data omgezet via XYZ naar xyY. Voor de Adobe RGB kleurruimte met een kleurdiepte van 6 bit per kanaal en gamma 2.2 en dan krijg je dan dit:
Afbeeldingslocatie: http://tweakers.net/ext/f/60exlwSW0jRtbiIkuTRIEjrC/full.png

Matlab kan dit berekenen op mijn PC t/m 8 bit kleurdiepte per kanaal met de code in de startpost, maar plotten gaat maar tot 6 bit. Matlab vindt 262144 cirkeltjes tekenen al moeilijk genoeg, 2097152 (7 bit per kanaal) of meer worden er echt teveel.

De reden dat ik ook nog naar L*a*b* wilde is dat CIE ∆E 2000 berekend moet worden in L*a*b*. Ik wilde namelijk kijken of ik kon bepalen wat de minimum vereiste kleurdiepte is zodat elke kleur in een bepaalde kleurruimte wordt afgedekt met een verschil ten opzichte van hoe het zou moeten zijn kleiner dan ∆E00 = 1 (op een manier vergelijkbaar met Non-MacAdam Color Discrimination Ellipses (Goldstein, 2012)). Maar dat is nogal een projectje...

[ Voor 4% gewijzigd door Kid Jansen op 13-02-2014 23:12 ]


  • naitsoezn
  • Registratie: December 2002
  • Niet online

naitsoezn

Nait Soez'n!

Kid Jansen schreef op donderdag 13 februari 2014 @ 21:28:
In rijvectoren bedoel je? Want als ik het in kolomvectoren splits heb ik toch nog steeds hetzelfde probleem?
wat is het verschil precies? ;) Ik weet het verschil wel, in matlab kan dit geen probleem voor je zijn.... een simpele ( : ) levert al een oplossing... of anders een reshape.

Kleur is m'n vak (vroeger vooral computer vision, tegenwoordig vooral meten / reflecties en af en toe cie-lab ), op je mooie plaatjes kom ik morgen terug :) . Waar ligt je interesse vooral? Is het enkel de visualisatie, wil je vooral dingen berekenen, of gaat het je echt om de hardcore kleur-informatie?

[ Voor 101% gewijzigd door naitsoezn op 13-02-2014 22:22 ]

't Het nog nooit, nog nooit zo donker west, of 't wer altied wel weer licht


  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Als ik de matrix verticaal opsplits dan krijg ik drie kolomvectoren X, Y en Z van 32768x1. Maar dan heb ik toch nog steeds hetzelfde probleem als nu? Of werkt "if X > epsilon" dan wel? Want "if X(:,1) > epsilon(:,1)" zal in ieder geval niet werken, anders zou m'n huidge code ook werken (inclusief update in m'n tweede post).
Kleur is m'n vak (vroeger vooral computer vision, tegenwoordig vooral meten / reflecties en af en toe cie-lab ), op je mooie plaatjes kom ik morgen terug :) . Waar ligt je interesse vooral? Is het enkel de visualisatie, wil je vooral dingen berekenen, of gaat het je echt om de hardcore kleur-informatie?
Vooral visualisatie, maar ik ben ook geïnteresseerd in de cijfers.

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Maak gewoon een loopje, dat is ook niet langzamer. Dat vectorized hij ook gewoon. Sowieso heb je geen native vector support oid, dus alles wordt een loop.

Acties:
  • 0 Henk 'm!

  • naitsoezn
  • Registratie: December 2002
  • Niet online

naitsoezn

Nait Soez'n!

Zoijar schreef op vrijdag 14 februari 2014 @ 08:02:
Maak gewoon een loopje, dat is ook niet langzamer. Dat vectorized hij ook gewoon. Sowieso heb je geen native vector support oid, dus alles wordt een loop.
Misschien heb ik een recente update van Matlab gemist, maar toen ik nog regelmatig 'matlabte' merkte ik wel degelijk een factor 20 / 50 verschil in snelheid als ik met een for-loop over een matrix / vector heen loop of gewoon met een masker dezelfde bewerking in één regel uitvoer. :)
Kid Jansen schreef op donderdag 13 februari 2014 @ 22:47:
[...]

Als ik de matrix verticaal opsplits dan krijg ik drie kolomvectoren X, Y en Z van 32768x1. Maar dan heb ik toch nog steeds hetzelfde probleem als nu? Of werkt "if X > epsilon" dan wel? Want "if X(:,1) > epsilon(:,1)" zal in ieder geval niet werken, anders zou m'n huidge code ook werken (inclusief update in m'n tweede post).
Als je een vector hebt hoe je de variabele niet te benaderen als een matrix. Maar is het al gelukt? Anders zou ik gewoon een toolbox downloaden (dan hoef je die draak van de dE2000 straks ook niet meer uit te programmeren) ;) Bijvoorbeeld die van Stephen Westland :)

Wat betreft je project, weet wel dat RGB een monitor kleurenruimte is, en XYZ / Lab device-onafhankelijk zijn. Het is altijd een beetje tricky om van RGB naar XYZ te gaan. Mathematisch kan het prima, maar 'fysisch' (bij gebrek aan beter woord) is de RGB een beetje een betekenisloos kleurmodel. Als je uitspraken wilt doen over kleuren en 'kleurdiepte' (naar woord) dan kun je net zo goed beginnen met Lab :) .

Edit: Wat betreft dE00 < 1 om de hele kleurenruimte af te dichten: Prima om ergens een grens te stellen, en dE00 < 1 is net zo goede grens als elke andere, maar trap niet in de val om de achterliggende gedachte van dE00 te geloven dat een dE00 = 1 een "just noticeable difference" is. De kleurmakers bij ons op het lab lachen je hardop uit als je zegt dat je een kleurverschil kleiner dan 1 niet zult zien. Voor lichte kleuren is zelfs een dE van 0.5 nog zichtbaar :) .

[ Voor 11% gewijzigd door naitsoezn op 14-02-2014 09:44 ]

't Het nog nooit, nog nooit zo donker west, of 't wer altied wel weer licht


Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
naitsoezn schreef op vrijdag 14 februari 2014 @ 09:39:
Als je een vector hebt hoe je de variabele niet te benaderen als een matrix. Maar is het al gelukt?
Nog niet, heb het geprobeerd zoals hieronder (dit bedoel je toch?), maar de ifs en elseifs doen nog steeds niks.
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
Lab = zeros(size(XYZ));
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);
    if x_r > epsilon
        f_x = x_r^(1/3);
    elseif x_r <= epsilon
        f_x = (kappa*x_r+16)/116;
    end
    if y_r > epsilon
        f_y = y_r^(1/3);
    elseif y_r <= epsilon
        f_y = (kappa*y_r+16)/116;
    end
    if z_r > epsilon
        f_z = z_r^(1/3);
    elseif z_r <= epsilon
        f_z = (kappa*z_r+16)/116;
    end
Lab(:,1) = 116*f_y-16;
Lab(:,2) = 500*(f_x-f_y);
Lab(:,3) = 200*(f_y-f_z);


Heb voor nu het probleem maar opgelost met een while-loop. Moet zeggen dat 5 bit dan nog verassend snel gaat. Met 6 bit duurt het wel wat langer, maar nog steeds prima te doen en hoger dan 6 bit is voor plots toch geen optie.

Laatste stuk code ziet er dan zo uit:

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
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));
s = 2^(3*N);
i = 1;
    while i <= s
        if xyz_r(i,1) > epsilon
            f_xyz(i,1) = xyz_r(i,1)^(1/3);
        elseif xyz_r(i,1) <= epsilon
            f_xyz(i,1) = (kappa*xyz_r(i,1)+16)/116;
        end
        if xyz_r(i,2) > epsilon
            f_xyz(i,2) = xyz_r(i,2)^(1/3);
        elseif xyz_r(i,2) <= epsilon
            f_xyz(i,2) = (kappa*xyz_r(i,2)+16)/116;
        end
        if xyz_r(i,3) > epsilon
            f_xyz(i,3) = xyz_r(i,3)^(1/3);
        elseif xyz_r(i,3) <= epsilon
            f_xyz(i,3) = (kappa*xyz_r(i,3)+16)/116;
        end
        i = i+1;
    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));
scatter3(Lab(:,2),Lab(:,3),Lab(:,1),3,RGB_gamma)
axis equal
axis([min(Lab(:,2))-10 max(Lab(:,2))+10 min(Lab(:,3))-10 max(Lab(:,3))+10 min(Lab(:,1))-10 max(Lab(:,1))+10])


Resultaat voor Adobe RGB voor gamma 2.2 en kleurdiepte per kanaal van 6 bit is dan:
Afbeeldingslocatie: http://tweakers.net/ext/f/uVBo29qQE6D85NXtw6s3e78E/full.png

En 2D view geprojecteerd op a*b* vlak:
Afbeeldingslocatie: http://tweakers.net/ext/f/rCIb5KqU2NWcsdbtZkzPUdnw/full.png

Als ik die laatste vergelijk met andere afbeeldingen van Adobe RGB in CIE L*a*b* dan lijkt dat te kloppen.
Anders zou ik gewoon een toolbox downloaden (dan hoef je die draak van de dE2000 straks ook niet meer uit te programmeren) ;) Bijvoorbeeld die van Stephen Westland
Doe ik alsnog wel. Heb in ieder geval de code nu werkende, al is het met een loop in plaats van vectorized.
Wat betreft je project, weet wel dat RGB een monitor kleurenruimte is, en XYZ / Lab device-onafhankelijk zijn. Het is altijd een beetje tricky om van RGB naar XYZ te gaan. Mathematisch kan het prima, maar 'fysisch' (bij gebrek aan beter woord) is de RGB een beetje een betekenisloos kleurmodel. Als je uitspraken wilt doen over kleuren en 'kleurdiepte' (naar woord) dan kun je net zo goed beginnen met Lab
Eigenlijk begin ik toch in xyY met die Adobe RGB kleurruimte? Dat is hoe vrijwel alle gangbare RGB kleurruimtes en ook het kleurbereik van beeldschermen zijn gedefinieerd. Die RGB matrix bestaat uit simpelweg alle mogelijke combinaties voor een bepaalde kleurdiepte. Het gaat mij er niet om, om voor één bepaalde RGB combinatie voor een bepaalde kleurruimte naar XYZ naar xyY of L*a*b* te gaan (dan zijn er inderdaad betere opties). Het gaat mij alleen om het patroon dat je krijgt in xyY of L*a*b* voor een bepaalde kleurdiepte, gamma en RGB kleurruimte.
Edit: Wat betreft dE00 < 1 om de hele kleurenruimte af te dichten: Prima om ergens een grens te stellen, en dE00 < 1 is net zo goede grens als elke andere, maar trap niet in de val om de achterliggende gedachte van dE00 te geloven dat een dE00 = 1 een "just noticeable difference" is.
Zou inderdaad nog wel kleiner kunnen. Die publicatie die ik eerder aanhaalde heeft het erover dat voor dE00 = 1 meer dan 99% van de bevolking een verschil ziet. Mensen die in dit wereldje zitten zien inderdaad vaak nog veel kleinere kleurverschillen. Als je wil dat niet meer dan 1% van de bevolking een verschil ziet zal je misschien wel dE00 = 0.2 als grens moeten stellen.
De kleurmakers bij ons op het lab lachen je hardop uit als je zegt dat je een kleurverschil kleiner dan 1 niet zult zien. Voor lichte kleuren is zelfs een dE van 0.5 nog zichtbaar :)
Mooi is dat... ;)

Acties:
  • 0 Henk 'm!

  • naitsoezn
  • Registratie: December 2002
  • Niet online

naitsoezn

Nait Soez'n!

Kan het nu even niet testen, maar heb je code iets aangepast; zou moeten werken zo, volgens mij....
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Lab = zeros(size(XYZ));
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);

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;

Lab(:,1) = 116*y_r-16;
Lab(:,2) = 500*(x_r-y_r);
Lab(:,3) = 200*(y_r-z_r);

[ Voor 3% gewijzigd door naitsoezn op 14-02-2014 14:12 ]

't Het nog nooit, nog nooit zo donker west, of 't wer altied wel weer licht


Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Nice! Dat werkt! Heel erg bedankt! Zat nog één klein foutje, maar dat was nog van mij, niet van jou: de "^" moeten ".^" zijn.

Jouw code is iets meer dan een factor twee sneller dan mijn code zonder het plotgedeelte (getest voor 6, 7 en 8 bit, hoger heb ik niet genoeg werkgeheugen voor). Maar zelfs voor 8 bit duurt het met mijn code nog steeds maar 15 seconden (zonder het plotgedeelte).

De echte tijd gaat in het plotten zitten, dat kan maar tot en met 6 bit en dan duurt het plotten alleen al 140 seconden (ongeacht de view). Bottleneck zit daarbij waarschijnlijk in geheugenbandbreedte of geheugenlatency, want geen één CPU core wordt maximaal belast en Matlab gebruikt ook maar 925 MB geheugen op z'n piek tijdens het plotten.

  • TheWickedD
  • Registratie: Juli 2002
  • Laatst online: 02-04-2024
wat betreft plotten, zet je plot window in openGL mode, dat werkt misschien beter als je zoveel in je figuur hebt zitten.
http://www.mathworks.com/...e_props.html#RendererMode

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Als je zo'n plaatje ray traced; i.e. per pixel berekent, dan hoef je een stuk minder te rekenen :) Misschien wil je op 4x de resolutie en dan downscalen om het iets te smoothen.

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Ga ik naar kijken, bedankt!

Acties:
  • 0 Henk 'm!

  • rvtk
  • Registratie: Juni 2001
  • Laatst online: 19:19
Je kan ook de functie makecform (zie http://www.mathworks.nl/help/images/ref/makecform.html) gebruiken.

Bijvoorbeeld:
code:
1
2
3
rgb = imread('peppers.png');
cform = makecform('srgb2lab');
lab = applycform(rgb,cform);


Waarschijnlijk kan ik het plotten wel voor je versnellen, post dan even een werkend voorbeeldje.

Met patch kan je redelijk snel veel punten plotten (vrijdagmiddag toegift).
code:
1
2
3
4
5
6
7
n = 200000;

patchinfo.Vertices = rand(n,3); % contain x,y,z coordinates of points
patchinfo.Faces = [1:n]';
vertexColor = jet(n); % rgb color for each point

p = patch(patchinfo,'Marker','.','EdgeColor','interp','FaceVertexCData',vertexColor);

[ Voor 50% gewijzigd door rvtk op 21-02-2014 15:57 ]


Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
rvtk schreef op vrijdag 21 februari 2014 @ 15:36:
Je kan ook de functie makecform (zie http://www.mathworks.nl/help/images/ref/makecform.html) gebruiken.

Bijvoorbeeld:
code:
1
2
3
rgb = imread('peppers.png');
cform = makecform('srgb2lab');
lab = applycform(rgb,cform);
Eigenlijk is de topictitel een beetje misleidend, want het gaat me niet om de RGB waardes van de pixels van een afbeelding om zetten, maar om de patronen die je krijgt in xyY en L*a*b* door alle mogelijke RGB combinaties daar in te plotten voor een bepaalde kleurdiepte, gammawaarde en kleurruimte. Dus die methode is hierboven heb ik dan niet zo veel aan.
Waarschijnlijk kan ik het plotten wel voor je versnellen, post dan even een werkend voorbeeldje.

Met patch kan je redelijk snel veel punten plotten (vrijdagmiddag toegift).
code:
1
2
3
4
5
6
7
n = 200000;

patchinfo.Vertices = rand(n,3); % contain x,y,z coordinates of points
patchinfo.Faces = [1:n]';
vertexColor = jet(n); % rgb color for each point

p = patch(patchinfo,'Marker','.','EdgeColor','interp','FaceVertexCData',vertexColor);
Wat bedoel je precies met werkend voorbeeld? Voor xyY plot gebruik ik code in startpost t/m regel 57 met daar het volgende achter:

code:
1
2
3
4
scatter(xyY(:,1),xyY(:,2),3,RGB_gamma)
axis equal
axis([0 .8 0 .9])
whitebg([0,0,0])

Acties:
  • 0 Henk 'm!

  • rvtk
  • Registratie: Juni 2001
  • Laatst online: 19:19
Je gaf aan dat het plotten van al die cirkels erg lang duurde. Vandaar mijn alternatief om patch te gebruiken. In onderstaand voorbeeld duurt scatter bij mij 54 seconden, terwijl patch binnen 0.3 seconden klaar is. Hopelijk helpt onderstaande code je verder.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
n = 200000;
s = 3;
xyY = rand(n,2);
RGB_gamma = rand(n,3);

% use scatter
figure, tic
scatter(xyY(:,1),xyY(:,2),3,RGB_gamma)
toc

% use patch
figure, tic
patchinfo.Vertices = xyY; % contain x,y coordinates of points
patchinfo.Faces = [1:n]';
vertexColor = RGB_gamma; % rgb color for each point
p = patch(patchinfo,'Marker','.','EdgeColor','interp','FaceVertexCData',vertexColor);
toc

Acties:
  • 0 Henk 'm!

  • Kid Jansen
  • Registratie: Oktober 2005
  • Niet online
Bij mij is het verschil nog groter met jouw code: 57 seconden vs. 0,00644 seconden, dat is bijna 9000 keer sneller dus.

Enige probleem is dat de markers te groot zijn. Met een paar kleine aanpassingen kon ik het zo achter mijn code plakken, resultaat staat hieronder.

code:
1
2
3
4
5
6
7
8
9
figure, tic
patchinfo.Vertices = xyY;
patchinfo.Faces = [1:2^N^3]';
p = patch(patchinfo,'Marker','.','MarkerSize',1,'EdgeColor','interp','FaceVertexCData',RGB_gamma);
axis equal
axis([0 .8 0 .9])
whitebg([0,0,0])
grid on
toc


Afbeeldingslocatie: http://tweakers.net/ext/f/uYiciBeNnW589c41d4HquYNq/full.png
(klikbaar)

Zoals je kan zien verschilt het resultaat behoorlijk van hetzelfde plaatje met scatter qua duidelijkheid van het patroon:

Afbeeldingslocatie: http://tweakers.net/ext/f/60exlwSW0jRtbiIkuTRIEjrC/full.png
(klikbaar)

Is het ook mogelijk om een marker van 1 pixel te hebben? Dan heeft het namelijk nog zin voor hoger dan 6 bit. Met patch gaat 8 bit plotten nog steeds behoorlijk snel, maar dan is het een compleet dicht vlak.

EDIT: heb nu 'MarkerSize',1, toegevoegd in de patch, waardoor 6 bit met patch nu zelfs nog een stuk beter is dan het resultaat van scatter. Maar hoger dan 6 bit heeft alsnog geen zin, want met 7 bit zie je nauwelijks nog een patroon en met 8 bit is het op één zwarte streep na alsnog een compleet dicht vlak.

Gaat overigens lekker snel, bovengenoemde code heeft voor 6 bit maar 0,08 seconden nodig.

[ Voor 17% gewijzigd door Kid Jansen op 24-02-2014 22:45 ]

Pagina: 1