Bootstrap

基于盒式滤波的初步美颜功能实现

本项目实现了一个图像去噪和人脸美颜的完整流程,利用了积分图来加速局部统计量的计算,结合了盒式滤波和平滑处理,使得图像中的噪声和瑕疵得以减轻。每个函数都有特定的用途,从图像预处理、局部统计信息计算、去噪到人脸掩膜的生成和应用。

一、基础实现方式

1.初始化读取图像

clear all; close all; clc;
img = imread('xxx.jpg');   //(xxx.jpg为美颜的目标图像) 

clear all:清除工作空间中的所有变量,close all:关闭所有图形窗口。 

clc:清除命令窗口。imread:读取指定路径的图像文件,并存储在变量 img 中。

2.添加高斯噪声并再次读取图像

noisyImg = imnoise(img, 'gaussian', 0, 0.01);
noisyImg = imread('xxx.jpg'); //此处图像和上部分代码相同

imnoise(img, 'gaussian', 0, 0.01):向图像添加高斯噪声,均值为0,方差为0.01。

noisyImg = imread(...):重新读取图像,覆盖了前面添加噪声的操作。

3.设置去噪参数和去噪

r = 10;
level = 5;
sigma = 10 + level^2;
dnImg = denoiseBasedLocalStat(noisyImg, r, sigma);

r = 10:设置局部区域的半径为10

level = 5:设置去噪级别为5。

sigma = 10 + level^2:计算噪声的标准差参数。 

dnImg = denoiseBasedLocalStat(...):调用函数 denoiseBasedLocalStat 进行图像去噪。

4.显示图像

figure, imshow(noisyImg);
figure, imshow(dnImg);

 figure:创建一个新的图形窗口

imshow:显示图像。

5.生成人脸掩膜并合并图像

mask = faceMask(noisyImg, 5);
w = 0.5;
mergedImg = uint8(double(noisyImg) .* (1 - w * mask) + w * double(dnImg) .* mask);
figure, imshow(mergedImg);

mask = faceMask(noisyImg, 5):调用函数 faceMask 生成人脸掩膜。

w = 0.5:设置权重参数为0.5。

mergedImg = ...:根据掩膜将去噪图像与原始图像合并。

imshow:显示合并后的图像。

6.去噪函数:denoiseBasedLocalStat

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

该函数根据图像的颜色通道数选择处理方法

灰度图像:直接调用 denoiseBasedLocalStat_gray 进行处理。

彩色图像:转换为YCrCb颜色空间,只处理亮度通道,然后再转换回RGB

7.灰度图像去噪函数:denoiseBasedLocalStat_gray

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

该函数对灰度图像进行基于局部统计信息的去噪。

padarray:对图像进行边界填充。

intergalMap:计算积分图,用于快速计算局部区域的和与平方和。

循环部分:对每个像素计算局部均值和方差,并根据自适应滤波公式进行去噪。

8.积分图函数:intergalMap

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

该函数生成积分图,用于快速计算任意矩形区域的和与平方和。

积分图计算:通过递推公式计算积分图,方便快速获取局部区域的和与平方和 

9.人脸掩膜生成函数:faceMask

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

该函数生成人脸掩膜。

根据颜色阈值生成初步掩膜:将满足条件的像素标记为1,其余为0。

myBoxFilt:对初步掩膜进行盒式滤波。

掩膜扩展到三个通道:使掩膜适用于彩色图像的三个通道。

10.盒式滤波函数:myBoxFilt

function fImg = myBoxFilt(img, r)
    paddedImg = padarray(img, [r r], 'symmetric', 'both');
    [Yim, ~] = intergalMap(paddedImg);
    fImg = zeros(size(img));
    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

该函数对图像进行盒式滤波。

对图像进行边界填充

使用积分图计算局部区域的均值:通过滑动窗口计算局部均值,生成平滑后的图像。 

二、什么是盒式滤波

盒式滤波(Box Filter)是一种常见的图像平滑滤波器,其原理是用一个固定大小的矩形窗口在图像上滑动,窗口内的所有像素值取平均值,然后用这个平均值替代窗口中心的像素值。盒式滤波是一种线性平滑滤波器,能够有效地减少图像中的随机噪声,虽然会导致一定程度的边缘模糊。

下面我们具体解释一下  盒式滤波函数:myBoxFil

1.图像填充

paddedImg = padarray(img, [r r], 'symmetric', 'both');

padarray:对图像进行边界填充,填充值采用对称方式。这样做的目的是为了在计算边界像素的滤波时,不会因为缺少周围像素值而出错。填充的大小为 r,即窗口半径。 

2.生成积分图

[Yim, ~] = intergalMap(paddedImg);

调用 intergalMap 函数生成积分图。积分图用于快速计算任意矩形区域的像素和

3.初始化输出图像

fImg = zeros(size(img));

初始化一个与输入图像大小相同的矩阵 fImg,用于存储滤波后的图像

 4.滑动窗口计算局部均值

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

 遍历填充后的图像的每个像素(去除填充区域)。

使用积分图快速计算窗口内像素的和。公式如下: 

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);


//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;

 5.总结

盒式滤波的关键在于利用积分图(也称为累积分布图)快速计算局部区域的和。积分图的好处在于,无论窗口的大小如何,计算区域和的时间复杂度始终是常数时间O(1),这极大地提高了计算效率。在您的代码中,myBoxFilt 函数使用积分图实现了高效的盒式滤波,而 intergalMap 函数负责生成所需的积分图和平方积分图。

三、什么是高斯滤波和高斯噪声

既然前文提到了高斯噪声的添加,那么现在来理解一下高斯噪声和高斯滤波

1)高斯滤波

1.高斯滤波原理

高斯滤波器使用一个高斯函数的加权窗口对图像进行平滑处理。它可以有效地减少高频噪声,同时保留低频信号。

2.代码实现
function gaussianFilteredImg = gaussianFilter(img, sigma)
    % 创建高斯滤波器
    kernelSize = 2 * ceil(3 * sigma) + 1;
    h = fspecial('gaussian', kernelSize, sigma);
    
    % 对图像进行滤波
    gaussianFilteredImg = imfilter(img, h, 'symmetric');
end

% 示例使用
img = imread('C:\Users\27660\Desktop\download.jpg');
sigma = 2;
gaussianFilteredImg = gaussianFilter(img, sigma);
figure, imshow(gaussianFilteredImg);

1)高斯噪声

1.高斯噪声定义

高斯噪声(Gaussian noise),也称为正态噪声(Normal noise),是一种常见的随机噪声,其概率密度函数遵循正态分布,即高斯分布。它常用来模拟实际图像采集过程中产生的噪声,尤其是那些由电子设备(如传感器和放大器)引起的噪声。

2.高斯噪声的特性

概率密度函数:高斯噪声的概率密度函数由均值和标准差两个参数确定,数学表达式如下:

其中,μ\muμ 是均值, σ\sigmaσ 是标准差。

零均值:在许多实际应用中,高斯噪声常假设为零均值( μ=0\mu = 0μ=0 ),这表示噪声值在正负两个方向上均匀分布。

独立性:高斯噪声通常假设为独立的,即每个像素的噪声值相互独立,不受其他像素噪声值的影响。

3.高斯噪声的生成

在图像处理中,可以通过添加高斯噪声来模拟图像的噪声污染。以下是 MATLAB 中添加高斯噪声的示例代码:

% 读取图像
img = imread('xxx.jpg');

% 将图像转换为灰度图像(可选)
grayImg = rgb2gray(img);

% 添加高斯噪声
noisyImg = imnoise(grayImg, 'gaussian', 0, 0.01);

% 显示原始图像和添加噪声后的图像
figure, imshow(grayImg), title('Original Image');
figure, imshow(noisyImg), title('Noisy Image (Gaussian Noise)');

四、其他的滤波方式

1)中值滤波 (Median Filtering)

1.原理

中值滤波使用一个窗口内像素的中值来替代中心像素值。它对椒盐噪声(即极端噪声)特别有效。

2.代码实现
function medianFilteredImg = medianFilter(img, filterSize)
    % 对图像进行中值滤波
    medianFilteredImg = medfilt2(img, [filterSize filterSize]);
end

% 示例使用
img = imread('C:\Users\27660\Desktop\download.jpg');
filterSize = 3;
medianFilteredImg = medianFilter(rgb2gray(img), filterSize);
figure, imshow(medianFilteredImg);

 2)双边滤波 (Bilateral Filtering)

1.原理

双边滤波器结合了空域和颜色域的信息进行滤波,既能平滑图像,又能保留边缘细节。

2.代码实现
function bilateralFilteredImg = bilateralFilter(img, sigma_spatial, sigma_range)
    % 双边滤波的实现
    img = double(img) / 255.0;
    w = 5; % 窗口半径
    [X, Y] = meshgrid(-w:w, -w:w);
    spatialKernel = exp(-(X.^2 + Y.^2) / (2 * sigma_spatial^2));
    
    % 初始化输出图像
    bilateralFilteredImg = zeros(size(img));
    
    for i = 1:size(img, 1)
        for j = 1:size(img, 2)
            % 提取当前像素的局部区域
            iMin = max(i - w, 1);
            iMax = min(i + w, size(img, 1));
            jMin = max(j - w, 1);
            jMax = min(j + w, size(img, 2));
            
            region = img(iMin:iMax, jMin:jMax, :);
            
            % 计算颜色权重
            colorKernel = exp(-sum((region - img(i, j, :)).^2, 3) / (2 * sigma_range^2));
            
            % 计算总权重
            combinedKernel = spatialKernel((iMin:iMax) - i + w + 1, (jMin:jMax) - j + w + 1) .* colorKernel;
            
            % 归一化
            normalizationFactor = sum(combinedKernel(:));
            
            % 计算滤波后的值
            bilateralFilteredImg(i, j, :) = sum(sum(region .* combinedKernel, 1), 2) / normalizationFactor;
        end
    end
    
    bilateralFilteredImg = uint8(bilateralFilteredImg * 255);
end

% 示例使用
img = imread('xxx.jpg');
sigma_spatial = 2;
sigma_range = 0.1;
bilateralFilteredImg = bilateralFilter(img, sigma_spatial, sigma_range);
figure, imshow(bilateralFilteredImg);

;