C++实现中值滤波

为了加深对中值滤波算法的理解以及方便以后更好的复习,我将该算法的一些重点细节和实现过程踩过的坑记录下来。

适用对象:带椒盐噪声的图像

由于椒盐噪声像素值与原图像素值没有关联,随机性较大,因此使用中值滤波可有效滤掉噪声。

中值滤波需要对像素值进行排序,因此首先写一个冒泡排序算法。

冒泡排序实现:

为提高效率加入标志位flag,当第i次寻找最大值时,如果相邻两个数均未发生互换,此时flag位为false,即说明此时数组已经按照递增排列,可提前终止。此处应该注意flag=false所在位置,因为需要保证第i次寻找最大值过程中,遍历到所有未参与排列的数据,所以flag=false应该放在循环条件for(int j=0; j<len-1-i; j++)的外部。

void bubble(std::vector<int> &arr, int len)
{
	bool flag = true;
	for (int i = 0; i < len-1; i++)
	{
		while (flag)
		{
			flag = false;
			for (int j = 0; j < len - i - 1; j++)
			{
				
				if (arr[j + 1] < arr[j])
				{
					flag = true;  //只要发生一次交换就继续判断
					int temp = arr[j + 1];
					arr[j + 1] = arr[j];
					arr[j] = temp;
				}
			}
		}
	}	
}

 

 中值滤波的实现:

需要注意的主要问题:

  1. 为了能够遍历到原图的边界,需要对原图进行边界扩充,扩充长度为(窗口的长度-1)/ 2。
  2. 注意利用窗口对扩充后的图像遍历时,起始的位置不是0,而是扩充的长度,因为这时对应的才是原图的第一个像素点,同理结束的位置也是原图的最后一个像素点。
  3. 另外为了方便将窗口内对应的像素存到容器中,可以写两个循环,循环长度为窗口的长度与宽度,依次将像素值存入容器中。
  4. 最后对容器内的像素按照递增排列后,取中值赋给目标矩阵相应的位置,而此时的位置也应该用i-h,对应扩充前的位置。

经实践证明我写的这两个算法可有效使用。

void medianFilter(cv::Mat& src, cv::Mat& dst, cv::Size width)
{
	//判断窗口是否为奇数
	if (width.width % 2 == 0 || width.height % 2 == 0)
	{
		std::cout << "输入窗口大小应该为奇数,请重新输入" << endl;
		exit(-1);
	}
	else
	{
		//计算边界扩充长度
		int h = (width.height - 1) / 2;
		int w = (width.width - 1) / 2;

		//对原图边界扩充
		cv::Mat src_border;
		cv::copyMakeBorder(src, src_border, h, h, w, w, cv::BORDER_REFLECT_101);
		for (int i = h; i < src.rows + h; i++)
		{

			for (int j = w; j < src.cols + w; j++)
			{
				//定义容器存放窗口对应的像素
				std::vector <int> v;
				for (int ii = i - h; ii <= i + h; ii++)
				{
					for (int jj = j - w; jj <= j + w; jj++)
					{

						v.push_back(src_border.at<uchar>(ii, jj));
					}
				}
				//对容器内存放的像素排序
				int len = width.area();
				bubble(v, len);
				//将中值赋给目标图像对应位置
				dst.at<uchar>(i-h, j-w) = v[(len - 1) / 2];
				
			}
		}
		
	}

}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GDAL是一个开源的地理信息系统库,它提供了对各种栅格和矢量地理数据格式的读取和写入功能。中值滤波是一种常用的数字图像处理方法,可以用于去除图像中的噪声。在GDAL中,可以使用C++语言实现中值滤波。 下面是一个使用GDAL C++实现中值滤波的示例代码: ```c++ #include "gdal_priv.h" #include "cpl_conv.h" // for CPLMalloc() int main() { GDALAllRegister(); // 打开输入图像 GDALDataset *poDataset = (GDALDataset *) GDALOpen("input.tif", GA_ReadOnly); if (poDataset == NULL) { printf("Open failed.\n"); exit(1); } // 获取图像宽度和高度 int nXSize = poDataset->GetRasterXSize(); int nYSize = poDataset->GetRasterYSize(); // 创建输出图像 GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); GDALDataset *poDstDS = poDriver->Create("output.tif", nXSize, nYSize, 1, GDT_Float32, NULL); // 定义中值滤波的窗口大小 int nWindowSize = 3; // 定义中值滤波的缓冲区 float *pafWindow = (float *) CPLMalloc(sizeof(float) * nWindowSize * nWindowSize); // 对每个像素进行中值滤波 for (int i = 0; i < nYSize; i++) { for (int j = 0; j < nXSize; j++) { // 读取窗口内的像素值 int nIndex = 0; for (int m = i - nWindowSize / 2; m <= i + nWindowSize / 2; m++) { for (int n = j - nWindowSize / 2; n <= j + nWindowSize / 2; n++) { if (m >= 0 && m < nYSize && n >= 0 && n < nXSize) { pafWindow[nIndex++] = poDataset->GetRasterBand(1)->ReadAsFloat(n, m); } } } // 对窗口内的像素值进行排序 for (int k = 0; k < nIndex - 1; k++) { for (int l = k + 1; l < nIndex; l++) { if (pafWindow[k] > pafWindow[l]) { float fTemp = pafWindow[k]; pafWindow[k] = pafWindow[l]; pafWindow[l] = fTemp; } } } // 将中值赋给输出图像 poDstDS->GetRasterBand(1)->WriteFloat(j, i, pafWindow[nIndex / 2]); } } // 释放资源 CPLFree(pafWindow); GDALClose(poDataset); GDALClose(poDstDS); return 0; } ``` 在上面的代码中,我们首先打开输入图像,然后创建输出图像。接着,我们定义了中值滤波的窗口大小,并创建了一个缓冲区用于存储窗口内的像素值。然后,我们对每个像素进行中值滤波,具体步骤是读取窗口内的像素值,对像素值进行排序,然后将中值赋给输出图像。最后,我们释放了缓冲区和数据集,并返回0表示程序正常结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值