您的位置:首页 > 运维架构

【图像处理】基于OpenCV底层实现的滤波

2015-03-26 21:46 831 查看
转载自http://blog.csdn.net/ironyoung/article/details/41170299

image processing 系列

【图像处理】直方图匹配
【图像处理】图片旋转

高斯滤波:

高斯滤波器介绍:wikipedia。高斯滤波器的未知数(或者说函数输入)有两个:(1)滤波器核半径;(2)σ(正态分布的标准偏差)。在连续二维空间中,这个函数长这样:



除了函数中心是极大值,周围都是围绕中心对称的。

这样有一个好处,因为滤波器实质上是卷积(convolution)操作,卷积操作需要将核函数围绕中心翻转之后,在与对应矩阵中各个数相乘(注意:此时不是矩阵相乘,只是函数核中每个数字单独的相乘,不涉及整体相乘求和)。而高斯函数的对称的,所以函数核翻不翻转都一样结果。

首先,我们需要根据核半径(代码中slab = 2*r + 1)、σ(sigma)求出高斯核函数矩阵:

[cpp] view
plaincopyprint?

// get Gaussian Kernel Function

void ycGaussianKernel(float* kernel, int sigma, int slab)

{

int index;

float dx2, dy2;

float sum = 0;

for(int i=0; i<slab; i++)

{

dx2 = pow(i - (slab - 1)/2.0, 2);

for(int j=0; j<slab; j++)

{

dy2 = pow(j - (slab - 1)/2.0, 2);

index = i*slab + j;

kernel[index] = exp(-(dx2 + dy2)/2/pow(sigma, 2)) / (2*PI*pow(sigma, 2));

//printf("%f\n", kernel[index]);

sum += kernel[index];

}

}

for(int k=0; k< slab*slab; k++)

{

kernel[k] = kernel[k] / sum;

//printf("%f\n", kernel[k]);

}

}

这样可以得到高斯滤波函数为:

[cpp] view
plaincopyprint?

// Gaussian filter

Mat filterGaussian(cv::Mat img, const float sigma, const int slab)

{

cvtColor(img, img, CV_BGR2GRAY);

Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);

for(int i=0; i<img.rows; i++)

for(int j=0; j<img.cols; j++)

retMat.at<uchar>(i, j) = img.at<uchar>(i, j);

// 一维数组模拟二维数组

float* kernel = new float[slab * slab];

int* xLocation = new int[slab];

int* yLocation = new int[slab];

ycGaussianKernel(kernel, sigma, slab);

float sum;

int index;

// 对于边缘,这里采取直接舍弃不计算的方法。因此,循环起点是 slab/2

for(int i= slab/2; i<img.rows - slab/2; i++)

{

xLocation[slab/2] = i;

for(int delta = 0; delta <= slab/2; delta++)

{

xLocation[slab/2 - delta] = i - delta;

xLocation[slab/2 + delta] = i + delta;

}

for(int j= slab/2; j<img.cols - slab/2; j++)

{

yLocation[slab/2] = j;

for(int delta = 0; delta <= slab/2; delta++)

{

yLocation[slab/2 - delta] = j - delta;

yLocation[slab/2 + delta] = j + delta;

}

sum = 0;

for(int fi=0; fi < slab; fi++)

{

for(int fj=0; fj < slab; fj++)

{

index = fi*slab + fj;

sum += kernel[index] * img.at<uchar>(xLocation[fi], yLocation[fj]);

}

}

retMat.at<uchar>(i ,j) = sum;

}

}

return retMat;

}


均值滤波

这个没啥好说的,就是函数核内所有像素点求和之后平均,平均值即为核中心上的像素值。需要输入滤波核半径。

[cpp] view
plaincopyprint?





// Mean filter: 均值滤波器

Mat filterMean(cv::Mat img, const int slab)

{

cvtColor(img, img, CV_BGR2GRAY);

Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);

for(int i=0; i<img.rows; i++)

for(int j=0; j<img.cols; j++)

retMat.at<uchar>(i, j) = img.at<uchar>(i, j);

int* xLocation = new int[slab];

int* yLocation = new int[slab];

float sum;

int index;

for(int i= slab/2; i<img.rows - slab/2; i++)

{

xLocation[slab/2] = i;

for(int delta = 0; delta <= slab/2; delta++)

{

xLocation[slab/2 - delta] = i - delta;

xLocation[slab/2 + delta] = i + delta;

}

for(int j= slab/2; j<img.cols - slab/2; j++)

{

yLocation[slab/2] = j;

for(int delta = 0; delta <= slab/2; delta++)

{

yLocation[slab/2 - delta] = j - delta;

yLocation[slab/2 + delta] = j + delta;

}

sum = 0;

for(int fi=0; fi < slab; fi++)

{

for(int fj=0; fj < slab; fj++)

{

index = fi*slab + fj;

sum += img.at<uchar>(xLocation[fi], yLocation[fj]);

}

}

retMat.at<uchar>(i ,j) = sum/(slab * slab);

}

}

return retMat;

}

中值滤波

中值滤波跟均值滤波听起来很像,但不是一回事。中值滤波是将滤波核内各个像素由从小到大顺序排列,然后取序列中值作为核中心像素的值。需要输入滤波核半径,并且对于现有的像素序列排序。排序函数我是用快排(quickSort)写的,见这里。滤波器代码:

[cpp] view
plaincopyprint?





// Median filter: 中值滤波器

Mat filterMedian(cv::Mat img, const int slab)

{

cvtColor(img, img, CV_BGR2GRAY);

Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);

for(int i=0; i<img.rows; i++)

for(int j=0; j<img.cols; j++)

retMat.at<uchar>(i, j) = img.at<uchar>(i, j);

int* xLocation = new int[slab];

int* yLocation = new int[slab];

int* tmpArr = new int[slab * slab];

float sum;

int index;

for(int i= slab/2; i<img.rows - slab/2; i++)

{

xLocation[slab/2] = i;

for(int delta = 0; delta <= slab/2; delta++)

{

xLocation[slab/2 - delta] = i - delta;

xLocation[slab/2 + delta] = i + delta;

}

for(int j= slab/2; j<img.cols - slab/2; j++)

{

yLocation[slab/2] = j;

for(int delta = 0; delta <= slab/2; delta++)

{

yLocation[slab/2 - delta] = j - delta;

yLocation[slab/2 + delta] = j + delta;

}

for(int fi = 0; fi<slab; fi++)

for(int fj =0; fj<slab; fj++)

{

index = fi*slab + fj;

tmpArr[index] = img.at<uchar>(xLocation[fi], yLocation[fj]);

}

quickSort(tmpArr, 0, slab*slab - 1);

retMat.at<uchar>(i ,j) = tmpArr[slab * slab / 2];

}

}

return retMat;

}


滤波效果

原图为lena图,即:


对于高斯滤波,当sigma = 3,核函数为 3*3(slab = 3,核半径为 1)时,结果为:


对于均值滤波,当核函数为 5*5(slab = 5,核半径为 2)时,结果为:


对于中值滤波,当核函数为 7*7(slab = 7,核半径为 3)时,结果为:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: