C/C++图像处理3 中值、均值滤波

内容

对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;
		}
	}
}

参考:c语言数字图像处理(八):噪声模型及均值滤波器

椒盐

添加椒盐噪声按钮

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

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺有缸的高飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值