• OpenCV-C++ 图像滤波(一)-均值滤波-高斯滤波


    图像模糊,也可以称为图像滤波,主要是为了去除图像中明显的噪声点;

    这一节主要介绍两种滤波方式: 均值滤波和高斯滤波;

    重点介绍一下两者的原理,并使用OpenCV提供的API进行测试;

    卷积计算

    其实,不管是均值滤波,还是高斯滤波,其核心计算是卷积操作;

    计算方式如下图所示,通过一个卷积核在图像上以滑动窗口的形式进行计算:

    相应位置元素相乘后,累加,再取平均;每一次卷积计算的表达式如下:

    [g(i, j) = dfrac{1}{k imes l}sum_{k,l}f(i +k , j+l)h(k, l) ]

    其中,(k ,l)表示卷积核的尺寸;(h)表示卷积核;

    因此,卷积计算的核心是卷积核的选择;另外,卷积核的尺寸最好是奇数,因为需要对局部视野中心进行赋值;

    均值滤波

    均值滤波的卷积核如下所示:

    均值滤波的卷积核中所有的元素大小相同,且经过归一化;

    OpenCV中均值滤波API blur使用的介绍:

    void blur( InputArray src, OutputArray dst,
              Size ksize, Point anchor = Point(-1,-1),
              int borderType = BORDER_DEFAULT );
    
    • src表示需要被执行均值滤波处理的图像
    • dst表示滤波后的图像
    • ksize表示卷积核的尺寸
    • 其他保持默认即可;

    举例, blur的使用(完整代码在文章最后):

    Mat dst;
    blur(src, dst, Size(3, 3), Point(-1, -1));  // filter2D
    

    高斯滤波

    高斯滤波的卷积核不同于均值滤波;

    高斯滤波卷积核是通过高斯函数计算出来的,计算方式如下:

    [G(x, y) = dfrac{1}{2pi sigma^2}e^{-dfrac{x^2+y^2}{2sigma^2}} ]

    将各个位置的坐标带入到高斯函数中,计算得到卷积核,其位置坐标如下所示:

    假设,卷积核尺寸选择(3 imes3),(sigma=0.8),则计算得到的卷积核为:

    上面卷积核的计算方式如下:

    • 将位置坐标代码高斯函数中,计算得到每个位置的结果;
    • 将所有位置的值除以所有位置的总和;

    这里提供一下python实现的计算方式:

    import math
    import numpy as np
    
    sigma = 0.8;
    
    def calc_val(x, y, sigma):
        val = (1/(2*math.pi*sigma**2))*(math.e**(-(x**2+y**2)/(2*sigma**2)))
        return val
    
    a_11 = calc_val(-1, 1, sigma)
    a_12 = calc_val(0, 1, sigma)
    a_13 = calc_val(1, 1, sigma)
    a_21 = calc_val(-1, 0, sigma)
    a_22 = calc_val(0, 0, sigma)
    a_23 = calc_val(1, 0, sigma)
    a_31 = calc_val(-1, -1, sigma)
    a_32 = calc_val(0, -1, sigma)
    a_33 = calc_val(1, -1, sigma)
    
    res = np.array([[a_11, a_12, a_13], 
                    [a_21, a_22, a_23], 
                    [a_31, a_32, a_33]])
    res = res/np.sum(res)
    print(res)
    

    那么,由高斯函数计算得到卷积核之后,有两种使用方式:

    1. 小数卷积核

    小数卷积核指的是直接使用计算得到卷积核用于后续卷积计算;

    2. 整数卷积核

    整数卷积核指的是将卷积核进行归一化处理;

    • 首先,先将左上角缩放到1,其他位置上的值再乘以这个缩放系数;

    得到:

    计算方式,python实现如下:

    # 归一化, 代码接着上面的来
    scale = 1 / a_11
    res = res * scale
    print(res)
    
    • 其次, 对计算后的卷积核,取整,再除以和,如下;

    从以上的描述过程可以看出,高斯卷积核最重要的参数是高斯分布的标准差(sigma),它代表了数据的离散程度;

    • 如果(sigma)较小,得到的高斯核中心系数就越大,周围系数越小,则对图像的平滑效果不好;
    • 如果(sigma)较大,则高斯核中的各个系数相差不大,则对图像的平滑效果较好;

    上面介绍了,如何得到高斯核,那么接下来,看一下OpenCV中提供的GaussianBlur的使用:

    void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                      double sigmaX, double sigmaY = 0,
                      int borderType = BORDER_DEFAULT );
    
    • src表示需要模糊的图像;
    • dst表示模糊的输出图像;
    • ksize表示卷积核的尺寸;
    • sigmaX表示在X方向的标准偏差;
    • sigmaY表示在Y方向上的标准偏差;

    需要注意的是,如果sigmaY=0,则将其设为sigmaX;如果两者都为0,则两者由卷积核的尺寸进行计算:

    [sigma_x = (dfrac{n_x-1}{x})cdot 0.3 + 0.8, qquad n_x = ksize.width -1 ]

    [sigma_y = (dfrac{n_y-1}{x})cdot 0.3 + 0.8, qquad n_y = ksize.height -1 ]

    注意:这里提到的sigmaX, sigmaY如何与上面叙述的高级核的构造过程如何产生关系,还不得知,以后弄明白了再补充;

    示例:

    Mat dst_gaussian;
    int sigma = 3;
    GaussianBlur(src, dst_gaussian, Size(3, 3), sigma, sigma);
    

    最后,完整的程序如下:

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main(){
    
        // 读取图像
        Mat src = imread("/home/chen/dataset/lena.jpg");
        if (src.empty()){
            cout << "cloud not load image." << endl;
            return -1;
        }
    
        // 均值模糊
        Mat dst;
        blur(src, dst, Size(3, 3), Point(-1, -1));  // filter2D
    
        // 高斯模糊
        Mat dst_gaussian;
        int sigma = 3;
        GaussianBlur(src, dst_gaussian, Size(3, 3), sigma, sigma);
    
        // 显示图像
        char input_title[] = "src";
        char output_title[] = "src_blur";
        char output_title_gaussian[] = "src_gaussian_blur";
    
        namedWindow(input_title, WINDOW_AUTOSIZE);
        imshow(input_title, src);
        namedWindow(output_title, WINDOW_AUTOSIZE);
        imshow(output_title, dst);
        namedWindow(output_title_gaussian, WINDOW_AUTOSIZE);
        imshow(output_title_gaussian, dst_gaussian);
    
        waitKey(0);
        return 0;
    }
    

    输出:

    Reference:

  • 相关阅读:
    实例演示:如何在Kubernetes上大规模运行CI/CD
    Word 2010文档自动生成目录和某页插入页码
    python用pyinstaller打包成exe文件
    C#建WindowForm调用R可视化
    Git Extension工具安装及使用
    python的scikit-learn的主要模块和基本使用
    NoSQL 数据库概览及其与 SQL 语法的比较
    Redis 搜索引擎优化
    图像卷积与滤波
    C# 编写 TensorFlow 人工智能应用
  • 原文地址:https://www.cnblogs.com/chenzhen0530/p/14624012.html
Copyright © 2020-2023  润新知