内容
对lena原始图像分别添加高斯和椒盐噪声,再分别使用矩形、菱形、十字丝窗口下的均值、中值滤波进行滤波处理
原理
share_noel/图像处理/数字图像处理-夏良正.pdf
https://blog.csdn.net/qq_41102371/article/details/125646840
数字图像处理-夏良正P151
滤波窗口:菱形、十字丝、矩形
添加噪声
基于前面的博客C/C++图像处理1 灰度图修正添加处理代码
高斯
主要原理是在原来的灰度值上添加一个高斯随机数
添加高斯噪声按钮
void Cmedian_filtering_LXDlg::OnBnClickedCorrection1a()
{
// TODO: 在此添加控件通知处理程序代码
if (bmpfilepath1 == "" || bmpfilepath2 == "")
{
MessageBox(_T("请先加载原图"));
return;
}
int i, j, a=0,b=0,c=0;
UpdateData(true);//更新编辑框值到变量
//直方图数组清零
for (i = 0; i < h1; i++)
{
gramf1a[i] = 0;
}
//out_array = allocate_image_array(h1, w1);
//定义全局二级指针short **in_array1, **in_array2, **out_array, **g_noise_array, **sp_noise_array;存放像素
g_noise_array = allocate_image_array(h1, w1);
bmheader.height = h1;
bmheader.width = w1;
create_allocate_bmp_file(pFileName1a, &bmp_file_header, &bmheader);
//m_gaussian_u、m_gaussian_sigma、m_gaussian_k由编辑框手动输入
add_gaussian_noise(in_array1, g_noise_array, h1, w1,m_gaussian_u,m_gaussian_sigma,m_gaussian_k);//加高斯噪声到g_noise_array
gaussianflag = 1;
for (i = 0; i < h1; i++)
{
for (j = 0; j < w1; j++)
{
gramf1a[g_noise_array[i][j]]++;
}
}
write_bmp_image(pFileName1a, g_noise_array);
Cmedian_filtering_LXDlg::showbmp(file1fa, 3);//显示灰度变换图1
}
下面代码中:
K(gaussian_k)为高斯噪声的系数,系数越大,高斯噪声越强;
σ(gaussian_sigma)是方差,噪声服从高斯分布,所以方差越大,数据越分散,噪声也就越多;
u(gaussian_u)是均值,均值决定着整个图像的明亮程度,均值大于0,表示图像加上一个使自己变亮的噪声,小于0,表示图像加上一个使自己变暗的噪声。
//生成高斯随机数
double GaussianNoise(double mu, double sigma)
{
static double V1, V2, S;
static int phase = 0;
double X;
double U1, U2;
if (phase == 0) {
do {
U1 = (double)rand() / RAND_MAX;
U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while (S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
}
else{
X = V2 * sqrt(-2 * log(S) / S);
}
phase = 1 - phase;
return mu + sigma*X;
}
//高斯噪声为加性噪声,在原图的基础上加上噪声即为加噪后的图象
void add_gaussian_noise(short** in_array, short** out_array, long height, long width, double gaussian_u, double gaussian_sigma, int gaussian_k)
{
srand(time(NULL));
for (int i = 0; i < height; i++){
for (int j = 0; j < width; j++){
out_array[i][j] = in_array[i][j] + (int)gaussian_k*GaussianNoise(gaussian_u, gaussian_sigma);
if (out_array[i][j] < 0x00)
out_array[i][j] = 0x00;
else if (out_array[i][j] > 0xff)
out_array[i][j] = 0xff;
}
}
}
椒盐
添加椒盐噪声按钮
void Cmedian_filtering_LXDlg::OnBnClickedCorrection2a()
{
// TODO: 在此添加控件通知处理程序代码
if (bmpfilepath1 == "" || bmpfilepath2 == "")
{
MessageBox(_T("请先加载原图"));
return;
}
int i, j,a=0;
UpdateData(true);//更新编辑框值到变量
//直方图数组清零
for (i = 0; i < h1; i++)
{
gramf2a[i] = 0;
}
//out_array = allocate_image_array(h2, w2);
sp_noise_array = allocate_image_array(h2, w2);
bmheader.height = h2;
bmheader.width = w2;
create_allocate_bmp_file(pFileName2a, &bmp_file_header, &bmheader);
//m_snr由编辑框手动输入
add_salt_pepper_noise(in_array2, sp_noise_array, h2, w2, m_snr);//加椒盐噪声到sp_noise_array,信噪比m_snr
spflag = 1;
for (i = 0; i < h1; i++)
{
for (j = 0; j < w1; j++)
{
gramf2a[sp_noise_array[i][j]]++;
}
}
write_bmp_image(pFileName2a, sp_noise_array);
Cmedian_filtering_LXDlg::showbmp(file2fa, 7);//显示灰度变换图1
}
SNR为信噪比
void add_salt_pepper_noise(short** in_array, short** out_array, long height, long width, double SNR)
{
srand(time(NULL));
int noise_p;
int SP = height*width;
int NP = SP*(1 - SNR);
for (int i = 0; i < height; i++){
for (int j = 0; j < width; j++){
out_array[i][j] = in_array[i][j];
}
}
for (int i = 0; i<NP; i++) {
int x = (int)(rand()*1.0 / (RAND_MAX + 1.0)* (double)height);
int y = (int)(rand()*1.0 / (RAND_MAX + 1.0)* (double)width);
int r = rand() % 2;
if (r){
out_array[x][y] = 0;
}
else{
out_array[x][y] = 255;
}
}
}
处理代码
按钮
void Cmedian_filtering_LXDlg::OnBnClickedCorrection1b()
{
// TODO: 在此添加控件通知处理程序代码
if (bmpfilepath1 == "" || bmpfilepath2 == "")
{
MessageBox(_T("请先加载原图"));
return;
}
if (gaussianflag==0)
{
//MessageBox(_T("请先添加高斯噪声"));
MessageBoxA(NULL, ("请先添加高斯噪声"), ("警告"), MB_OK);
return;
}
int i, j, a = 0;
UpdateData(true);//更新编辑框值到变量
//直方图数组清零
for (i = 0; i < h1; i++)
{
gramf1b[i] = 0;
}
out_array = allocate_image_array(h1, w1);
bmheader.height = h1;
bmheader.width = w1;
file1fb = _TEXT("rec_med_g.bmp");
newbmppath(pFileName1, &file1fb, &pFileName1b);
create_allocate_bmp_file(pFileName1b, &bmp_file_header, &bmheader);
//矩形中值滤波m_rec1_m、m_rec1_n是矩形窗口大小,由编辑框手动输入
rec_median_filter(g_noise_array, out_array, h1, w1, m_rec1_m, m_rec1_n);//矩形中值滤高斯
//rec_median_filter(sp_noise_array, out_array, h1, w1, m_rec2_m, m_rec2_n);//矩形中值滤椒盐
//rhomb_median_filter(g_noise_array, out_array, h1, w1, m_rhomb1);//菱形中值滤高斯
//rhomb_median_filter(sp_noise_array, out_array, h2, w2, m_rhomb2);//菱形中值滤椒盐
//crosswire_median_filter(g_noise_array, out_array, h1, w2, m_crosswire1);//十字丝中值滤高斯
//crosswire_median_filter(sp_noise_array, out_array, h1, w2, m_crosswire2);//十字丝中值滤椒盐
//rec_ava_filter(g_noise_array, out_array, h1, w1, m_rec1_m, m_rec1_n);//矩形均值滤高斯
//rec_ava_filter(sp_noise_array, out_array, h1, w1, m_rec2_m, m_rec2_n);//矩形均值滤椒盐
//rhomb_ava_filter(g_noise_array, out_array, h1, w1, m_rhomb1);//菱形均值滤高斯
//rhomb_ava_filter(sp_noise_array, out_array, h2, w2, m_rhomb2);//菱形均值滤椒盐
//crosswire_ava_filter(g_noise_array, out_array, h1, w2, m_crosswire1);//十字丝均值滤高斯
//crosswire_ava_filter(sp_noise_array, out_array, h1, w2, m_crosswire2);//十字丝均值滤椒盐
for (i = 0; i < h1; i++)
{
for (j = 0; j < w1; j++)
{
gramf1b[out_array[i][j]]++;
}
}
write_bmp_image(pFileName1b, out_array);
free_image_array(out_array, h1);
Cmedian_filtering_LXDlg::showbmp(file1fb, 4);//显示灰度变换图1
}
矩形中值滤波
水平有限,代码较low,有错请指
//矩形中值滤波
void rec_median_filter(short** in_array, short** out_array, long height, long width, int m, int n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0, p = 0, q = 0;
int *parray = (int *)malloc(sizeof(int) * m*n);//给数组分配内存
int temp;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1b[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - m; i++)//height - m去除窗口到不了的边缘行
{
for (j = 0; j < width - n; j++)//width - n去除窗口到不了的边缘行
{
for (k = 0; k < m; k++)//以窗口左上角为起点依次将窗口所有灰度值元素copy进一个数组,数组的个数是窗口元素个数m*n个
{
for (l = 0; l < n; l++)
{
parray[a] = in_array[i + k][j + l];//灰度值进数组
a++;//写进下一个数组元素
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度的数组排序
for (p = 0; p < m*n; p++)
{
for (q = 0; q < m*n - p - 1; q++)
{
if (parray[q] > parray[q + 1])
{
// 互换
temp = parray[q];
parray[q] = parray[q + 1];
parray[q + 1] = temp;
}
}
}
// 计算中值
if ((m*n & 1) > 0)
{
// 数组有奇数个元素,返回中间一个元素
temp = parray[(m*n + 1) / 2];
}
else
{
// 数组有偶数个元素,返回中间两个元素平均值
temp = (parray[m*n / 2] + parray[m*n / 2 + 1]) / 2;
}
out_array[i][j] = temp;
}
}
//初始化内存
memset(parray, 0x00, sizeof(int) * m*n);
//释放内存
free(parray);
}
菱形中值滤波
//菱形中值滤波
void rhomb_median_filter(short** in_array, short** out_array, long height, long width, int rhomb_n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0, p = 0, q = 0;
int num = 2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1;//给数组分配内存,(2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1)是菱形块中元素个数
int *parray = (int *)malloc(sizeof(int) *num);
int temp;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1c[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - (2 * rhomb_n - 2); i++)//height - (2*rhomb_n - 2)去除窗口到不了的边缘行
{
for (j = 0; j < width - (2 * rhomb_n - 2); j++)//width - (2 * rhomb_n - 2)去除窗口到不了的边缘列
{
//以窗口左上角为起点依次将菱形窗口中该有位置的元素copy进一个数组,数组的个数是窗口元素个数(2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1)个
for (int k = 1; k <= rhomb_n; k++)//前n行
{
for (int l = 1; l <= 2 * k - 1; l++)
{
parray[a] = in_array[i + k - 1][j + rhomb_n - k + l - 1];//灰度值进数组
a++;
}
}
for (int k = rhomb_n + 1; k < 2 * rhomb_n; k++)//n+1行到最后一行(2n-1行)
{
//if (k > rhomb_n)//debug用
//{
// k = k;
//}
for (int l = 1; l <= (2 * rhomb_n - 1 - (k-rhomb_n)*2); l++)
{
parray[a] = in_array[i + k - 1][j + k - rhomb_n + l - 1];
a++;
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度的数组排序
for (p = 0; p < num; p++)
{
for (q = 0; q < num - p - 1; q++)
{
if (parray[q] > parray[q + 1])
{
// 互换
temp = parray[q];
parray[q] = parray[q + 1];
parray[q + 1] = temp;
}
}
}
// 计算中值
if ((num & 1) > 0)
{
// 数组有奇数个元素,返回中间一个元素
temp = parray[(num + 1) / 2];
}
else
{
// 数组有偶数个元素,返回中间两个元素平均值
temp = (parray[num / 2] + parray[num / 2 + 1]) / 2;
}
out_array[i][j] = temp;
if (out_array[i][j] < 0 || out_array[i][j]>256)
{
out_array[i][j] = temp;
}
}
}
//
//初始化内存
memset(parray, 0x00, sizeof(int) * num);
//释放内存
free(parray);
}
十字丝中值滤波
//十字丝中值滤波
void crosswire_median_filter(short** in_array, short** out_array, long height, long width, int cw_n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0, p = 0, q = 0;
int num = 4 * cw_n - 3;//给数组分配内存,4 * cw_n - 3是十字丝元素个数
int *parray = (int *)malloc(sizeof(int) *num);
int temp;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1d[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - (2 * cw_n - 2); i++)//height - (2*cw_n - 2)去除窗口到不了的边缘行
{
for (j = 0; j < width - (2 * cw_n - 2); j++)//width - (2 * cw_n - 2)去除窗口到不了的边缘列
{
//以窗口左上角为起点依次将十字丝窗口中该有位置的元素copy进一个数组,数组的个数是窗口元素个数(4 * cw_n - 3)个
for (int k = 1; k <= 2 * cw_n - 1; k++)//前n行
{
if (k == cw_n)
{
for (int l = 1; l <= 2 * cw_n - 1; l++)
{
parray[a] = in_array[i + k - 1][j + l - 1];//灰度值进数组
a++;
}
}
else
{
parray[a] = in_array[i + k - 1][j + cw_n - 1];//灰度值进数组
a++;
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度的数组排序
for (p = 0; p < num; p++)
{
for (q = 0; q < num - p - 1; q++)
{
if (parray[q] > parray[q + 1])
{
// 互换
temp = parray[q];
parray[q] = parray[q + 1];
parray[q + 1] = temp;
}
}
}
// 计算中值
if ((num & 1) > 0)
{
// 数组有奇数个元素,返回中间一个元素
temp = parray[(num + 1) / 2];
}
else
{
// 数组有偶数个元素,返回中间两个元素平均值
temp = (parray[num / 2] + parray[num / 2 + 1]) / 2;
}
out_array[i][j] = temp;
if (out_array[i][j] < 0 || out_array[i][j]>256)
{
out_array[i][j] = temp;
}
}
}
//
//初始化内存
memset(parray, 0x00, sizeof(int) * num);
//释放内存
free(parray);
}
矩形均值滤波
//矩形均值滤波
void rec_ava_filter(short** in_array, short** out_array, long height, long width, int m, int n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0, p = 0, q = 0;
int *parray = (int *)malloc(sizeof(int) * m*n);//给数组分配内存
int temp=0;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1b[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - m; i++)//height - m去除窗口到不了的边缘行
{
for (j = 0; j < width - n; j++)//width - n去除窗口到不了的边缘行
{
for (k = 0; k < m; k++)//以窗口左上角为起点依次将窗口所有灰度值元素copy进一个数组,数组的个数是窗口元素个数m*n个
{
for (l = 0; l < n; l++)
{
parray[a] = in_array[i + k][j + l];//灰度值进数组
a++;//写进下一个数组元素
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度值计算均值
for (p = 0; p < m*n; p++)
{
temp += parray[p];
}
temp = temp / (m*n);
out_array[i][j] = temp;
//if (out_array[i][j] < 0 || out_array[i][j]>256)//debug用
//{
// out_array[i][j] = temp;
//}
//
}
}
//初始化内存
memset(parray, 0x00, sizeof(int) * m*n);
//释放内存
free(parray);
}
菱形均值滤波
//菱形均值滤波
void rhomb_ava_filter(short** in_array, short** out_array, long height, long width, int rhomb_n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0;
int num = 2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1;//给数组分配内存,(2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1)是菱形块中元素个数
int *parray = (int *)malloc(sizeof(int) *num);
int temp=0;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1c[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - (2 * rhomb_n - 2); i++)//height - (2*rhomb_n - 2)去除窗口到不了的边缘行
{
for (j = 0; j < width - (2 * rhomb_n - 2); j++)//width - (2 * rhomb_n - 2)去除窗口到不了的边缘列
{
//以窗口左上角为起点依次将菱形窗口中该有位置的元素copy进一个数组,数组的个数是窗口元素个数(2 * rhomb_n*rhomb_n - 2 * rhomb_n + 1)个
for (int k = 1; k <= rhomb_n; k++)//前n行
{
for (int l = 1; l <= 2 * k - 1; l++)
{
parray[a] = in_array[i + k - 1][j + rhomb_n - k + l - 1];//灰度值进数组
a++;
}
}
for (int k = rhomb_n + 1; k < 2 * rhomb_n; k++)//n+1行到最后一行(2n-1行)
{
//if (k > rhomb_n)//debug用
//{
// k = k;
//}
for (int l = 1; l <= (2 * rhomb_n - 1 - (k - rhomb_n) * 2); l++)
{
parray[a] = in_array[i + k - 1][j + k - rhomb_n + l - 1];
a++;
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度值计算均值
for (int p = 0; p < num; p++)
{
temp += parray[p];
}
temp = temp / (num);
out_array[i][j] = temp;
if (out_array[i][j] > 256)
{
out_array[i][j] = temp;
}
}
}
//
//初始化内存
memset(parray, 0x00, sizeof(int) * num);
//释放内存
free(parray);
}
十字丝均值滤波
//十字丝均值滤波
void crosswire_ava_filter(short** in_array, short** out_array, long height, long width, int cw_n)
{
int a = 0, i = 0, j = 0, k = 0, l = 0, p = 0, q = 0;
int num = 4 * cw_n - 3;//给数组分配内存,4 * cw_n - 3是十字丝元素个数
int *parray = (int *)malloc(sizeof(int) *num);
int temp=0;
if (parray == 0) {
MessageBox(NULL, _T("分配内存出错"), _T("警告"), MB_OK);
return;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
out_array[i][j] = 0;//初始化行列,必要,不然会导致gramf1d[out_array[i][j]]++这里崩掉;
}
}
for (i = 0; i < height - (2 * cw_n - 2); i++)//height - (2*cw_n - 2)去除窗口到不了的边缘行
{
for (j = 0; j < width - (2 * cw_n - 2); j++)//width - (2 * cw_n - 2)去除窗口到不了的边缘列
{
//以窗口左上角为起点依次将十字丝窗口中该有位置的元素copy进一个数组,数组的个数是窗口元素个数(4 * cw_n - 3)个
for (int k = 1; k <= 2 * cw_n - 1; k++)//前n行
{
if (k == cw_n)
{
for (int l = 1; l <= 2 * cw_n - 1; l++)
{
parray[a] = in_array[i + k - 1][j + l - 1];//灰度值进数组
a++;
}
}
else
{
parray[a] = in_array[i + k - 1][j + cw_n - 1];//灰度值进数组
a++;
}
}
a = 0;//为下一个窗口作准备
//对存好窗口灰度值计算均值
for (p = 0; p < num; p++)
{
temp += parray[p];
}
temp = temp / (num);
out_array[i][j] = temp;
}
}
//
//初始化内存
memset(parray, 0x00, sizeof(int) * num);
//释放内存
free(parray);
}
结果
中值滤波结果
均值滤波结果
完
学习笔记,如有错漏,敬请指正
--------------------------------------------------------------------------------------------诺有缸的高飞鸟202007