图像处理中的滤波

作者: 芒果浩明 | 来源:发表于2018-10-06 00:14 被阅读3次

    滤波

    滤波(Wave filtering)是将信号中特定波段频率滤除的操作,是抑制和防止干扰的一项重要措施。在图像处理中,滤波是图像预处理的一种。图像处理中滤波将信号中特定的波段频率滤除,从而保留所需要的波段频率信号。根据选择保留的不同频段可以体现这么两个作用

    消除图像中混入的噪声
    对应的是低通滤波,噪声在图像中一般是高频信号。
    为图像识别抽取出图像特征
    这里的特征一般为边缘纹理的特征,对应的是高通滤波,图像中边缘和纹理细节是高频信号。

    滤波的分类

    图像中滤波算法的分类有很多,可以分为线性滤波和非线性滤波,可以分为相关滤波和卷积滤波,还可以分为高通滤波和低通滤波,空间滤波和频域滤波。

    线性滤波和非线性滤波

    • 线性滤波

    维基百科解释为:用于时变输入信号的线性运算,在图像处理中可以这么理解,对于输入的信号(即要处理的图像),进行的是线性的运算,得出的结果作为输出图像。可以参考下图


    线性滤波原理

    首先有一个滤波器的模板(这里是3x3大小),模板里有系数,f(x,y)的值等于模板系数与f(x,y)周围一的像素点相乘求和,这个运算是线性的。在线性的滤波器中,运算的不同即为滤波器的系数模板不同。

    线性滤波的包含方框滤波、均值滤波、高斯滤波、拉普拉斯滤波、sobel算子等。

    • 非线性滤波

    输出的信号响应是由输入经过非线性的运算得到的。比如典型的中值滤波,就是取像素点邻域的中值作为像素的的响应输出。

    非线性滤波包含中值滤波和双边滤波。

    卷积滤波和相关滤波

    首先要注意的是卷积滤波和相关滤波都属于线性滤波,两者的区别是加权系数的对应相乘顺序有所不同。

    卷积和相关

    高通滤波和低通滤波

    高通滤波与低通滤波之分是相对于滤波的目的而言的,简而言之,高通滤波器就是去除图像中的低频部分,保留高频。表现就是经高通滤波后,保留了图像的高频边缘和纹理细节,所以高通滤波对应的是图像的锐化。低通滤波则是相反的,处理的结果是保留低频部分去除高频部分,在图像上的表现是纹理细节都被模糊了,所以低通滤波对应的是图像的平滑模糊。

    空间滤波和频域滤波
    空间滤波即直接在像素坐标上对图像数据进行处理滤波,频域滤波则是先把图像由空间域变换到频域,在频域进行处理,结束以后再由频域变换会空间域。

    空间滤波和频域滤波.png

    下面是几个具体的滤波算法的例子

    方框滤波

    方框滤波,线性滤波里面最简单的一个。即用一个已确定的模板系数去与像素点领域相乘,所得结果即为像素点的响应。

    均值滤波器模板

    均值滤波

    均值滤波则是方框滤波的特例,将方框滤波的系数模板归一化之后便是均值滤波

    均值滤波模板

    可以看到,均值滤波的结果是取像素点周围领域的平均值作为响应输出。

    高斯滤波

    高斯滤波的模板系数就稍显复杂,其模板系数是服从高斯分布的。

    先看看一维的高斯分布

    一维高斯分布

    二维的高斯分布


    二维高斯分布

    所以高斯滤波的模板系数,应该服从上图中的锥形山峰。那如何计算高斯分布的模板系数呢,我们取均值为模板的中心点,计算公式如下


    高斯滤波模板系数计算公式

    这里附上代码

    std::vector<std::vector<double> >getModel(const int& n, const double& sigmma)//求解nxn的模板系数
    {
        const double pi = 3.1415926;
        const double weight = 1.0 /(2.0 * pi * sigmma * sigmma);//gaussion公式中的系数
    
        double sum = 0.0;
        std::vector<std::vector<double>> res(n, std::vector<double>(n, 0.0));
        
        for(int i = 0;  i < n; ++i)
            for (int j = 0; j < n; ++j)
            {
                res[i][j] = weight * std::exp(-((i - n / 2) * (i - n / 2) + (j - n / 2)*(j - n / 2)) / (2.0*sigmma*sigmma));//n/2为公式中都均值,即原点在图像中心
            }
    
        return res;
    }
    

    假如不想手动计算高斯滤波的模板系数,也可以取模板的近似值作为模板。如3x3和5x5的模板可以取

    高斯滤波模板

    拉普拉斯算子

    拉普拉斯滤波属于高通滤波,算子定义为

    拉普拉斯算子定义

    下面由算子推导计算模板系数
    在x方向上,二阶导数的微分可以由差分近似表示,有

    x方向

    类似地,在y方向上有

    y方向

    所以拉普拉斯算子在离散的情况下,可以近似为


    离散拉普拉斯

    那么可以得矩阵的模板系数

    拉普拉斯模板系数

    还有一般常用的拉普拉斯模板

    拉普拉斯模板

    Roberts算子

    Roberts算子比较简单,使用2x2的领域


    Roberts算子

    计算响应值的方式如下

    Roberts算子计算

    sobel算子

    sobel算子

    Robinson算子

    Robinson算子

    Kirsch算子

    Kirsch算子

    以上所有有的算子都属于线性滤波,在得到离散情况下的算子模板系数之后,就可以用这个模板去对图像进行操作,使用模板系数去遍历图像,操作可以选择卷积或者相关。这些算子也称卷积掩模。

    这里先给出二维卷积的代码实现

    //二维卷积的实现
    #include<cassert>
    #include<vector>
    
    
    void conv2(int** filter, int **mat, int** res, const int filter_rows, const int filter_cols, const int mat_rows, const int mat_cols);//指针数组版本
    std::vector<std::vector<int> > conv2(std::vector<std::vector<int> > filter, std::vector<std::vector<int> > mat);//向量版本
    
    
    int main(void)
    {
        return 0;
    }//main
    
    void conv2(int** filter, int **mat, int** res, const int filter_rows, const int filter_cols, const int mat_rows, const int mat_cols)
    {
        assert(filter_cols < mat_cols && filter_rows < mat_rows);
        for(int i = 0; i < mat_rows - 1; ++i)
            for (int j = 0; j < mat_cols - 1; ++j)
            {
                int tmp = 0;
                for (int m = 0; m < filter_rows; ++m)
                    for (int n = 0; n < filter_cols; ++n)
                        if(0 <= i -m  && i - m < mat_rows && 0 <= j - n && j - n < mat_cols)
                            tmp += filter[m][n] * mat[i - m][j - n];//卷积公式
    
                res[i][j] = tmp;
            }
    }
    
    std::vector<std::vector<int> > conv2(std::vector<std::vector<int> > filter, std::vector<std::vector<int> > mat )//向量版本
    {
        const int filter_rows = filter.size();
        const int filter_cols = filter[0].size();
    
        const int mat_rows = mat.size();
        const int mat_cols = mat[0].size();
    
        assert(filter_cols < mat_cols && filter_rows < mat_rows);
        std::vector<std::vector<int> > res(mat_rows, std::vector<int>(mat_cols, 0));
    
        for (int i = 0; i < mat_rows - 1; ++i)
            for (int j = 0; j < mat_cols - 1; ++j)
            {
                int tmp = 0;
                for (int m = 0; m < filter_rows; ++m)
                    for (int n = 0; n < filter_cols; ++n)
                        if (0 <= i - m && i - m < mat_rows && 0 <= j - n && j - n < mat_cols)
                            tmp += filter[m][n] * mat[i - m][j - n];//卷积公式
    
                res[i][j] = tmp;
            }
        return res;
    }
    

    然后以高斯滤波为例,给出这些模板系数卷积滤波的实现

    void mycv::gaussianFilter(cv::Mat& src, cv::Mat& dst)
    {
        const int rows = src.rows;
        const int cols = src.cols;
        dst = cv::Mat(src.size(), src.type(), cv::Scalar::all(0));
    
        std::vector<std::vector<double>> gauss = getModel(3);//3x3模板系数
    
        switch (src.channels())
        {
        case 1://灰度图
            for(int i = 0; i < rows -1; ++i)
                for (int j = 0; j < cols - 1; ++j)
                {
                    double tmp = 0.0;
                    for(int m = 0; m < gauss.size(); ++m)
                        for (int n = 0; n < gauss[0].size(); ++n)
                        {
                            if (i - m >= 0 & i - m < rows && j - n >= 0 && j - n < cols)
                                tmp += gauss[m][n] * static_cast<double>(src.at<uchar>(i - m, j - n));//卷积公式
                        }
    
                    dst.at<uchar>(i, j) = static_cast<int>(tmp);
                }
            break;
        case 3://彩色
            for (int i = 0; i < rows - 1; ++i)
                for (int j = 0; j < cols - 1; ++j)
                    for (int k = 0; k < 3; ++k)
                    {
                        double tmp = 0.0;
                        for (int m = 0; m < gauss.size(); ++m)
                            for (int n = 0; n < gauss[0].size(); ++n)
                                if (i - m >= 0 & i - m < rows && j - n >= 0 && j - n < cols)
                                    tmp += gauss[m][n] * static_cast<double>(src.at<cv::Vec3b>(i - m, j - n)[k]);//卷积公式
    
                        dst.at<cv::Vec3b>(i, j)[k] = static_cast<int>(tmp);
                    }
            break;
        default:
            break;
        }
    }
    

    相关文章

      网友评论

        本文标题:图像处理中的滤波

        本文链接:https://www.haomeiwen.com/subject/idsqaftx.html