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

来源:互联网 发布:spss数据差异性分析 编辑:程序博客网 时间:2024/06/05 06:20

转载自http://blog.csdn.net/ironyoung/article/details/41170299


image processing 系列

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

高斯滤波:

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

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

首先,我们需要根据核半径(代码中slab = 2*r + 1)、σ(sigma)求出高斯核函数矩阵:
[cpp] view plaincopyprint?
  1. // get Gaussian Kernel Function  
  2. void ycGaussianKernel(float* kernel, int sigma, int slab)  
  3. {  
  4.     int index;  
  5.     float dx2, dy2;  
  6.     float sum = 0;  
  7.     for(int i=0; i<slab; i++)  
  8.     {  
  9.         dx2 = pow(i - (slab - 1)/2.0, 2);  
  10.         for(int j=0; j<slab; j++)  
  11.         {  
  12.             dy2 = pow(j - (slab - 1)/2.0, 2);  
  13.             index = i*slab + j;  
  14.             kernel[index] = exp(-(dx2 + dy2)/2/pow(sigma, 2)) / (2*PI*pow(sigma, 2));  
  15.             //printf("%f\n", kernel[index]);  
  16.             sum += kernel[index];  
  17.         }  
  18.     }  
  19.   
  20.     for(int k=0; k< slab*slab; k++)  
  21.     {  
  22.         kernel[k] = kernel[k] / sum;  
  23.         //printf("%f\n", kernel[k]);  
  24.     }  
  25. }  
这样可以得到高斯滤波函数为:
[cpp] view plaincopyprint?
  1. // Gaussian filter  
  2. Mat filterGaussian(cv::Mat img, const float sigma, const int slab)  
  3. {  
  4.     cvtColor(img, img, CV_BGR2GRAY);  
  5.     Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);  
  6.     for(int i=0; i<img.rows; i++)  
  7.         for(int j=0; j<img.cols; j++)  
  8.             retMat.at<uchar>(i, j) = img.at<uchar>(i, j);  
  9.   
  10.     // 一维数组模拟二维数组  
  11.     float* kernel = new float[slab * slab];  
  12.     int* xLocation = new int[slab];  
  13.     int* yLocation = new int[slab];  
  14.     ycGaussianKernel(kernel, sigma, slab);  
  15.     float sum;  
  16.     int index;  
  17.   
  18.     // 对于边缘,这里采取直接舍弃不计算的方法。因此,循环起点是 slab/2  
  19.     for(int i= slab/2; i<img.rows - slab/2; i++)  
  20.     {  
  21.         xLocation[slab/2] = i;  
  22.         for(int delta = 0; delta <= slab/2; delta++)  
  23.         {  
  24.             xLocation[slab/2 - delta] = i - delta;  
  25.             xLocation[slab/2 + delta] = i + delta;  
  26.         }  
  27.   
  28.         for(int j= slab/2; j<img.cols - slab/2; j++)  
  29.         {  
  30.             yLocation[slab/2] = j;  
  31.             for(int delta = 0; delta <= slab/2; delta++)  
  32.             {  
  33.                 yLocation[slab/2 - delta] = j - delta;  
  34.                 yLocation[slab/2 + delta] = j + delta;  
  35.             }  
  36.   
  37.             sum = 0;  
  38.             for(int fi=0; fi < slab; fi++)  
  39.             {  
  40.                 for(int fj=0; fj < slab; fj++)  
  41.                 {  
  42.                     index = fi*slab + fj;  
  43.                     sum += kernel[index] * img.at<uchar>(xLocation[fi], yLocation[fj]);  
  44.                 }  
  45.             }  
  46.             retMat.at<uchar>(i ,j) = sum;  
  47.         }  
  48.     }  
  49.   
  50.     return retMat;  
  51. }  

均值滤波

这个没啥好说的,就是函数核内所有像素点求和之后平均,平均值即为核中心上的像素值。需要输入滤波核半径。
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. // Mean filter: 均值滤波器  
  2. Mat filterMean(cv::Mat img, const int slab)  
  3. {  
  4.     cvtColor(img, img, CV_BGR2GRAY);  
  5.     Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);  
  6.     for(int i=0; i<img.rows; i++)  
  7.         for(int j=0; j<img.cols; j++)  
  8.             retMat.at<uchar>(i, j) = img.at<uchar>(i, j);  
  9.   
  10.     int* xLocation = new int[slab];  
  11.     int* yLocation = new int[slab];  
  12.     float sum;  
  13.     int index;  
  14.   
  15.     for(int i= slab/2; i<img.rows - slab/2; i++)  
  16.     {  
  17.         xLocation[slab/2] = i;  
  18.         for(int delta = 0; delta <= slab/2; delta++)  
  19.         {  
  20.             xLocation[slab/2 - delta] = i - delta;  
  21.             xLocation[slab/2 + delta] = i + delta;  
  22.         }  
  23.   
  24.         for(int j= slab/2; j<img.cols - slab/2; j++)  
  25.         {  
  26.             yLocation[slab/2] = j;  
  27.             for(int delta = 0; delta <= slab/2; delta++)  
  28.             {  
  29.                 yLocation[slab/2 - delta] = j - delta;  
  30.                 yLocation[slab/2 + delta] = j + delta;  
  31.             }  
  32.   
  33.             sum = 0;  
  34.             for(int fi=0; fi < slab; fi++)  
  35.             {  
  36.                 for(int fj=0; fj < slab; fj++)  
  37.                 {  
  38.                     index = fi*slab + fj;  
  39.                     sum += img.at<uchar>(xLocation[fi], yLocation[fj]);  
  40.                 }  
  41.             }  
  42.             retMat.at<uchar>(i ,j) = sum/(slab * slab);  
  43.         }  
  44.     }  
  45.   
  46.     return retMat;  
  47. }  

中值滤波

中值滤波跟均值滤波听起来很像,但不是一回事。中值滤波是将滤波核内各个像素由从小到大顺序排列,然后取序列中值作为核中心像素的值。需要输入滤波核半径,并且对于现有的像素序列排序。排序函数我是用快排(quickSort)写的,见这里。滤波器代码:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. // Median filter: 中值滤波器  
  2. Mat filterMedian(cv::Mat img, const int slab)  
  3. {  
  4.     cvtColor(img, img, CV_BGR2GRAY);  
  5.     Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1);  
  6.     for(int i=0; i<img.rows; i++)  
  7.         for(int j=0; j<img.cols; j++)  
  8.             retMat.at<uchar>(i, j) = img.at<uchar>(i, j);  
  9.   
  10.     int* xLocation  = new int[slab];  
  11.     int* yLocation  = new int[slab];  
  12.     int* tmpArr     = new int[slab * slab];  
  13.     float sum;  
  14.     int index;  
  15.   
  16.     for(int i= slab/2; i<img.rows - slab/2; i++)  
  17.     {  
  18.         xLocation[slab/2] = i;  
  19.         for(int delta = 0; delta <= slab/2; delta++)  
  20.         {  
  21.             xLocation[slab/2 - delta] = i - delta;  
  22.             xLocation[slab/2 + delta] = i + delta;  
  23.         }  
  24.   
  25.         for(int j= slab/2; j<img.cols - slab/2; j++)  
  26.         {  
  27.             yLocation[slab/2] = j;  
  28.             for(int delta = 0; delta <= slab/2; delta++)  
  29.             {  
  30.                 yLocation[slab/2 - delta] = j - delta;  
  31.                 yLocation[slab/2 + delta] = j + delta;  
  32.             }  
  33.   
  34.             for(int fi = 0; fi<slab; fi++)  
  35.                 for(int fj =0; fj<slab; fj++)  
  36.                 {  
  37.                     index = fi*slab + fj;  
  38.                     tmpArr[index] = img.at<uchar>(xLocation[fi], yLocation[fj]);  
  39.                 }  
  40.   
  41.             quickSort(tmpArr, 0, slab*slab - 1);  
  42.             retMat.at<uchar>(i ,j) = tmpArr[slab * slab / 2];  
  43.         }  
  44.     }  
  45.   
  46.     return retMat;  
  47. }  

滤波效果

原图为lena图,即:

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


0 0
原创粉丝点击