PS图层混合模式的MATLAB实现
- 一、基本介绍
- 二、算法
- 1. 组合模式(正常、溶解)
- 2. 加深混合模式(变暗、正片叠底、颜色加深、线性加深,深色)
- 3. 减淡混合模式(变亮、滤色、颜色减淡、线性减淡,浅色)
- 4. 对比混合模式(叠加、柔光、强光、亮光、线性光、点光、实色混合)
- 5. 比较混合模式(差值、排除、减去、划分)
- 6. 色彩混合模式(色相、饱和度、颜色、亮度)
- 三、调用实例
- 其他
因为需要批量处理图像,而PS好像只能一张张人工操作,想把PS中一系列操作改写成代码。
所以开始探索PS中各个功能背后的原理。记录并分享在这里。
by HPC_ZY
一、基本介绍
Photoshop的图层选项里有一个图层混合方法,如下图所示。6个模块,27种方式
二、算法
这里我们将放在下层的图片称为背景(bg),放在上层的图片称为混合图(mix)
注:
1)以下代码均为彩色模式下,对于灰度图可自行推导。
2)以下bg,mix均以double类型输入,计算完毕再将out转为uint8。
3)以下所有方法的描述,均为自己的理解(并非官方定义)。
1. 组合模式(正常、溶解)
- 正常:mix完全覆盖bg
o u t = b g out = bg out=bg
% 正常
function out = do1_1(bg,mix)
out = mix;
end
- 溶解:还没搞明白怎么回事……
2. 加深混合模式(变暗、正片叠底、颜色加深、线性加深,深色)
- 变暗:取各分量最小值
o u t = m i n ( b g , m i x ) out = min(bg,mix) out=min(bg,mix)
% 变暗
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
- 正片叠底:灰度乘积后,调整至0~255范围
o u t = b g ∗ m i x 255 out = \frac{bg*mix}{255} out=255bg∗mix
% 正片叠底
function out = do2_2(bg,mix)
out = bg.*mix/255;
end
- 颜色加深:
o u t = b g − ( 255 − b g ) ( 255 − m i x ) m i x ; out = bg-\frac{(255-bg)(255-mix)}{mix}; out=bg−mix(255−bg)(255−mix);
function out = do2_3(bg,mix)
out = bg-(255-bg).*(255-mix)./(mix+0.0001);
end
注:经过测试发现PS在进行颜色加深时是以uint8进行计算的,所以结果有杂点(可自行测试)
- 线性加深:减去mix的反色
o u t = b g − ( 255 − m i x ) out = bg-(255-mix) out=bg−(255−mix)
% 线性加深
function out = do2_4(bg,mix)
out = bg+mix-255;
end
- 深色:保留总体亮度更低的点
o u t = { b g , I b g < I m i x m i x , I b g > I m i x out=\left\{ \begin{aligned} bg & ,& I_{bg}<I_{mix} \\ mix &, &I_{bg}>I_{mix} \end{aligned} \right. out={bgmix,,Ibg<ImixIbg>Imix
% 深色
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
3. 减淡混合模式(变亮、滤色、颜色减淡、线性减淡,浅色)
- 变亮:取各分量最大值
o u t = m a x ( b g , m i x ) out = max(bg,mix) out=max(bg,mix)
% 变亮
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
- 滤色:
o u t = 255 − ( 255 − b g ) ∗ ( 255 − m i x ) 255 ; out = 255-\frac{(255-bg)*(255-mix)}{255}; out=255−255(255−bg)∗(255−mix);
% 滤色
function out = do3_2(bg,mix)
out = 255-(255-bg).*(255-mix)/255;
end
- 颜色减淡:根据mix灰度,增加bg的亮度
o u t = b g + b g ∗ m i x 255 − m i x ; out = bg+\frac{bg*mix}{255-mix}; out=bg+255−mixbg∗mix;
% 颜色减淡
function out = do3_3(bg,mix)
out = bg+bg.*mix./(255.0001-mix);
end
- 线性减淡:直接累加
o u t = b g + m i x out = bg+mix out=bg+mix
% 线性减淡
function out = do3_4(bg,mix)
out = bg+mix;
end
- 浅色:保留总体亮度更高的点
o u t = { b g , I b g > I m i x m i x , I b g < I m i x out=\left\{ \begin{aligned} bg & ,& I_{bg}>I_{mix} \\ mix &, &I_{bg}<I_{mix} \end{aligned} \right. out={bgmix,,Ibg>ImixIbg<Imix
注:这里的 I I I指亮度
% 浅色
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
4. 对比混合模式(叠加、柔光、强光、亮光、线性光、点光、实色混合)
- 叠加:
o u t = { b g ∗ m i x 128 , b g < 128 255 − ( 255 − b g ) ( 255 − m i x ) 128 , b g ≥ 128 out=\left\{ \begin{aligned} \frac{bg*mix}{128} & ,& bg<128 \\ 255-\frac{(255-bg)(255-mix)}{128} &, & bg\geq128 \end{aligned} \right. out=⎩⎪⎪⎨⎪⎪⎧128bg∗mix255−128(255−bg)(255−mix),,bg<128bg≥128
% 叠加
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
- 柔光:
o u t = { b g + ( 2 ∗ m i x − 255 ) ∗ ( b g 255 − ( b g 255 ) 2 ) , b g < 128 b g + ( 2 ∗ m i x − 255 ) ∗ ( b g 255 − b g 255 ) , b g ≥ 128 out=\left\{ \begin{aligned} bg+(2*mix-255)*(\frac{bg}{255}-(\frac{bg}{255})^2) & ,& bg<128 \\ bg+(2*mix-255)*(\sqrt{\frac{bg}{255}}-\frac{bg}{255}) &, & bg\geq128 \end{aligned} \right. out=⎩⎪⎪⎨⎪⎪⎧bg+(2∗mix−255)∗(255bg−(255bg)2)bg+(2∗mix−255)∗(255bg −255bg),,bg<128bg≥128
% 柔光
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
- 强光:
o u t = { 255 − ( 255 − b g ) ( 255 − m i x ) , b g < 128 b g ∗ m i x 128 , b g ≥ 128 out=\left\{ \begin{aligned} 255-(255-bg)(255-mix) & ,& bg<128 \\ \frac{bg*mix}{128}&, & bg\geq128 \end{aligned} \right. out=⎩⎨⎧255−(255−bg)(255−mix)128bg∗mix,,bg<128bg≥128
% 强光
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
- 亮光:
o u t = { 255 ∗ ( 1 − 255 − m i x 2 ∗ b g ) , b g < 128 255 ∗ m i x 2 ∗ ( 255 − b g ) , b g ≥ 128 out=\left\{ \begin{aligned} 255*(1-\frac{255-mix}{2*bg}) & ,& bg<128 \\ 255*\frac{mix}{2*(255-bg)}&, & bg\geq128 \end{aligned} \right. out=⎩⎪⎪⎨⎪⎪⎧255∗(1−2∗bg255−mix)255∗2∗(255−bg)mix,,bg<128bg≥128
% 亮光
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有一点点出入,待查明原因
- 线性光:线性加深+线性减淡
o u t = b g + m i x − ( 255 − m i x ) out= bg+mix-(255-mix) out=bg+mix−(255−mix)
function out = do4_5(bg,mix)
out = bg+mix*2-255;
end
- 点光:以mix为标准,将bg太亮的调暗,太暗的调亮
o u t = { 2 ∗ m i x − 255 , b g < 2 ∗ m i n − 255 2 ∗ m i x , b g > 2 ∗ m i x b g , o t h e r out=\left\{ \begin{aligned} 2*mix-255 & ,& bg<2*min-255 \\ 2*mix &, & bg>2*mix \\ bg &,& other \end{aligned} \right. out=⎩⎪⎨⎪⎧2∗mix−2552∗mixbg,,,bg<2∗min−255bg>2∗mixother
% 点光
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
- 实色混合:各通道根据累加和进行二值化
o u t = { 255 , b g + m i x > = 255 0 , b g + m i x < 255 out=\left\{ \begin{aligned} 255 & ,& bg+mix>=255 \\ 0 &, & bg+mix<255 \end{aligned} \right. out={2550,,bg+mix>=255bg+mix<255
% 实色混合
function out = do4_7(bg,mix)
out = double((bg+mix)>=255)*255;
end
5. 比较混合模式(差值、排除、减去、划分)
- 差值:两图的绝对差值
o u t = ∣ b g − m i x ∣ out = |bg-mix| out=∣bg−mix∣
% 差值
function out = do5_1(bg,mix)
out = abs(bg-mix);
end
- 排除:
o u t = b g + m i x − b g ∗ m i x 128 out = bg+mix-bg*\frac{mix}{128} out=bg+mix−bg∗128mix
% 排除
function out = do5_2(bg,mix)
out = bg+mix-bg.*mix/128;
end
- 减去:直接减去mix,负数取0。
o u t = m a x ( b g − m i x , 0 ) out = max(bg-mix,0) out=max(bg−mix,0)
% 减去
function out = do5_3(bg,mix)
out = bg-mix;
end
- 划分:根据mix的值,调亮bg
- o u t = { 255 , m i x = 0 m i n ( b g ∗ 255 m i x , 255 ) , m i x > 0 out=\left\{ \begin{aligned} 255 & ,& mix=0 \\ min(bg*\frac{255}{mix}, 255) &, & mix>0 \end{aligned} \right. out=⎩⎨⎧255min(bg∗mix255,255),,mix=0mix>0
% 划分
function out = do5_4(bg,mix)
out = bg./(mix+0.0001)*255;
end
6. 色彩混合模式(色相、饱和度、颜色、亮度)
- 色相
在这里插入代码片
- 饱和度
在这里插入代码片
- 颜色
在这里插入代码片
- 亮度
在这里插入代码片
三、调用实例
为了方便使用,写了一个间接调用函数
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)
其他
- 有些还没完全搞清楚,待续
- 以上所有内容(公式、代码),都是针对uint8格式的图像写的。
- 代码里有些地方分母+0.0001是为了避免为0带来计算问题
- 可以用PS试试,看结果是否一致。