1、中值滤波
中值滤波是对一个滑动窗口内的诸像素灰度值排序,用其中值代替窗口中心象素的原来灰度值,它是一种非线性的图像平滑法,它对脉冲干扰级椒盐噪声的抑制效果好,在抑制随机噪声的同时能有效保护边缘少受模糊。
二维中值滤波算法是:对于一幅图像的象素矩阵,取以目标象素为中心的一个子矩阵窗口,这个窗口可以是3*3 ,5*5 等根据需要选取,对窗口内的象素灰度排序,取中间一个值作为目标象素的新灰度值。
步骤:
1:通过从图像中的某个采样窗口取出奇数个数据进行排序
在这里,我们选用的排序方法是冒泡排序
2:用排序后的中值取代要处理的数据即可
一般的,中值滤波对图像的边界用0做扩张,所以对边界可能会出现扭曲。在这里,我对边界进行了填充,用里圈的值来填充外圈的值。若要用0填充外圈,可将imagedatafilter初始化为0:
memset(imagedatafilter,0,linebyte*bmpHeight);如果这样,那填充的那个循环就可以去掉不要了,具体代码如下:
#include <cstring> #include <windows.h> #include"readbmp.h" #include"savebmp.h" #include<assert.h> #define iFilterW 3 #define iFilterH 3 unsigned char GetMedianNum(int * bArray, int iFilterLen) { int i, j;// 循环变量 unsigned char bTemp; // 用冒泡法对数组进行排序 for (j = 0; j < iFilterLen - 1; j++) { for (i = 0; i < iFilterLen - j - 1; i++) { if (bArray[i] > bArray[i + 1]) { // 互换 bTemp = bArray[i]; bArray[i] = bArray[i + 1]; bArray[i + 1] = bTemp; } } } // 计算中值 if ((iFilterLen & 1) > 0) { // 数组有奇数个元素,返回中间一个元素 bTemp = bArray[(iFilterLen + 1) / 2]; } else { // 数组有偶数个元素,返回中间两个元素平均值 bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2; } return bTemp; } void image_filter_median() { char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\jiaoyan.bmp"; readBmp(readPath); unsigned char *imagedatafilter; unsigned char *imagedata; imagedata = pBmpBuf; int aValue[iFilterH*iFilterW]; // 指向滤波器数组的指针 int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4; imagedatafilter = new unsigned char[lineByte * bmpHeight]; int iFilterHM= (iFilterH - 1)/ 2; int iFilterWM = (iFilterW - 1) / 2; for (int i = iFilterHM; i < bmpHeight - iFilterHM; i++) for (int j = iFilterWM; j < bmpWidth - iFilterWM; j++) for (int k = 0; k < 3; k++) { for (int m = 0; m< iFilterH; m++) for (int n = 0; n < iFilterW; n++) { aValue[m * iFilterW + n] = *(imagedata + lineByte* (i+m-1) + (j + n-1) * 3 + k); } *(imagedatafilter + bmpWidth * 3 * i + j * 3 + k) = GetMedianNum(aValue, iFilterH * iFilterW); } for (int i = 0; i < bmpHeight; i++) for (int j = 0; j < bmpWidth; j++) for (int k = 0; k < 3; k++) { if ((i<iFilterHM) && (j<iFilterWM)) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + (j + iFilterWM) * 3 + k); else if ((i<iFilterHM) && (j>=iFilterWM)&&(j<(bmpWidth - iFilterWM))) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + j * 3 + k); else if ((i<iFilterHM) && ( j >= (bmpWidth - iFilterWM))) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + (j - iFilterWM) * 3 + k); else if ((i>=iFilterHM) && i <(bmpHeight - iFilterHM) && (j< iFilterWM)) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* i + (j + iFilterWM) * 3 + k); else if ((i>=iFilterHM) && i < (bmpHeight - iFilterHM) && (j >= (bmpWidth - iFilterWM))) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* i + (j - iFilterWM) * 3 + k); else if ((i >= (bmpHeight - iFilterHM)) && (j< iFilterWM)) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + (j + iFilterWM) * 3 + k); else if ((i >= (bmpHeight - iFilterHM)) && (j>= iFilterWM)&&(j<(bmpWidth - iFilterWM))) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + j * 3 + k); else if ((i >= (bmpHeight - iFilterHM)) && ( j >= (bmpWidth - iFilterWM))) *(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + (j - iFilterWM) * 3 + k); } char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\mm.bmp"; saveBmp(writePath, imagedatafilter, bmpWidth, bmpHeight, biBitCount, pColorTable); printf("中值滤波操作完成,请查看bmp文件。\n\n"); }
原图:
滤波后: