图像的高斯滤波原理及C++代码实现

什么是图像的高斯噪声:

        高斯噪声指概率密度函数服从高斯分布即正态分布的一类噪声,而图像中的高斯噪声是一种在数字图像中普遍存在的随机干扰,表现为覆盖全图的颗粒状“雪花”或“薄雾”效果。其核心特征是每个像素的噪声值独立服从高斯分布(正态分布)

设原始图像为I(x,y),添加噪声后的图像为I’(x,y),则有

I’(x,y) = I(x,y) + N(x,y)

        其中:

                N(x,y)N(x,y) 是独立同分布的高斯随机变量

                服从分布 N∼N(μ,σ2)N∼N(μ,σ2)

                μ (均值):通常为 0(噪声不产生整体亮度偏移)

                σ (标准差):控制噪声强度(值越大,噪点越明显)

        关键特性:每个像素添加的噪声值独立生成,与位置、原始颜色无关。

高斯分布:均值为0,方差为σ²,而一维高斯分布公式及曲线如下:

二维高斯分布公式及曲线如下:

高斯核:理论上,高斯分布在二维平面上均有非负值,其高斯核应为无限大。在实际过程中,仅需要取均值周围3倍标准差范围内的值。如下图中,中心点坐标为(0,0),假定σ=1.5,将坐标点带入二维高斯分布的概率密度函数中,得出右边的卷积核

(-1,1)

(0,1)

(1,1)

0.0453542

0.0566406

0.0453542

(-1,0)

(0,0)

(1,0)

=>

0.0566406

0.0707355

0.0566406

(-1,-1)

(0,-1)

(1,-1)

0.0453542

0.0566406

0.0453542

以下为构建高斯核的伪代码,其中kernel_size = 3

        int x = 0,y = 0;
        int offset = floor(kernel_size/2);
        float kernel[kernel_size][kernel_size];
        double kernel_sum = 0;
        //sigma为1.5 构建高斯核
        for(int y = 0;y < kernel_size;y++){
            for(int x = 0;x < kernel_size;x++){
                kernel[y][x] = 1 / (2 * PI * sigma * sigma) * exp(-((x-offset) * (x-offset) + (y-offset) * (y-offset))/(2 * sigma * sigma));
                kernel_sum += kernel[y][x];
            }
        }

构建完成输出高斯核矩阵:

计算高斯权值之和为0.4787148

因需要确保高斯核归一化,即九个权重加起来为1,如下为归一化操作:

 //归一化
        for(int y = 0;y < kernel_size;y++){
            for(int x = 0;x < kernel_size;x++){
                kernel[y][x] /= kernel_sum;
                cout << kernel[y][x] << " ";
            }
            cout << endl;
        }

归一化后最终的高斯核矩阵如下:

至此,一个3×3的高斯模板(高斯核)构建完成。

有了高斯模板,就可以利用高斯模板对图像进行卷积了。对图像进行卷积计算,其实就是将模板作为权值,与对应像素相乘再求和,得到的结果就是中心点卷积后的结果,本质上就是个加权平均操作。

举个例子:
假设随机在图像中取一个3*3的局部块,共有9个像素点,其高斯滤波计算如下:

10

8

30

10*0.0947417

8*0.1183180

30*0.0947417

40

50

50

=>

40*0.1183180

50*0.1477613

50*0.1183180

30

1

5

30*0.0947417

1*0.1183180

5*0.0947417

将这9个值加起来,就是中心点50进行高斯滤波后的值。对图像中所有的像素点重复这个过程,就是在对图像进行高斯滤波操作,最终得到高斯模糊的图像。

边界处理:在对图像边缘进行卷积时,由于缺少邻域像素,通常将缺失的像素补零,而且其相对应的高斯模板要做归一化,在下面的代码实现中我没有对边界进行处理,有兴趣的可以自己写一写。

以下为高斯滤波的结果,左图为灰度图,右图为高斯滤波的结果图:

为了更直观的看到处理前后的差异,以下放一张直观的局部对比图,左图为灰度图,右图为高斯平滑后的结果图,可直观地看出右图更加平滑,图像更加干净:

代码实现:其中不对边界进行处理

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

#define PI 3.1415926

int gaussian_fliter(Mat& src,Mat& dst,float sigma,int kernel_size){
    int channels = src.channels();
    cout << "channels :";
    cout <<  channels << endl;
    if(channels != 1){
        cout << "[gaussian_fliter]:channels error!" << endl;
        return 0;
    }
    int piexl_num = 0;
    if(kernel_size){
        int height = src.rows;
        int width = src.cols;
        cout << "[gaussian_fliter]:height:" << height << "width:" << width << endl;

        int x = 0,y = 0;
        int offset = floor(kernel_size/2);
        float kernel[kernel_size][kernel_size];
        double kernel_sum = 0;
        //构建高斯核
        for(int y = 0;y < kernel_size;y++){
            for(int x = 0;x < kernel_size;x++){
                kernel[y][x] = 1 / (2 * PI * sigma * sigma) * exp(-((x-offset) * (x-offset) + (y-offset) * (y-offset))/(2 * sigma * sigma));
                kernel_sum += kernel[y][x];
            }
        }
        //归一化
        cout << "kernel value :"<< endl;
        for(int y = 0;y < kernel_size;y++){
            for(int x = 0;x < kernel_size;x++){
                kernel[y][x] /= kernel_sum;
                cout << kernel[y][x] << " ";
            }
            cout << endl;
        }

        for(int y = 0;y < height;y++){
            for(int x = 0;x < width;x++){
                if(y-offset >= 0 && y + offset < height && x- offset >= 0 && x + offset < width){
                    float temp = 0;
                    for(int yy = 0;yy < kernel_size;yy++){
                        for(int xx = 0;xx < kernel_size;xx++){
                            float element = src.at<uchar>(y-offset+yy,x- offset+xx) * 1.0;
                            temp += element * kernel[yy][xx];
                            //cout << "src["<<y-offset+yy <<"]" << "[" << x- offset+xx << "]: " << element  <<  " kernel["<<yy <<"]" << "[" << xx << "]: " << kernel[yy][xx] <<endl;
                        }
                    }
                    //cout << "temp" << temp << endl;
                    dst.at<uchar>(y,x) = temp;
                    //cout << "src: " << src.at<uchar>(y,x) * 1.0  << " dst: " << dst.at<int>(y,x) * 1.0 <<endl;
                    piexl_num++;
                }
            } 
        }
    }
    cout << "process end!" << endl;
    //判断是否经过高斯
    Mat judge = dst == src;
    if(countNonZero(judge) == 0){
        cout << "[gaussian_fliter]:error,no process" << endl;
        return 0;
    }else{
        cout << "piexl_num:" << piexl_num << endl;
        cout << "[gaussian_fliter]:process success!" << endl;
        return 1;
    }

}

    
int main(){
     // 读取图像
    Mat image = imread("C:/Users/Desktop/IMG_2600.jpg");
    namedWindow("GRAY", WINDOW_AUTOSIZE);
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    imwrite("C:/Users/Desktop/gray.jpg", gray);
    imshow("GRAY",gray);
    waitKey(0);
    Mat guassian = gray;
    cout << gaussian_fliter(gray,guassian,1.5,3) << endl;
    //GaussianBlur(gray, guassian, Size(3, 3), 1);
    imwrite("C:/Users/Desktop/guassian.jpg", guassian);
    namedWindow("gaussian", WINDOW_AUTOSIZE);
    imshow("guassian",guassian);
    waitKey(0);

    return 0;
}

感谢阅读!

高斯滤波是一种常见的图像处理技术,用于平滑图像并减少噪声,其原理是利用高斯函数对图像进行卷积。在Arduino上实现高斯滤波可以使用C语言编写代码。 以下是基于Arduino的高斯滤波代码实现: ```c #define KERNEL_SIZE 5 int kernel[KERNEL_SIZE][KERNEL_SIZE] = { {1, 4, 7, 4, 1}, {4, 16, 26, 16, 4}, {7, 26, 41, 26, 7}, {4, 16, 26, 16, 4}, {1, 4, 7, 4, 1} }; void gaussian_filter(int *input, int *output, int width, int height) { int x, y, i, j, k, sum, index; int offset = KERNEL_SIZE / 2; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { sum = 0; index = y * width + x; for (j = -offset; j <= offset; j++) { for (i = -offset; i <= offset; i++) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { sum += input[(y + j) * width + (x + i)] * kernel[offset + j][offset + i]; } } } output[index] = sum / 273; } } } ``` 在代码中,`KERNEL_SIZE` 定义了高斯卷积核的大小。`kernel` 数组则存储了高斯卷积核的权重。 高斯卷积核的大小应该是奇数,并且中心点的权重最大。在代码中,卷积核的中心点权重为 41,其余点的权重根据高斯函数计算得出。 函数 `gaussian_filter` 对输入图像进行高斯滤波处理,并将结果存储到输出数组中。在循环中,对于每个像素点,根据高斯卷积核计算其周围像素点的加权平均值,并将结果存储到输出数组中。 需要注意的是,在计算卷积核的加权平均值时,需要对超出图像边界的像素点进行特殊处理。在代码中,使用了简单的边界检测方法,对超出边界的像素点直接忽略不计。 使用该函数需要传入以下参数: - `input`:指向输入图像数据的指针; - `output`:指向输出图像数据的指针; - `width`:输入图像的宽度; - `height`:输入图像的高度。 例如,可以将摄像头采集到的图像数据作为输入,经过高斯滤波处理后显示在LCD屏幕上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值