您的位置:首页 > 其它

高斯平滑滤波的实现与图像内存之间值的复制

2017-08-03 15:23 337 查看
以另外一个滤波器而言----均值滤波器, 就是说某像素的颜色, 由以其为中心的九宫格的像素平均值来决定. 在这个基础上又发展成了带权的“平均”滤波器, 这里的高斯平滑或者说滤波器就是这样一种带权(通常我们认为距离要代替的点像素的作用大一些)的“平均”滤波器. 那么这些权重如何分布呢? 我们先来看几个经典的模板例子:





尝试了使用这些滤波器对我们原来的图进行操作, 得到了这样的一组结果:

原图:



3x3 高斯滤波处理后:



5x5 高斯处理后:



 

单纯从效果来看, 两个模板都起到了平滑的作用, 只是程度有深浅的区分. 那么从理论上来说为什么能起到平滑的作用呢? 很显然, 像素的颜色不仅由自身决定了, 同时有其周围的像素加权决定, 客观上减小了和周围像素的差异.同时这些权重的设定满足了越近权重越大的规律. 从理论来讲, 这些权重的分布满足了著名的所谓高斯分布:

这就是1维的计算公式:


   

这就是2维的计算公式:


 

x, y表示的就是当前点到对应点的距离, 而那些具体的模板就是由这里公式中的一些特例计算而来. 需要说明的是不只有这么一些特例, 从wikipedia可以方便地找到那些复杂的模板比如像:


Sample Gaussian matrix

This is a sample matrix, produced by sampling the Gaussian filter kernel (with σ = 0.84089642) at the midpoints of each pixel and then normalising. Note that the center element (at [4, 4]) has the largest value, decreasing symmetrically as distance from the
center increases.
0.000000670.000022920.000191170.000387710.000191170.000022920.00000067
0.000022920.000786330.006559650.013303730.006559650.000786330.00002292
0.000191170.006559650.054721570.110981640.054721570.006559650.00019117
0.000387710.013303730.110981640.225083520.110981640.013303730.00038771
0.000191170.006559650.054721570.110981640.054721570.006559650.00019117
0.000022920.000786330.006559650.013303730.006559650.000786330.00002292
0.000000670.000022920.000191170.000387710.000191170.000022920.00000067
是不是看到就头大了?不过没关系, 对于一般的应用来说, 前面的例子已经可以完成任务了.  代码的话我们还是给一份5x5的example:

[html] view
plain copy

 print?

void gaussianFilter2 (unsigned char* corrupted, unsigned char* smooth, int width, int height)    

{    

    int templates[25] = { 1, 4, 7, 4, 1,     

                          4, 16, 26, 16, 4,     

                          7, 26, 41, 26, 7,    

                          4, 16, 26, 16, 4,     

                          1, 4, 7, 4, 1 };        //滤波器模板  

        

    memcpy ( smooth, corrupted, width*height*sizeof(unsigned char) );  //复制像素  

    for (int j=2;j<height-2;j++)  //边缘不处理  

    {    

        for (int i=2;i<width-2;i++)    

        {    

            int sum = 0;    

            int index = 0;    

            for ( int m=j-2; m<j+3; m++)    

            {    

                for (int n=i-2; n<i+3; n++)    

                {    

                    sum += corrupted [ m*width + n] * templates[index++] ;    

                }    

            }    

            sum /= 273;    

            if (sum > 255)    

                sum = 255;    

            smooth [ j*width+i ] = sum;    

        }    

    }    



今天也尝试了图像复原算法的研究,其实图像复原算法与傅里叶变换与滤波的关系很大。下面为一部分代码

# include <opencv2/core/core.hpp>

# include <opencv2/highgui/highgui.hpp>

# include <opencv2/imgproc/imgproc.hpp>

#include <iostream>

using namespace cv;

using namespace std;

void gaussianFilter2 (unsigned char* corrupted, unsigned char* smooth, int width, int height)    

{    
int templates[25] = { 1, 4, 7, 4, 1,     
4, 16, 26, 16, 4,     
7, 26, 41, 26, 7,    
4, 16, 26, 16, 4,     
1, 4, 7, 4, 1 };        //滤波器模板  
//定义卷积核算子
cv::Mat kernal = (cv::Mat_<float>(3,3)<< 1,1,1,
1,1,1,
1,1,1);

memcpy ( smooth, corrupted, width*height*sizeof(unsigned char) );  //复制像素  
for (int j=2;j<height-2;j++)  //边缘不处理  
{    
for (int i=2;i<width-2;i++)    
{    
int sum = 0;    
int index = 0;    
for ( int m=j-2; m<j+3; m++)    
{    
for (int n=i-2; n<i+3; n++)    
{    
sum += corrupted [ m*width + n] * templates[index++] ;    
}    
}    
sum /= 273;    
if (sum > 255)    
sum = 255;    
smooth [ j*width+i ] = sum;    
}    
}    

}  

cv::Mat DFT(cv::Mat srcImage)

{

cv::Mat srcGray;
cvtColor(srcImage,srcGray,CV_RGB2GRAY);
// 将输入图像延扩到最佳的尺寸
int nRows = getOptimalDFTSize(srcImage.rows);
int nCols = getOptimalDFTSize(srcImage.cols);
cv::Mat resultImage;
// 把灰度图像放在左上角,在右边和下边扩展图像,
// 添加的像素初始化为0
copyMakeBorder(srcGray, resultImage, 0,
nRows - srcGray.rows, 
0, nCols - srcGray.cols, 
BORDER_CONSTANT, Scalar::all(0));
// 为傅立叶变换的结果(实部和虚部)分配存储空间
cv::Mat planes[] = { cv::Mat_<float>(resultImage), 
cv::Mat::zeros(resultImage.size(), CV_32F)};
Mat completeI;
// 为延扩后的图像增添一个初始化为0的通道
merge(planes,2,completeI);
// 进行离散傅立叶变换
dft(completeI,completeI);
// 将复数转换为幅度

split(completeI,planes);
magnitude(planes[0],planes[1],planes[0]);
cv::Mat dftResultImage = planes[0]; 
// 对数尺度(logarithmic scale)缩放
dftResultImage += 1;
log(dftResultImage,dftResultImage);
// 剪切和重分布幅度图象限
dftResultImage= dftResultImage(Rect(0,
0,srcGray.cols,srcGray.rows));
// 归一化图像
/*normalize(dftResultImage,dftResultImage,
0,1,CV_MINMAX);*/
int cx = dftResultImage.cols/2;
int cy = dftResultImage.rows/2; 
Mat tmp;
// Top-Left - 为每一个象限创建ROI
Mat q0(dftResultImage,Rect(0,0,cx,cy));
// Top-Right
Mat q1(dftResultImage,Rect(cx,0,cx,cy));
// Bottom-Left
Mat q2(dftResultImage,Rect(0,cy,cx,cy));
// Bottom-Right
Mat q3(dftResultImage,Rect(cx,cy,cx,cy)); 
// 交换象限 (Top-Left with Bottom-Right)    
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
// 交换象限 (Top-Right with Bottom-Left)
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
return dftResultImage;

}

int main()

{
cv::Mat srcImage = imread("3.jpg");
Mat dstImage = Mat(srcImage.size(),srcImage.type(),Scalar::all(0));
uchar *dataSrc = srcImage.data;
uchar *dataDst = dstImage.data;
int nRows = srcImage.rows;
int nCols = srcImage.cols;
/*gaussianFilter2(dataSrc,dataDst,nCols,nRows);*/
memcpy(dataDst,dataSrc,sizeof(uchar)*nCols*nRows * 3); 此处为3通道图像
namedWindow("2",0);
imshow("2",dstImage);
waitKey(0);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: