Here:
% inputs
inpict = imread('peppers.png');
invec = linspace(0,1,100); % for creating line plot
% k is [alpha beta gamma]
% but calling things gamma is only going to create confusion
% this vector can be variable-length
% breakpoints will be spaced uniformly on x
k = [0.5 1 0.5];
% process things
outvec = kcurves(invec,k);
inpict = im2double(inpict);
outpict = kcurves(inpict,k);
outpict = im2uint8(outpict);
% plot stuff
imshow(outpict)
figure
plot(invec,outvec)
axis square
grid on
xlim([0 1])
ylim([0 1])
xlabel('input')
ylabel('output')
This seems like a cumbersome way of parameterizing the task. You have control over slopes, but usually levels are at least as important. The fact that the curve is pinned at 0 seems limiting.
It almost seems more convenient to just pick the breakpoints directly. Any set of points (see xx and yy) on this unit interval can be defined to create an arbitrary curve. Also, the interpolation options available with interp1() means that it can be a smooth curve. Using a piecewise-linear curve is a good way to create noticeable banding artifacts in local contrast.
If all that's desired is a simplified means to trade midtone contrast for highlight/shadow contrast, a single-parameter method might be:
% a test vector
invec = linspace(0,1,100);
% process
kcont = 2; % contrast factor
outvec = stretchcurve(invec,kcont);
% plot things
plot(invec,outvec)
axis square
grid on
xlim([0 1])
ylim([0 1])
xlabel('input')
ylabel('output')
Much like a simple gamma adjustment, this method preserves black and white. This is the same as the 'contrast' term used in MIMT imlnc() (on the File Exchange).
% the support functions %%%%%%%%%%%%%%%%%%%%%%%%
function outpict = kcurves(inpict,k)
% input breakpoints
xx = linspace(0,1,numel(k)+1);
% output breakpoints
va = xx(2)*k(1);
vb = (xx(3)-xx(2))*k(2) + va;
vc = (xx(4)-xx(3))*k(3) + vb;
yy = [0 va vb vc];
outpict = interp1(xx,yy,inpict,'linear');
end
function outpict = stretchcurve(inpict,kc)
if kc == 1
outpict = inpict;
return;
end
c = 0.5; % input pivot point
mk = abs(kc) < 1;
mc = c < 0.5;
if ~xor(mk,mc)
pp = kc; kk = kc*c/(1-c);
else
kk = kc; pp = (1-c)*kc/c;
end
hi = inpict > c; lo = ~hi;
outpict = zeros(size(inpict));
outpict(lo) = 0.5*((1/c)*inpict(lo)).^kk;
outpict(hi) = 1-0.5*((1-inpict(hi))*(1/(1-c))).^pp;
end