因为需要批量处理图像,而PS好像只能一张张人工操作,想把PS中一系列操作改写成代码。
所以开始探索PS中各个功能背后的原理。记录并分享在这里。
by HPC_ZY
Photoshop的图层选项里有一个图层混合方法,如下图所示。6个模块,27种方式
这里我们将放在下层的图片称为背景(bg),放在上层的图片称为混合图(mix)
注:
1)以下代码均为彩色模式下,对于灰度图可自行推导。
2)以下bg,mix均以double类型输入,计算完毕再将out转为uint8。
3)以下所有方法的描述,均为自己的理解(并非官方定义)。
% 正常
function out = do1_1(bg,mix)
out = mix;
end
% 变暗
function out = do2_1(bg,mix)
R = min(cat(3,bg(:,:,1),mix(:,:,1)),[],3);
G = min(cat(3,bg(:,:,2),mix(:,:,2)),[],3);
B = min(cat(3,bg(:,:,3),mix(:,:,3)),[],3);
out = cat(3,R,G,B);
end
% 正片叠底
function out = do2_2(bg,mix)
out = bg.*mix/255;
end
function out = do2_3(bg,mix)
out = bg-(255-bg).*(255-mix)./(mix+0.0001);
end
注:经过测试发现PS在进行颜色加深时是以uint8进行计算的,所以结果有杂点(可自行测试)
% 线性加深
function out = do2_4(bg,mix)
out = bg+mix-255;
end
% 深色
function out = do2_5(bg,mix)
bgsum = 0.299*bg(:,:,1)+0.587*bg(:,:,2)+0.114*bg(:,:,3);
mixsum = 0.299*mix(:,:,1)+0.587*mix(:,:,2)+0.114*mix(:,:,3);
flag = double(bgsum<mixsum);
out = bg.*flag+mix.*(~flag);
end
% 变亮
function out = do3_1(bg,mix)
R = max(cat(3,bg(:,:,1),mix(:,:,1)),[],3);
G = max(cat(3,bg(:,:,2),mix(:,:,2)),[],3);
B = max(cat(3,bg(:,:,3),mix(:,:,3)),[],3);
out = cat(3,R,G,B);
end
% 滤色
function out = do3_2(bg,mix)
out = 255-(255-bg).*(255-mix)/255;
end
% 颜色减淡
function out = do3_3(bg,mix)
out = bg+bg.*mix./(255.0001-mix);
end
% 线性减淡
function out = do3_4(bg,mix)
out = bg+mix;
end
% 浅色
function out = do3_5(bg,mix)
bgsum = 0.299*bg(:,:,1)+0.587*bg(:,:,2)+0.114*bg(:,:,3);
mixsum = 0.299*mix(:,:,1)+0.587*mix(:,:,2)+0.114*mix(:,:,3);
flag = double(bgsum>mixsum);
out = bg.*flag+mix.*(~flag);
end
% 叠加
function out = do4_1(bg,mix)
out = zeros(size(bg));
idx = bg<128;
out(idx) = bg(idx).*mix(idx)/128;
out(~idx) = 255-(255-bg(~idx)).*(255-mix(~idx))/128;
end
% 柔光
function out = do4_2(bg,mix)
out = zeros(size(bg));
idx = bg<128;
out(idx) = bg(idx)+(2*mix(idx)-255).*(bg(idx)/255-(bg(idx)/255).^2);
out(~idx) = bg(~idx)+(2*mix(~idx)-255).*(sqrt(bg(~idx)/255)-bg(~idx)/255);
end
% 强光
function out = do4_3(bg,mix)
out = zeros(size(bg));
idx = bg<128;
out(idx) = 255-(255-bg(idx)).*(255-mix(idx))/128;
out(~idx) = bg(~idx).*mix(~idx)/128;
end
% 亮光
function out = do4_4(bg,mix)
out = zeros(size(bg));
idx = bg<128;
out(idx) = 255-(255-mix(idx))./(2*bg(idx)+0.0001)*255;
out(~idx) = mix(~idx)./(2*(255-bg(~idx))+0.0001)*255;
end
注:跟PS有一点点出入,待查明原因
function out = do4_5(bg,mix)
out = bg+mix*2-255;
end
% 点光
function out = do4_6(bg,mix)
out = bg;
idx1 = bg<2*mix-255;
idx2 = bg>2*mix;
out(idx1) = 2*mix(idx1)-255;
out(idx2) = 2*mix(idx2);
end
% 实色混合
function out = do4_7(bg,mix)
out = double((bg+mix)>=255)*255;
end
% 差值
function out = do5_1(bg,mix)
out = abs(bg-mix);
end
% 排除
function out = do5_2(bg,mix)
out = bg+mix-bg.*mix/128;
end
% 减去
function out = do5_3(bg,mix)
out = bg-mix;
end
% 划分
function out = do5_4(bg,mix)
out = bg./(mix+0.0001)*255;
end
在这里插入代码片
在这里插入代码片
在这里插入代码片
在这里插入代码片
为了方便使用,写了一个间接调用函数
function out = LayerBlending(bg,mix,mode)
% 判断尺寸
if ~isequal(size(bg),size(mix))
message("图像尺寸不相等")
end
if size(bg,3)~=3
message("图像不是彩色图")
end
% 初始化
bg = double(bg);
mix = double(mix);
switch mode
case 11
out = do1_1(bg,mix);
case 12
out = do1_2(bg,mix);
case 21
out = do2_1(bg,mix);
case 22
out = do2_2(bg,mix);
case 23
out = do2_3(bg,mix);
case 24
out = do2_4(bg,mix);
case 25
out = do2_5(bg,mix);
case 31
out = do3_1(bg,mix);
case 32
out = do3_2(bg,mix);
case 33
out = do3_3(bg,mix);
case 34
out = do3_4(bg,mix);
case 35
out = do3_5(bg,mix);
case 41
out = do4_1(bg,mix);
case 42
out = do4_2(bg,mix);
case 43
out = do4_3(bg,mix);
case 44
out = do4_4(bg,mix);
case 45
out = do4_5(bg,mix);
case 46
out = do4_6(bg,mix);
case 47
out = do4_7(bg,mix);
case 51
out = do5_1(bg,mix);
case 52
out = do5_2(bg,mix);
case 53
out = do5_3(bg,mix);
case 54
out = do5_4(bg,mix);
case 61
out = do6_1(bg,mix);
case 62
out = do6_2(bg,mix);
case 63
out = do6_3(bg,mix);
case 64
out = do6_4(bg,mix);
end
out = uint8(out);
end
使用方法
bg = imread('1.png');
mix = imread('0.png');
out1 = LayerBlending(bg,mix,24); % 线性加深
out2 = LayerBlending(bg,mix,33); % 颜色减淡
out3 = LayerBlending(bg,mix,47); % 实色混合
out4 = LayerBlending(bg,mix,51); % 差值
subplot(231),imshow(bg)
subplot(234),imshow(mix)
subplot(232),imshow(out1)
subplot(233),imshow(out2)
subplot(235),imshow(out3)
subplot(236),imshow(out4)