滤波器的原理就是对一个领域(一块较小的区域),对该邻域包围的图像像素执行预定义操作,滤波产生一个新的像素,且坐标为邻域中心的坐标。滤波器的中心访问图像中每一个像素的位置,就产生了处理过的图像也就是滤波图像。简言之,选定要作用于目标位置的像素点(领域),按照一定的运算操作,把通过这些像素点得到的新的像素值赋给目标位置。
可见滤波器是由两部分组成:领域,和领域下的需要执行的预定义操作。如果这个操作是线性的,滤波器就是线性滤波器,否则就是非线性滤波器。
线性滤波器:
使用3X3的领域线性滤波器的机理如下图所示;
图像中任意一点(x, y)处滤波器的操作结果g(x,y)就是滤波器系数与滤波器所包围的像素乘积之和,
g(x,y)=w(-1,-1)f(x-1,y-1) + w(-1,0)f(x-1,y) + w(-1,1)f(x-1,y+1) + …… + w(1,0)f(x+1,y) + w(1,1)f(x+1,y+1)
当滤波器系数都为1时就是均值滤波器此时新的像素值为g(x,y)/9。
若系数为
为加权均值滤波器。此时新的像素值为g(x,y)/16。
实现如下:
void LinearFilter(string src)
{
//kernel
float arr[3][3] = {1,2,1,2,4,2,1,2,1};
/*for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
arr[i][j] = 1;
}
}*/
cv::Mat image = imread(src,0);
namedWindow("original");
imshow("original", image);
cv::Mat image1 = Mat(Size(image.cols + 4, image.rows + 4), image.type(), Scalar(0));
Mat dst = Mat(Size(image.cols + 4, image.rows + 4), image.type(), Scalar(0));
Mat ImageROI = image1(Rect(2, 2, image.cols, image.rows));
image.copyTo(ImageROI, image);
Mat dst1 = Mat(Size(image.cols + 4, image.rows + 4), image.type(), Scalar(0));
//加权均值滤波器
for (int i = 2; i < image1.rows - 2; i++)
{
for (int j = 2; j < image1.cols - 2; j++)
{
if (image.channels() == 1)
{
uchar data = (arr[0][0] * image1.at<uchar>(i - 1, j - 1) + arr[0][1] * image1.at<uchar>(i - 1, j) + arr[0][2] * image1.at<uchar>(i - 1, j + 1) + arr[1][0] * image1.at<uchar>(i, j - 1) + arr[1][1] * image1.at<uchar>(i, j) + arr[1][2] * image1.at<uchar>(i, j + 1) + arr[2][0] * image1.at<uchar>(i + 1, j - 1) + arr[2][1] * image1.at<uchar>(i + 1, j) + arr[2][2] * image1.at<uchar>(i + 1, j + 1))/16;
dst1.at<uchar>(i, j) = data;
}
}
}
//均值滤波器
for (int i = 2; i < image1.rows - 2; i++)
{
for (int j = 2; j < image1.cols - 2; j++)
{
if (image.channels() == 1)
{
uchar data = (image1.at<uchar>(i - 1, j - 1) + image1.at<uchar>(i - 1, j) + image1.at<uchar>(i - 1, j + 1) + image1.at<uchar>(i, j - 1) + image1.at<uchar>(i, j) + image1.at<uchar>(i, j + 1) + image1.at<uchar>(i + 1, j - 1) + image1.at<uchar>(i + 1, j) + image1.at<uchar>(i + 1, j + 1)) / 9;
dst.at<uchar>(i, j) = data;
}
}
}
namedWindow("linear9");
imshow("linear9", dst);
namedWindow("linear16");
imshow("linear16", dst1);
}
注意:需要在计算data值时就进行取平均值,uchar类型的最大值是255,当data超过255时,就不再是想要的值。
高斯滤波原理是和均值滤波一样的,只是滤波器系数的变化而已,产生Guass滤波系数的函数是
以sigma=1,3X3的高斯滤波为例:
void guassFilter(Mat &src, Mat &dst)
{
double pi = 3.14159265358;
double sum = 0;
double arr[3][3];
for (int i = 1; i < 4; i++)
{
for (int j = 1; j < 4; j++)
{
arr[i-1][j-1] = exp(-((i-2)*(i-2) + (j-2)*(j-2)) / (2*1.0)) / (2 * pi);
sum += arr[i - 1][j - 1];
}
}
//归一化
for (int i = 1; i < 4; i++)
{
for (int j = 1; j < 4; j++)
{
arr[i - 1][j - 1] = arr[i - 1][j - 1] / sum;
}
}
for (int i = 2; i < dst.rows - 2; i++)
{
for (int j = 2; j < dst.cols - 2; j++)
{
if (src.channels() == 1)
{
uchar data = (arr[0][0] * src.at<uchar>(i - 1, j - 1) + arr[0][1] * src.at<uchar>(i - 1, j) + arr[0][2] * src.at<uchar>(i - 1, j + 1) + arr[1][0] * src.at<uchar>(i, j - 1) + arr[1][1] * src.at<uchar>(i, j) + arr[1][2] * src.at<uchar>(i, j + 1) + arr[2][0] * src.at<uchar>(i + 1, j - 1) + arr[2][1] * src.at<uchar>(i + 1, j) + arr[2][2] * src.at<uchar>(i + 1, j + 1));
dst.at<uchar>(i, j) = data;
}
}
}
namedWindow("Guass");
imshow("Guass", dst);
}
非线性滤波器
非线性滤波器以3X3的中指滤波器为例:
中指滤波器
是将邻域所包围的图像像素进行排序,取其中值赋值给滤波器中心位置的像素。
代码如下
void swap(uchar *p1, uchar *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
//内插排序
void insertSort(uchar *a, int len)
{
int i, j;
for (i = 0; i<len; i++)
{
for (j = i + 1; j >= 1; j--)
{
if (a[j]<a[j - 1])
swap(&a[j], &a[j - 1]);
}
}
}
void midValueFilter(string src)
{
cv::Mat image = imread(src, 0);
namedWindow("original");
imshow("original", image);
cv::Mat image1 = Mat(Size(image.cols + 4, image.rows + 4), image.type(), Scalar(0));
Mat dst = Mat(Size(image.cols + 4, image.rows + 4), image.type(), Scalar(0));
Mat ImageROI = image1(Rect(2, 2, image.cols, image.rows));
image.copyTo(ImageROI, image);
for (int i = 2; i < image1.rows - 2; i++)
{
for (int j = 2; j < image1.cols - 2; j++)
{
if (image.channels() == 1)
{
uchar data[9] = { image1.at<uchar>(i - 1, j - 1) , image1.at<uchar>(i - 1, j) , image1.at<uchar>(i - 1, j + 1) ,image1.at<uchar>(i, j - 1) , image1.at<uchar>(i, j) , image1.at<uchar>(i, j + 1),image1.at<uchar>(i + 1, j - 1) , image1.at<uchar>(i + 1, j) , image1.at<uchar>(i + 1, j + 1) };
insertSort(data, 9);
dst.at<uchar>(i, j) = data[4];
}
}
}
namedWindow("midValue");
imshow("midValue", dst);
}
我在使用vs2013运行时会出现数组越界异常
在网上找了很多技术文章大都是说,项目占用堆栈较大时,超出了vs编译器限定的对战的大小,就会报异常。
把 project->配置属性->c/c++->代码生成->基本运行时检查 设置为 “默认值”即可解决问题