前言
这里我分享一下加权最小二乘法滤波算法对图像进行滤波处理实现磨皮功能;借助wlsFilter函数在MATLAB中实现该功能
实现思路及函数说明
给定一个输入图像命名INPUT,我们需要得到一张图像命名为OUTPUT,这张图像一方面,它尽可能接近INPUT,同时,除了INPUT中的显着梯度之外,它在任何地方都尽可能平滑。
wlsFilter函数说明
参数 | 说明 |
INPUT | 输入图像(二维、双精度、N×M 矩阵) |
lambda | 数据项和平滑项之间的平衡。 增加 lambda 将产生更平滑的图像。默认值为 1.0 |
alpha | 通过对梯度进行非线性缩放,对亲和力进行一定程度的控制。 增加 alpha 将导致更锐利的保留边缘。 默认值:1.2 |
L | 与源图像相似。 它具备与输入图像INPUT相同的尺寸 |
使用wlsFilter实现磨皮流程:
- 读取RGB图像(自己的人脸);
- 将RGB图像转化为灰度图YCBR;
- YCBR图像数据格式由unit8型转变为double型;
- 获取YCBR矩阵的第三个通道的值记为YCBR_B;
- 计算YCBR_B图像中的最大值(由于计算出来的是一个数组,这里可以求该数组的最值OR均值),记为:MAX_YCBR_B;
- 合理设置wlsFilter参数并计算出结果转uint8型数据便于显示(构造方式:YCBR_B,lambda,alpha,YCBR_B./MAX_YCBR_B);
- 此时将第六步中数据转化为RGB进行显示(之前它为ycbr格式的图像)记为WLS_I。
结果展示
左侧为原图(RGB图)、左侧为磨皮后的图像(WLS_I图)
从结果上来看咱们磨皮的目的达到了,但是不够那么自然,像一个PS新手一般进行磨皮,针对此现象我们可以对此进行改进。
改进磨皮效果
最终的效果目的为:成果 + 显的自然
实现流程:
8. 将磨皮后的图像(WLS_I)转换为double型
9. (磨皮后的图像 + 原图 )./(YCBR_B图像中的最大值) = (WLS_I + RGB)./(MAX_YCBR_B)
10 输出改进后的图
改进后图像:
demo部分
定义函数wlsFilter:
function OUTPUT = wlsFilter(INPUT, lambda, alpha, L) if(~exist('L', 'var')), L = log(IN+eps); end if(~exist('alpha', 'var')), alpha = 1.2; end if(~exist('lambda', 'var')), lambda = 1; end smallNum = 0.0001; [r,c] = size(IN); k = r*c; % Compute affinities between adjacent pixels based on gradients of L dy = diff(L, 1, 1); dy = -lambda./(abs(dy).^alpha + smallNum); dy = padarray(dy, [1 0], 'post'); dy = dy(:); dx = diff(L, 1, 2); dx = -lambda./(abs(dx).^alpha + smallNum); dx = padarray(dx, [0 1], 'post'); dx = dx(:); % Construct a five-point spatially inhomogeneous Laplacian matrix B(:,1) = dx; B(:,2) = dy; d = [-r,-1]; A = spdiags(B,d,k,k); e = dx; w = padarray(dx, r, 'pre'); w = w(1:end-r); s = dy; n = padarray(dy, 1, 'pre'); n = n(1:end-1); D = 1-(e+w+s+n); A = A + A' + spdiags(D, 0, k, k); % Solve OUT = A\IN(:); OUT = reshape(OUT, r, c);
主程序调用:
RGB = imread('test.jpg'); YCBRC = rgb2ycbcr(RGB); I = double(YCBRC); YCBR_B = I(:,:,1); MAX_YCBR_B = max(max(YCBR_B)) lambda=0.001; alpha=20; OutPut_YCBRC = uint8(wlsFilter(YCBR_B, lambda,alpha,YCBR_B/MAX_YCBR_B)); OutPut_RGB=ycbcr2rgb(cat(3,diff,YCBRC (:,:,2:3))); subplot(1,2,1) imshow(RGB); subplot(1,2,2) imshow(OutPut_RGB); C_OutPut = uint8((double(OutPut_RGB)+double(RGB))/2); subplot(1,2,3) imshow(C_OutPut);