快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)

姓名:张右润

学号:19021210648

转载自:https://blog.csdn.net/qq_36359022/article/details/80188873

【嵌牛导读】高斯滤波(Gauss Filter)是线性滤波中的一种。在OpenCV图像滤波处理中,高斯滤波用于平滑图像,或者说是图像模糊处理,因此高斯滤波是低通的。其广泛的应用在图像处理的减噪过程中,尤其是被高斯噪声所污染的图像上。 高斯滤波的基本思想是: 图像上的每一个像素点的值,都由其本身和邻域内其他像素点的值经过加权平均后得到。其具体操作是,用一个核(又称为卷积核、掩模、矩阵)扫描图像中每一个像素点,将邻域内各个像素值与对应位置的权值相称并求和。从数学的角度来看,高斯滤波的过程是图像与高斯正态分布做卷积操作。 

【嵌牛鼻子】高斯滤波器 高斯模糊 高斯平滑

【嵌牛提问】快速高斯滤波如何用opencv实现?

【嵌牛正文】

高斯滤波(Gauss Filter)是线性滤波中的一种。在OpenCV图像滤波处理中,高斯滤波用于平滑图像,或者说是图像模糊处理,因此高斯滤波是低通的。其广泛的应用在图像处理的减噪过程中,尤其是被高斯噪声所污染的图像上。

高斯滤波的基本思想是: 图像上的每一个像素点的值,都由其本身和邻域内其他像素点的值经过加权平均后得到。其具体操作是,用一个核(又称为卷积核、掩模、矩阵)扫描图像中每一个像素点,将邻域内各个像素值与对应位置的权值相称并求和。从数学的角度来看,高斯滤波的过程是图像与高斯正态分布做卷积操作。 

注意: 高斯滤波是将二维高斯正态分布放在图像矩阵上做卷积运算。考虑的是邻域内像素值的空间距离关系,因此对彩色图像处理时应分通道进行操作,也就是说操作的图像原矩阵时用单通道数据,最后合并为彩色图像。

本章节仅讨论快速高斯滤波的实现,如对高斯滤波的基本原理和实现不理解的,可以先看之前的一篇

OpenCV高斯滤波器详解及代码实现

一、高斯函数分离特性

快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)_第1张图片

可以看到,高斯二维公式可以推导为X轴与Y轴上的一维高斯公式。而图形矩阵是二维的,高斯滤波就是将核范围中的各个点的坐标带入高斯二维公式,得出在核矩阵上的空间分布特性,这些特性将作为权值反应在核矩阵的各个点上。最终使用核与图像矩阵作卷积运算得到处理图像。

在之前的那篇高斯滤波文章上,采用的二维方式实现的。假设一张单通道图片大小(M*N),核大小(size*size),核上的(size*size)个点都将被计算权值。最终实现的复杂度为 (M*N*size*size)。

而如果将二维分步成X轴Y轴的一维处理。在X轴上计算size个点,Y轴上size个点。其复杂度将优化到 (M*N*size*2).

注意:先使用X轴方向(Y轴方向)对整个图像矩阵作卷积,再在Y轴方向(X轴方向)对整个图像矩阵作卷积。

二、高斯二维的空间分布

二维高斯是构建高斯滤波器的基础。可以看到,G(x,y)在x轴y轴上的分布是一个突起的帽子的形状。这里的sigma可以看作两个值,一个是x轴上的分量sigmaX,另一个是y轴上的分量sigmaY。对图像处理可以直接使用sigma并对图像的行列操作,也可以用sigmaX对图像的行操作,再用sigmaY对图像的列操作。它们是等价的。 

当sigmaX和sigmaY取值越大,整个形状趋近于扁平;当sigmaX和sigmaY取值越小,整个形状越突起。

假设核大小为(size*size),那么核上(size*size)个点都将计算权值。


快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)_第2张图片

三、高斯二维分步为X轴Y轴的高斯一维

假设一个(3*3)的核,在X轴(k方向)上

快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)_第3张图片

在Y轴(l方向)上

快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)_第4张图片

可以看到,实际上(size*size)个点中,最后仅以(size/2, size/2)点为中心,计算了(size*2)个点的权值。

四、二维与一维时间比较

同样对一张高斯噪声图处理,核大小取(53*53)。

上方时二维处理所用时间,下方是分步一维处理所用时间。当图像越大,或者核大小越大时,两者的差异将更加明显。

快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积)_第5张图片

五、代码实现

(1)main函数

int main(void)

{

    // [1] src读入图片

    cv::Mat src = cv::imread("Gaussian_pic.jpg");

    // [2] dst目标图片

    cv::Mat dst;

    cv::Mat dst2 = src.clone();

    // [3] 高斯滤波  sigma越大越平越模糊

    myGaussianFilterFast(&src, &dst, 53, 2.0f, 2.0f);

    // [4] 窗体显示

    cv::imshow("src", src);

    cv::imshow("dst", dst);

    cv::waitKey(0);

    cv::destroyAllWindows();

    return 0;

}

(2)彩色图像通道分离以及X,Y分别确定权值矩阵

void myGaussianFilterFast(cv::Mat *src, cv::Mat *dst, int n, double sigmaX, double sigmaY)

{

    // [1] 初始化

    *dst = (*src).clone();

    // [2] 彩色图片通道分离

    std::vector channels;

    cv::split(*src, channels);

    // [3] 滤波

    // [3-1] 分别确定高斯正态矩阵(X,Y)

    double *arrayX = getGaussianArray(n, sigmaX);

    double *arrayY = getGaussianArray(n, sigmaY);

    for (int i = 0; i < 3; i++) {

        gaussian(&channels[i], arrayX, arrayY, n);

    }

    // [4] 合并返回

    cv::merge(channels, *dst);

    return;

}

3)高斯一维计算

/* 获取高斯分布数组 (核大小, sigma值) */

double *getGaussianArray(int arr_size, double sigma)

{

    int i;

    // [1] 初始化数组

    double *array = new double[arr_size];

    // [2] 高斯分布计算

    int center_i = arr_size / 2;

    double sum = 0.0f;

    // [2-1] 高斯函数

    for (i = 0; i < arr_size; i++) {

            array[i] =

                exp(-(1.0f)* (((i - center_i)*(i - center_i)) /

                (2.0f*sigma*sigma)));

            sum += array[i];

    }

    // [2-2] 归一化求权值

    for (i = 0; i < arr_size; i++) {

            array[i] /= sum;

            //printf(" [%.15f] ", array[i]);

    }

    return array;

}1234567891011121314151617181920212223

(4)滤波处理,请注意,在X方向卷积完整个图像后,再在Y方向上卷积,不要一边X卷积一边Y卷积,此时计算中包含X卷积过和没卷积过的值,因此此时不能进行Y卷积。

/* 高斯滤波 (待处理单通道图片, 高斯分布数组, 高斯数组大小(核大小) ) */

void gaussian(cv::Mat *_src, double *_arrayX, double *_arrayY, int _size)

{

    int center = _size / 2;

    cv::Mat temp = (*_src).clone();

    // [1] 扫描  X方向

    for (int i = 0; i < (*_src).rows; i++) {

        for (int j = 0; j < (*_src).cols; j++) {

            // [2] 忽略边缘

            if (i >center - 1 && j >center - 1 &&

                i < (*_src).rows - center && j < (*_src).cols - center) {

                // [3] 找到图像输入点,以输入点为中心与核中心对齐

                //    核心为中心参考点 卷积算子=>高斯矩阵180度转向计算

                //    x y 代表卷积核的权值坐标  i j 代表图像输入点坐标

                //    卷积算子    (f*g)(j) = f(j-l)g(l)      f代表图像输入 g代表核

                //    带入核参考点 (f*g)(j) = f(j-(l-aj))g(l)  ai,aj 核参考点

                //    加权求和  注意:核的坐标以左上0,0起点

                double sum = 0.0;

                for (int l = 0; l < _size; l++) {

                    sum += (*_src).ptr(i)[j - l + center] * _arrayX[l];

                }

                // 放入中间结果

                temp.ptr(i)[j] = MAX(MIN(sum, 255), 0);

            } 

        }

    }

    // [1] 扫描  Y方向

    for (int i = 0; i < (*_src).rows; i++) {

        for (int j = 0; j < (*_src).cols; j++) {

            // [2] 忽略边缘

            if (i >center - 1 && j >center - 1 &&

                i < (*_src).rows - center && j < (*_src).cols - center) {

                double sum = 0.0;

                for (int k = 0; k < _size; k++) {

                    // 从中间结果取

                    sum += temp.ptr(i - k + center)[j] * _arrayY[k];

                }

                // 放入原图像

                (*_src).ptr(i)[j] = MAX(MIN(sum, 255), 0);

            }

        }

    }

}

你可能感兴趣的:(快速高斯滤波、高斯模糊、高斯平滑(二维卷积分步为一维卷积))