| % Create the color enhancement look-up table and write it to |
| % file colorEnhancementTable.cpp. Copy contents of that file into |
| % the source file for the color enhancement function. |
| |
| clear |
| close all |
| |
| |
| % First, define the color enhancement in a normalized domain |
| |
| % Compander function is defined in three radial zones. |
| % 1. From 0 to radius r0, the compander function |
| % is a second-order polynomial intersecting the points (0,0) |
| % and (r0, r0), and with a slope B in (0,0). |
| % 2. From r0 to r1, the compander is a third-order polynomial |
| % intersecting the points (r0, r0) and (r1, r1), and with the |
| % same slope as the first part in the point (r0, r0) and slope |
| % equal to 1 in (r1, r1). |
| % 3. For radii larger than r1, the compander function is the |
| % unity scale function (no scaling at all). |
| |
| r0=0.07; % Dead zone radius (must be > 0) |
| r1=0.6; % Enhancement zone radius (must be > r0 and < 1) |
| B=0.2; % initial slope of compander function (between 0 and 1) |
| |
| x0=linspace(0,r0).'; % zone 1 |
| x1=linspace(r0,r1).'; % zone 2 |
| x2=linspace(r1,1).'; % zone 3 |
| |
| A=(1-B)/r0; |
| f0=A*x0.^2+B*x0; % compander function in zone 1 |
| |
| % equation system for finding second zone parameters |
| M=[r0^3 r0^2 r0 1; |
| 3*r0^2 2*r0 1 0; |
| 3*r1^2 2*r1 1 0; |
| r1^3 r1^2 r1 1]; |
| m=[A*r0^2+B*r0; 2*A*r0+B; 1; r1]; |
| % solve equations |
| theta=M\m; |
| |
| % compander function in zone 1 |
| f1=[x1.^3 x1.^2 x1 ones(size(x1))]*theta; |
| |
| x=[x0; x1; x2]; |
| f=[f0; f1; x2]; |
| |
| % plot it |
| figure(1) |
| plot(x,f,x,x,':') |
| xlabel('Normalized radius') |
| ylabel('Modified radius') |
| |
| |
| % Now, create the look-up table in the integer color space |
| [U,V]=meshgrid(0:255, 0:255); % U-V space |
| U0=U; |
| V0=V; |
| |
| % Conversion matrix from normalized YUV to RGB |
| T=[1 0 1.13983; 1 -0.39465 -0.58060; 1 2.03211 0]; |
| Ylum=0.5; |
| |
| figure(2) |
| Z(:,:,1)=Ylum + (U-127)/256*T(1,2) + (V-127)/256*T(1,3); |
| Z(:,:,2)=Ylum + (U-127)/256*T(2,2) + (V-127)/256*T(2,3); |
| Z(:,:,3)=Ylum + (U-127)/256*T(3,2) + (V-127)/256*T(3,3); |
| Z=max(Z,0); |
| Z=min(Z,1); |
| subplot(121) |
| image(Z); |
| axis square |
| axis off |
| set(gcf,'color','k') |
| |
| R = sqrt((U-127).^2 + (V-127).^2); |
| Rnorm = R/127; |
| RnormMod = Rnorm; |
| RnormMod(RnormMod==0)=1; % avoid division with zero |
| |
| % find indices to pixels in dead-zone (zone 1) |
| ix=find(Rnorm<=r0); |
| scaleMatrix = (A*Rnorm(ix).^2 + B*Rnorm(ix))./RnormMod(ix); |
| U(ix)=(U(ix)-127).*scaleMatrix+127; |
| V(ix)=(V(ix)-127).*scaleMatrix+127; |
| |
| % find indices to pixels in zone 2 |
| ix=find(Rnorm>r0 & Rnorm<=r1); |
| scaleMatrix = (theta(1)*Rnorm(ix).^3 + theta(2)*Rnorm(ix).^2 + ... |
| theta(3)*Rnorm(ix) + theta(4)) ./ RnormMod(ix); |
| U(ix)=(U(ix)-127).*scaleMatrix + 127; |
| V(ix)=(V(ix)-127).*scaleMatrix + 127; |
| |
| % round to integer values and saturate |
| U=round(U); |
| V=round(V); |
| U=max(min(U,255),0); |
| V=max(min(V,255),0); |
| |
| Z(:,:,1)=Ylum + (U-127)/256*T(1,2) + (V-127)/256*T(1,3); |
| Z(:,:,2)=Ylum + (U-127)/256*T(2,2) + (V-127)/256*T(2,3); |
| Z(:,:,3)=Ylum + (U-127)/256*T(3,2) + (V-127)/256*T(3,3); |
| Z=max(Z,0); |
| Z=min(Z,1); |
| subplot(122) |
| image(Z); |
| axis square |
| axis off |
| |
| figure(3) |
| subplot(121) |
| mesh(U-U0) |
| subplot(122) |
| mesh(V-V0) |
| |
| |
| |
| % Last, write to file |
| % Write only one matrix, since U=V' |
| |
| fid = fopen('../out/Debug/colorEnhancementTable.h','wt'); |
| if fid==-1 |
| error('Cannot open file colorEnhancementTable.cpp'); |
| end |
| |
| fprintf(fid,'//colorEnhancementTable.h\n\n'); |
| fprintf(fid,'//Copy the constant table to the appropriate header file.\n\n'); |
| |
| fprintf(fid,'//Table created with Matlab script createTable.m\n\n'); |
| fprintf(fid,'//Usage:\n'); |
| fprintf(fid,'// Umod=colorTable[U][V]\n'); |
| fprintf(fid,'// Vmod=colorTable[V][U]\n'); |
| |
| fprintf(fid,'static unsigned char colorTable[%i][%i] = {\n', size(U,1), size(U,2)); |
| |
| for u=1:size(U,2) |
| fprintf(fid,' {%i', U(1,u)); |
| for v=2:size(U,1) |
| fprintf(fid,', %i', U(v,u)); |
| end |
| fprintf(fid,'}'); |
| if u<size(U,2) |
| fprintf(fid,','); |
| end |
| fprintf(fid,'\n'); |
| end |
| fprintf(fid,'};\n\n'); |
| fclose(fid); |
| fprintf('done'); |
| |
| |
| answ=input('Create test vector (takes some time...)? y/n : ','s'); |
| if answ ~= 'y' |
| return |
| end |
| |
| % Also, create test vectors |
| |
| % Read test file foreman.yuv |
| fprintf('Reading test file...') |
| [y,u,v]=readYUV420file('../out/Debug/testFiles/foreman_cif.yuv',352,288); |
| fprintf(' done\n'); |
| unew=uint8(zeros(size(u))); |
| vnew=uint8(zeros(size(v))); |
| |
| % traverse all frames |
| for k=1:size(y,3) |
| fprintf('Frame %i\n', k); |
| for r=1:size(u,1) |
| for c=1:size(u,2) |
| unew(r,c,k) = uint8(U(double(v(r,c,k))+1, double(u(r,c,k))+1)); |
| vnew(r,c,k) = uint8(V(double(v(r,c,k))+1, double(u(r,c,k))+1)); |
| end |
| end |
| end |
| |
| fprintf('\nWriting modified test file...') |
| writeYUV420file('../out/Debug/foremanColorEnhanced.yuv',y,unew,vnew); |
| fprintf(' done\n'); |