下午看到讲局部统计信息用于人脸磨皮的一篇文章(地址https://www.cnblogs.com/Imageshop/p/4679065.html),比较感兴趣,就动手实现了一下。基于局部均方差去噪的原理不难,就是拿窗口内的均方差去调制权重,对窗口内均值与原始值进行加权。废话就不多说了,还是直接上代码贴图啦(随意设的参数,读者可自己调参获得更好的效果)。
代码:
clear all;close all;clc % img=imread('parrot.png'); % noisyImg=imnoise(img,'gaussian',0,0.01); noisyImg=imread('test.jpg'); r=10; level=5; sigma=10+level^2; dnImg=denoiseBasedLocalStat(noisyImg,r,sigma); figure,imshow(noisyImg); figure,imshow(dnImg); mask=faceMask(noisyImg,5); figure,imshow(mask); w=0.5; mergedImg=uint8(double(noisyImg).*(1-w*mask)+w*double(dnImg).*mask); figure,imshow(mergedImg); function dnImg = denoiseBasedLocalStat(img,r,sigma) % 基于局部统计信息的图像滤波去噪 if size(img,3)==1 img=double(img); dnImg=denoiseBasedLocalStat_gray(img,r,sigma); dnImg=uint8(dnImg); end if size(img,3)==3 ycc=rgb2ycbcr(img); y=ycc(:,:,1); dnY=denoiseBasedLocalStat_gray(double(y),r,sigma); ycc(:,:,1)=uint8(dnY); dnImg=ycbcr2rgb(ycc); end end function dnImg=denoiseBasedLocalStat_gray(img,r,sigma) % 基于局部统计信息的灰度图像滤波去噪 dnImg=zeros(size(img)); img=double(img); paddedImg=padarray(img,[r,r],'symmetric','both'); [Yim,YYim]=intergalMap(paddedImg); for i=r+1:size(paddedImg,1)-r for j=r+1:size(paddedImg,2)-r rectSum=Yim(i+r+1,j+r+1)+Yim(i-r,j-r)-Yim(i-r,j+r+1)-Yim(i+r+1,j-r); rectSquareSum=YYim(i+r+1,j+r+1)+YYim(i-r,j-r)-YYim(i-r,j+r+1)-YYim(i+r+1,j-r); num=(2*r+1)^2; avg=rectSum/num; var=rectSquareSum/num-avg^2; k=var/(var+sigma^2); dnImg(i-r,j-r)=(1-k)*avg+k*img(i-r,j-r); end end end function [Yim,YYim]=intergalMap(img) % 生成积分图 paddedImg=padarray(img,[1 1],0,'pre'); Yim=zeros(size(paddedImg)); YYim=Yim; for i=2:size(paddedImg,1) for j=2:size(paddedImg,2) Yim(i,j)=Yim(i,j-1)+Yim(i-1,j)-Yim(i-1,j-1)+paddedImg(i,j); YYim(i,j)=YYim(i,j-1)+YYim(i-1,j)-YYim(i-1,j-1)+paddedImg(i,j)^2; end end end function mask=faceMask(img,r) % 人脸掩模 mask=zeros(size(img,1),size(img,2)); mask(img(:,:,1)>20 & img(:,:,2)>40 & img(:,:,3)>50)=1; mask=myBoxFilt(mask,r); mask=mask(:,:,ones(1,3)); end function fImg=myBoxFilt(img,r) % 盒式滤波 paddedImg=padarray(img,[r r],'symmetric','both'); [Yim,~]=intergalMap(paddedImg); for i=r+1:size(paddedImg,1)-r for j=r+1:size(paddedImg,2)-r rectSum=Yim(i+r+1,j+r+1)+Yim(i-r,j-r)-Yim(i-r,j+r+1)-Yim(i+r+1,j-r); avg=rectSum/(2*r+1)^2; fImg(i-r,j-r)=avg; end end end
原图:
滤波结果:
盒式滤波后的脸部掩模:
掩模遮罩下的融合结果: