Wednesday, July 24, 2024
HomeMatlabExtra experiments with sRGB gamut boundary in L*a*b* area » Steve on...

Extra experiments with sRGB gamut boundary in L*a*b* area » Steve on Picture Processing with MATLAB

I am nonetheless enjoying round with RGB gamut calculations in $ L^* a^* b^* $ area. (See my final put up on this matter, “Visualizing out-of-gamut colours in a Lab curve.”) Right now’s put up options some new gamut-related visualizations, plus some computational methods involving gamut boundaries and rays in $ L^* a^* b^* $ area.

First, right here is one other strategy to talk the concept that the in-gamut space within the $ (a^*,b^*) $ airplane varies with $ L^* $ (perceptual lightness). For 9 values of $ L^* $, (10, 20, …, 90), I will compute a 2-D $ (a^*,b^*) $ gamut masks by brute-forcing it. Then, I will use overlaid contour plots to point out the variation in gamut boundaries.

[aa,bb,LL] = meshgrid(a,b,L);

rgb = lab2rgb(cat(3,LL(:,:,okay),aa(:,:,okay),bb(:,:,okay)));

masks = all((0 <= rgb) & (rgb <= 1),3) * 2 – 1 + L(okay);

contour(a,b,masks,[L(k) L(k)],LineColor=[.8 .8 .8],LineWidth=1.5,ShowText=true,

title(“Gamut boundary within the (a,b) airplane for a number of values of L*”)

This is one other visualization idea. Individuals typically present colours on the $ (a^*,b^*) $ airplane, to provide an thought of the which means of $ a^* $ and $ b^* $, however that does not talk very nicely the concept that there are often a number of colours, corresponding to numerous $ L^* $ values, at anybody $ (a^*,b^*) $ location. Beneath, I present each the brightest in-gamut colour and the darkest in-gamut colour at every $ (a^*,b^*) $ location.

[L_min(p,q),L_max(p,q)] = Lrange(aa(p,q),bb(p,q));

rgb = lab2rgb(cat(3,L_max,aa,bb));

imshow(rgb,XData=a([1 end]),YData=b([1 end]))

title(“Brightest in-gamut colour”)

rgb_min = lab2rgb(cat(3,L_min,aa,bb));

imshow(rgb_min,XData=a([1 end]),YData=b([1 end]))

title(“Darkest in-gamut colour”)

Subsequent, I discover myself typically wanting to attract a ray in $ L^* a^* b^* $ area and discover the gamut boundary location alongside that ray. To that finish, I wrote a easy utility operate (findNonzeroBoundary beneath) that performs a binary search to seek out the place a operate goes from optimistic to 0. Then, I wrote some nameless features to seek out the specified gamut boundary level. Particularly, I used to be on this query: For a given $ L^* $ worth and a given $ (a^*,b^*) $ airplane angle, h, what’s the in-gamut colour with the utmost chroma, c, or distance from $ (0,0) $ within the $ (a^*,b^*) $ airplane?

Honest warning: the code beneath will get tough with nameless features. You may hate it. If that’s the case, I completely perceive, and I hope you may forgive me. 🙂

I will begin by creating an nameless operate that converts from $ L^* c h $ to $ L^* a^* b^* $:

lch2lab = @(lch) [lch(1) lch(2)*cosd(lch(3)) lch(2)*sind(lch(3))];

Subsequent, right here is an nameless operate that returns whether or not or not a specific $ L^* a^* b^* $ level is in gamut.

inGamut = @(lab) all(0 <= lab2rgb(lab),2) & all(lab2rgb(lab) <= 1,2);

Lastly, a 3rd nameless operate makes use of findNonzeroBoundary to seek out the gamut boundary level that I am excited about.

maxChromaAtLh = @(L,h) findNonzeroBoundary(@(c) inGamut(lch2lab([L c h])), 0, 200);

Let’s train this operate to discover a excessive chroma darkish colour at $ h=0^{circ} $.

And here is what that colour seems to be like.

rgb_out = lab2rgb(lch2lab([L c h]));

axis off

What occurs once we attempt to discover a excessive chroma colour, on the identical hue angle, that’s shiny as a substitute of darkish?

You possibly can can see that the utmost c worth is way decrease for the upper worth of $ L^* $. What does it appear like?

rgb_out = lab2rgb(lch2lab([L c h]));

axis off

Once I was doing these experiments to arrange for this weblog put up, my authentic intent was to only present examples for a few totally different values of h and $ L^* $. However I could not cease! It was an excessive amount of enjoyable, and I stored making an attempt totally different values.

After about quarter-hour or so, I made a decision it will be greatest to jot down some easy loops to generate a comparatively giant variety of $ (L^*,h) $ combos to take a look at. This is the code to generate the excessive c colours for a wide range of $ (L^*,h) $ combos.

rgb = zeros(size(h),size(L),3);

c = maxChromaAtLh(L(q),h(okay));

rgb(okay,q,:) = lab2rgb(lch2lab([L(q) c h(k)]));

And here is the code to view all these colours on a grid, with labeled h and $ L^* $ axes.

rgb2 = reshape(fliplr(rgb),[],3);

p = colorSwatches(rgb2,[length(L) length(h)]);

p.XData = (p.XData – 0.5) * (dh/1.5) + h(1);

p.YData = (p.YData – 0.5) * (dL/1.5) + L(1);

title(“Highest chroma (most saturated) colours for various L* and h values”)

Utility Features

operate [L_min,L_max] = Lrange(a,b)

gamut_mask = all((0 <= rgb) & (rgb <= 1),2);

j = discover(gamut_mask,1,‘first’);

okay = discover(gamut_mask,1,‘final’);

operate x = findNonzeroBoundary(f,x1,x2,abstol)

abstol (1,1) {mustBeFloat} = 1e-4

if (f(x1) == 0) || (f(x2) ~= 0)

error(“Perform should be nonzero at preliminary place to begin and nil at preliminary ending level.”)

if abs(xm – x1) / max(abs(xm),abs(x1)) <= abstol

x = findNonzeroBoundary(f,x1,xm);

x = findNonzeroBoundary(f,xm,x2);



Please enter your comment!
Please enter your name here

Most Popular

Recent Comments