概述
均值滤波的模板可为33,55,7*7等,为此我们在写函数时尽量不要把模板写死,把模板写在main函数里,再用函数调用模板。
将模板与图像进行卷积时,边缘像素总是需要特殊处理,我采用对边缘填充0的方法以使得边缘像素也可进行卷积。
#include<iostream>
#include<opencv2/opencv.hpp>
#define MAX 100
using namespace cv;
using namespace std;
//图像填充
void img_Filling(Mat& srcImg, Mat& dstImg, int n) //图像上下左右各填充n/2行n/2列
{
dstImg = Mat::zeros(srcImg.rows + n-1, srcImg.cols + n-1, srcImg.type());
for (int i = 0; i < srcImg.rows; i++) //对行操作
{
for (int j = 0; j < srcImg.cols; j++) //对列操作
{
for (int c = 0; c < 3; c++) //分别对B G R操作
{
uchar* data1 = srcImg.ptr<uchar>(i, j);
uchar* data2 = dstImg.ptr<uchar>(i + n / 2, j + n / 2);
data2[c] = data1[c];
}
}
}
}
//n*n均值滤波
void img_Average(Mat& srcImg, Mat& dstImg, int Mask[MAX][MAX], int n)
{
Mat tmp;
img_Filling(srcImg, tmp, n); //图像填充
for (int i = n/2; i < srcImg.rows+n/2; i++) //对填充后的图像从有图像区域开始滤波
{
for (int j = n/2; j < srcImg.cols+n/2; j++)
{
for (int c = 0; c < 3; c++)
{
int sum = 0;
int RIO[MAX][MAX] = { 0 };
for (int x = 0; x < n; x++) //对RIO矩阵赋值
for (int y = 0; y < n; y++)
RIO[x][y] = tmp.at<Vec3b>(i - n / 2 + x, j - n / 2 + y)[c];
for (int m = 0; m < n; m++)
{
for (int n1 = 0; n1 < n; n1++)
{
sum += Mask[m][n1] * RIO[m][n1];
}
}
dstImg.at<Vec3b>(i-n/2, j-n/2)[c] = sum/(n*n) ;
}
}
}
}
void main()
{
int mask[MAX][MAX];
for (int i = 0; i < MAX; i++)
for (int j = 0; j < MAX; j++)
mask[i][j] = 1;
Mat srcImg = imread("lena.jpg");
Mat dstImg = Mat::zeros(srcImg.rows, srcImg.cols, srcImg.type());
img_Average(srcImg, dstImg,mask,5);
imshow("原图", srcImg);
waitKey(100);
imshow("均值滤波", dstImg);
waitKey();
}
示例
结果