图像基础滤波处理

opencv滤波函数介绍:

1. 图像滤波介绍

图像滤波,在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可或缺的操作,滤波处理效果的好坏直接影响到后续图像处理和分析的有效性和可靠性。图像滤波也称为图像的平滑化或者图像模糊。

滤波的目的:一是消除图像中混入的噪声,二是为图像识别抽取出图像特征
滤波的要求:不能损坏图像轮廓和边缘,图像视觉效果应当更好;

平滑滤波是低频增强的空间域滤波技术,目的有二:模糊消除噪音

空间域的平滑滤波一般采用简单的平均值法处理,即求邻近像素的平均亮度值(均值滤波)。邻域的大小与平滑的效果直接相关,邻域越大,平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需要合理选择邻域的大小。

关于滤波器,可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

2. 常用的图像滤波方法

图像滤波处理有:

  • 线性滤波:均值滤波、高斯滤波、盒式滤波。
  • 非线性滤波:中值滤波、双边滤波。

均值滤波:以当前像素为中心,取周围n * n个区域像素的均值作为当前像素的值;
高斯滤波:以当前像素为中心,取周围n * n个区域像素,按照与当前像素的距离按照高斯分布作为权重,计算后的值作为当前像素的值;
盒式滤波:以当前像素为中心,取周围n * n个区域像素,通过计算后作为当前像素的值;

中值滤波:以当前像素为中心,取周围n * n个区域像素的中值作为当前像素的值;
双边滤波:以当前像素为中心,取周围n * n个区域的像素,既考虑像素值的权重,也考虑与当前像素的距离的权重,计算后的值作为当前像素的值;

如下,红色方框表示滤波器,也就是核,绿色方框表示当前像素,黑色方框表示当前图像;下图显示的滤波器是一个3 * 3的核。

简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_计算机视觉

对于均值滤波,取红色区域包含的所有像素的均值作为绿色像素点的值;
对于中值滤波,取红色区域包含的所有像素值的中值作为绿色像素点的值;
对于盒式滤波,取红色区域的所有像素,以核的值作为权值,相加后得到的就是绿色像素的值。通常盒式滤波的核的值都相等,如下:

简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_图像处理_02

高斯滤波的核按照如下计算:

高斯分布计算:$f(x) = \frac{1}{\sigma \sqrt{2\pi }}e^{-(x-\mu )^{2}/(2\sigma ^{2})} $

高斯核通过高斯函数计算:简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_图像处理_03

简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_图像处理_04

双边滤波是边缘保护滤波方法中的一种,是在高斯滤波的基础上加入了像素值权重项,既考虑距离因素,也考虑像素值差异的影响;像素值越相近,权重值越大。在平坦区域,滤波器中每个像素点的值相近,那么空间距离权重主导滤波效果;在边缘区域,边缘同侧的像素值相近,且远大于边缘另一侧的像素值,此时另一侧的像素点的权重对滤波结果影响很小,边缘信息得到保护,表现了一定的自适应。
简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_高斯滤波_05
其中简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_高斯滤波_06是高斯滤波中的距离权重,简述图像均值滤波法和中值滤波法的原理及适用场合 图像的均值滤波处理_图像处理_07是像素值的高斯分布的权重。

3. 滤波实现

/**
 * @file
 * @version 0.1
 * @@date: 2022-10-31
 *
 * @copyright Copyright (c) 2022
 *
 */

#include <opencv.hpp>
#include <stdio.h>
#include <stdlib.h>

#define WINDOW_NAME "fliter"

/// @brief 中值滤波
/// @param pos 滑动条位置
/// @param arg 传入参数
void on_meanFliter(int pos, void *arg)
{
    cv::Mat src = *(cv::Mat *)arg;
    cv::Size kernel(2 * pos + 1, 2 * pos + 1);
    cv::Mat dst;
    cv::blur(src, dst, kernel);
    cv::imshow(WINDOW_NAME, dst);
}

void on_medianFliter(int pos, void *arg)
{
    cv::Mat src = *(cv::Mat *)arg;
    int ksize = 2 * pos + 1;
    cv::Mat dst;
    cv::medianBlur(src, dst, ksize);
    cv::imshow(WINDOW_NAME, dst);
}

void on_gaussianFliter(int pos, void *arg)
{
    cv::Mat src = *(cv::Mat *)arg;
    cv::Size kernel(2 * pos + 1, 2 * pos + 1);
    cv::Mat dst;
    cv::GaussianBlur(src, dst, kernel, 0, 0); // sigmaX=sigmaY=0表示使用默认的高斯分布公式:sigma = (n_x-1)/2*0.30+0.80,n_x = kernel.width-1
    cv::imshow(WINDOW_NAME, dst);
}

void on_boxFliter(int pos, void *arg)
{
    cv::Mat src = *(cv::Mat *)arg;
    cv::Size kernel(2 * pos + 1, 2 * pos + 1);
    cv::Mat dst;
    cv::boxFilter(src, dst, -1, kernel, cv::Point(-1, -1), true);
    cv::imshow(WINDOW_NAME, dst);
}

void on_bilateralFliter(int pos, void *arg)
{
    cv::Mat src = *(cv::Mat *)arg;
    cv::Size kernel(2 * pos + 1, 2 * pos + 1);
    cv::Mat dst;
    int d = pos;
    double sigmaColor = d * 2;
    double sigmaSpace = d / 2.0;
    cv::bilateralFilter(src, dst, d, sigmaColor, sigmaSpace);
    cv::imshow(WINDOW_NAME, dst);
}

int main()
{
    // 读取图像
    cv::Mat src = cv::imread("1.jpg");
    if (src.empty())
    {
        printf("load image fail.\n");
        getc(stdin);
        exit(-1);
    }
    cv::imshow(WINDOW_NAME, src);

    // 创建窗口
    cv::namedWindow(WINDOW_NAME);
    // 创建滑动条,通过滑动条改变核的大小,改变滤波
    int g_meanKernel = 0; // 均值滤波核
    int g_max_meanKernel = 31;
    cv::createTrackbar("mean_kernel", WINDOW_NAME, &g_meanKernel, g_max_meanKernel, on_meanFliter, (void *)&src);

    int g_medianKernel = 0; // 中值滤波核
    int g_max_medianKernel = 31;
    cv::createTrackbar("median_kernel", WINDOW_NAME, &g_medianKernel, g_max_medianKernel, on_medianFliter, (void *)&src);

    int g_boxKernel = 0; // 盒式滤波核
    int g_max_boxKernel = 31;
    cv::createTrackbar("box_kernel", WINDOW_NAME, &g_boxKernel, g_max_boxKernel, on_boxFliter, (void *)&src);

    int g_gaussianKernel = 0; // 高斯滤波核
    int g_max_gaussianKernel = 31;
    cv::createTrackbar("gaussian_kernel", WINDOW_NAME, &g_gaussianKernel, g_max_gaussianKernel, on_gaussianFliter, (void *)&src);

    int g_bilateralKernel = 0; // 双边滤波核
    int g_max_bilateralKernel = 31;
    cv::createTrackbar("bilateral_kernel", WINDOW_NAME, &g_bilateralKernel, g_max_bilateralKernel, on_bilateralFliter, (void *)&src);

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}