接下来中值取代函数框中央的灰度值,具有简易、非

一 双边滤波简介

  双边滤波(Bilateral filter)是1种非线性的滤波方法,是构成图像的长空邻近度和像素值相似度的壹种折衷处理,同时考虑空域消息和灰度相似性,达到保边去噪的指标。具有简易、非迭代、局地的风味。

  双边滤波器的益处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较显著地歪曲边缘,对于频仍细节的维护效能并不分明。双边滤波器顾名思义比高斯滤波多了贰个高斯方差sigma-d,它是依照空间分布的高斯滤波函数,所以在边缘左近,离的较远的像素不会太多影响到边缘上的像素值,那样就保险了边缘相近像素值的保存。可是出于保存了过多的高频音讯,对于彩色图像里的1再噪声,双边滤波器不可能彻底的滤掉,只可以够对于低频音信举办较好的滤波。

 

一、线性滤波与非线性滤波

事先1篇小说说的正方滤波、均值滤波和高斯滤波都是线性滤波器的原本数据与滤波结果是1种线性的算术运算,即用加减乘除等运算达成,所以称之为线性滤波。

非线性滤波器的本来数据与滤波结果是一种逻辑关系,即通过比较一定邻域内的灰度值大小来兑现的。上面介绍的中值滤波和双方滤波就是非线性滤波。

二 双边滤波原理

  滤波算法中,目标点上的像素值常常是由其所在地点上的方圆的1个小一些邻居像素的值所决定。在贰D高斯滤波中的具体实现就是对周围的终将范围内的像素值分别赋以不一致的高斯权重值,并在加权平均后获取当前点的末梢结出。而那边的高斯权重因子是行使多少个像素之间的长空中距离离(在图像中为二D)关系来扭转。通过高斯分布的曲线能够发现,离目的像素越近的点对最终结出的进献越大,反之则越小。其公式化的讲述相似如下所述:

                     710官方网站 1

   在那之中的c即为依照空间距离的高斯权重,而用来对结果实行单位化。

  高斯滤波在低通滤波算法中有正确的显示,可是其却有其余三个标题,那便是只思量了像素间的上空地方上的关联,由此滤波的结果会丢掉边缘的新闻。那里的边缘首若是指图像中重大的不一致颜色区域(比如土褐的苍天,巴黎绿的毛发等),而Bilateral正是在Gaussian blur中进入了其它的一个权重分部来化解这一难点。Bilateral滤波中对此边缘的涵养通过下述表达式来促成:

                     710官方网站 2

                    710官方网站 3

  个中的s为基于像素间相似程度的高斯权重,同样用来对结果举办单位化。对双边进行重组即能够博得基于空间距离、相似程度综合考虑衡量的Bilateral滤波:

                  710官方网站 4

  上式中的单位化分部综合了三种高斯权重于联合而获得,当中的c与s计算可以详细描述如下:

                  710官方网站 5

   且有710官方网站 6

                   710官方网站 7

   且有710官方网站 8

  上述给出的表明式均是在半空中上的无比积分,而在像素化的图像中本来不可能这么做,而且也没供给这么做,由此在采纳前须求对其展开离散化。而且也不需求对此各个局地像素从整张图像上拓展加权操作,距离抢先一定程度的像素实际上对当前的靶子像素影响很小,能够忽略的。限定局地子区域后的离散化公就能够简化为如下形式:

                   710官方网站 9

  上述辩护公式就结成了Bilateral滤波达成的底子。为了直观地询问高斯滤波与五头滤波的不同,大家能够从下列图示中来看依据。假诺指标源图像为下述左右区域泾渭明显的包罗噪声的图像(由程序自动生成),藤黄框的主导即为目的像素所在的地点,那么当前像素处所对应的高斯权重与互相权重因子3D可视化后的形制如前面两图所示:

                   710官方网站 10

  左图为原始的噪音图像;中间为高斯采集样品的权重;右图为Bilateral采集样品的权重。从图中得以看出Bilateral参预了貌似程度分部今后可以将源图像左侧那多少个跟当前像素差值过大的点给滤去,那样就很好地涵养了边缘。为了特别形象地洞察两者间的界别,使用Matlab将该图在三种分歧方式下的惊人图3D绘制出来,如下:

                 710官方网站 11

  上述3图从左到右依次为:双边滤波,原始图像,高斯滤波。从中度图中能够鲜明看出Bilateral和Gaussian三种情势的界别,前者较好地保全了边缘处的梯度,而在高斯滤波中,由于其在边缘处的变型是线性的,因此就采纳连累的梯度突显出渐变的动静,而这表未来图像中的话就是境界的散失(图像的演示可知于后述)。         

 

二、中值滤波

中值滤波原理通过一张图就能够看明白:

710官方网站 12

简言之中值滤波就是把函数框(如图中的叁 X
3)内的灰度值按顺序排列,然后中值取代函数框中央的灰度值。所以一般选拔奇数点的邻域来总括中值,但如若像素点数为偶数,中值就取排序像素中间两点的平均值。

中值滤波在自然的尺码下能够摆日常见线性滤波器如方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲困扰及图像扫描噪声非凡实惠,也常用来维护边缘音信,
保存边缘的特点使它在不希望现身边缘模糊的场馆也很有用,是相当经典的平整噪声处理措施。

可是中值滤波的通病也很醒目,因为要开始展览排序操作,所以拍卖的时日长,是均值滤波的5倍以上。

中值滤波在OpenCV中用medianBlur函数达成,下边是函数注解:

void medianBlur( InputArray src, OutputArray dst, int ksize );

参数很简短,就是输入图像src,输出图像dst,以及核的大小ksize。注意那里的ksize必须为正奇数壹,三,五,七……不然程序会出错。

三 双边滤波实现步骤

  有了上述辩白之后完毕比拉teral Filter就相比简单了,其实它也与壹般的Gaussian Blur未有太大的界别。那里最首要包含三有的的操作: 基于空间距离的权重因子变化;基于相似度的权重因子的变动;最后filter颜色的计量。

 

3、双边滤波

双方滤波(Bilateral
filter)是一种非线性的滤波方法,是构成图像的上空周边度和像素值相似度的壹种折衷处理,同时思索空域音信和灰度相似性,达到保边去噪的目标。具有简易、非迭代、局地的性状。
互相滤波器的益处是能够做边缘保存(edge
preserving),一般用高斯滤波去降噪,会较强烈地混淆边缘,对于频仍细节的护卫功效并不强烈。双边滤波器顾名思义比高斯滤波多了二个高斯方差sigma-d,它是依照空间分布的高斯滤波函数,所以在边缘周围,离的较远的像素不会太多影响到边缘上的像素值,这样就保险了边缘左近像素值的保留。不过由于保存了过多的频繁消息,对于彩色图像里的反复噪声,双边滤波器不可见彻底的滤掉,只可以够对于低频音信实行较好的滤波。

下图是双边滤波的规律示意图:

710官方网站 13

在互相滤波器中,输出像素的值正视于邻域像素值的加权值组合:

710官方网站 14

而加权周到w(i,j,k,l)取决于空域核和值域核的乘积。
(i,j),(k,l)分别指八个像素点的坐标。

当中空域核表示如下(如图):

710官方网站 15

值域核表示为:

710官方网站 16

互相相乘后,就会产生正视性于数据的相互滤波权重函数:

710官方网站 17

d函数是依照像素距离选用权重,距离越近权重越大,那一点和方框滤波,高斯滤波方式同样。而r函数则是基于像素的出入来分配权值。假如八个像素值越接近,尽管距离较远,也比差异大而离开近的像素点权重大。便是r函数的效能,使得边缘,即距离近但差距大的像素点的特色得以保存。

OpenCV中用medianBlur函数完成多头滤波。
函数评释:

void bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

参数:

  • 率先个参数,InputArray类型的src,输入图像,即源图像,须要为五位照旧浮点型单通道、三通路的图像。
  • 其次个参数,OutputArray类型的dst,即目的图像,必要和源图片有平等的尺寸和项目。
  • 其多少个参数,int类型的d,表示在过滤进程中各类像素邻域的直径。要是那几个值大家设其为非正数,那么OpenCV会从第5个参数sigmaSpace来计算出它来。
  • 第四个参数,double类型的sigmaColor,颜色空间滤波器的sigma值。那一个参数的值越大,就评释该像素邻域内有越来越宽广的颜料会被混合到壹块,爆发较大的半对等颜色区域。
  • 第6个参数,double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域丰硕相似的颜色获取相同的水彩。当d>0,d钦点了邻域大小且与sigmaSpace毫无干系。否则,d正比于sigmaSpace。
  • 第八个参数,int类型的borderType,用于猜度图像外部像素的某种边界情势。注意它有私下认可值BO库罗德DE途睿欧_DEFAULT。

3.1Spatial Weight

  那就是常见的Gaussian Blur中应用的估量高斯权重的主意,其首要通过三个pixel之间的偏离并选用如下公式总括而来:

                 710官方网站 18

 

四、示例代码:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"  
#include<opencv2/imgproc/imgproc.hpp>  
#include <iostream>  

using namespace cv;

int main(){

    Mat img = imread("dog.jpg");//据说丑女经过双边滤波用有美颜效果哦,有兴趣的同学可以试试

    Mat out1,out2,out3;

    medianBlur(img, out1, 35);
    bilateralFilter(img, out2, 25, 25 * 2, 25 / 2);

    namedWindow("中值滤波", 2);

    imshow("中值滤波", out1);

    namedWindow("双边滤波", 2);

    imshow("双边滤波", out2);

    waitKey(0);

    return 0;
}

710官方网站 19

参考:
http://blog.csdn.net/poem\_qianmo/article/details/23184547

3.1Similarity Weight

  与基于距离的高斯权重计算类似,只不过此处不再依照五个pixel之间的上空中距离离,而是基于其相似程度(只怕七个pixel的值时期的偏离)。

Atitit
  图像处理 平滑 也称 模糊归一化块滤波、高斯滤波、中值滤波、双边滤波)

            710官方网站 20

   个中的代表七个像素值之间的偏离,能够直接行使其灰度值之间的差值只怕TiggoGB向量之间的欧氏距离。

 

3.4 Color Filtering

   当中的相似度分部的权重s重要依照三个Pixel之间的水彩差值总计面来。对于灰度图而言,那么些差值的限制是能够预感的,即[-255, 255],因此为了增强总结的频率大家得以将该片段权重因子预计算生成并存表,在动用时火速查询即可。使用上述达成的算法对几张带有噪声的图像实行滤波后的结果如下所示:

 是一项不难且使用频率很高的图像处理方法

 3 双边滤波源码达成

 1 #include <time.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <math.h>
 5 #include "bf.h"
 6 
 7 
 8 //--------------------------------------------------
 9 /**
10 双边滤波器图像去噪方法
11 \param   pDest       去噪处理后图像buffer指针
12 \param   pSrc        原始图像buffer指针
13 \paran   nImgWid     图像宽
14 \param   nImgHei     图像高
15 \param   nSearchR    搜索区域半径
16 \param   nSigma      噪声方差 
17 \param   nCoff       DCT变换系数个数
18 
19 return   void  
20 */
21 //--------------------------------------------------
22 void BilateralFilterRGB(float *pDest, BYTE *pSrc,int nImgWid, int nImgHei, int nSearchR, int nSigma, int nCoff)
23 {
24 
25     BYTE *pSrcR  = new BYTE[nImgHei * nImgWid];                  // 新建图像缓冲区R
26     BYTE *pSrcG  = new BYTE[nImgHei * nImgWid];                  // 新建图像缓冲区G
27     BYTE *pSrcB  = new BYTE[nImgHei * nImgWid];                  // 新建图像缓冲区B
28 
29 
30     for(int i = 0;i < nImgHei; i++)
31     {
32         for (int j = 0; j < nImgWid; j++)
33         {
34             pSrcR[i * nImgWid + j] = pSrc[i * nImgWid * 3 + j * 3 + 0];         
35             pSrcG[i * nImgWid + j] = pSrc[i * nImgWid * 3 + j * 3 + 1];         
36             pSrcB[i * nImgWid + j] = pSrc[i * nImgWid * 3 + j * 3 + 2];         
37         }
38     }    
39 
40 
41     float* pDestR = new float[nImgHei * nImgWid];         // 去噪后的图像数据R通道
42     float* pDestG = new float[nImgHei * nImgWid];         // 去噪后的图像数据G通道
43     float* pDestB = new float[nImgHei * nImgWid];         // 去噪后的图像数据B通道
44     memset(pDestR,255,nImgHei * nImgWid * sizeof(float)); // 传递变量初始化
45     memset(pDestG,255,nImgHei * nImgWid * sizeof(float));
46     memset(pDestB,255,nImgHei * nImgWid * sizeof(float));
47 
48 
49     float *pII = new float[nImgHei * nImgWid ];                       // 积分图
50     float *pWeights  = new float[nImgHei * nImgWid ];                       // 每一个窗的权重之和,用于归一化  
51 
52 
53     float mDctc[MAX_RANGE];                                     // DCT变换系数
54     float mGker[MAX_RANGE];                                     // 高斯核函数的值
55 
56     for (int i = 0; i< MAX_RANGE; ++i)
57     {
58         mGker[i] = exp(-0.5 * pow(i / nSigma, 2.0));                       // 首先计算0-255的灰度值在高斯变换下的取值,然后存在mGker数组中
59     }
60 
61     CvMat G = cvMat(MIN_RANGE, MAX_RANGE, CV_32F, mGker);           // 转换成opencv中的向量
62     CvMat D = cvMat(MIN_RANGE, MAX_RANGE, CV_32F, mDctc);   // 把mDctc系数数组转换成opencv中的向量形式
63 
64     cvDCT(&G,&D,CV_DXT_ROWS);                                           // 然后将高斯核进行离散的dct变换
65     mDctc[0] /= sqrt(2.0);                                              // 离散余弦变换的第一个系数是1/1.414;
66 
67 
68     bf(pSrcR, pDestR, mDctc, pII, pWeights, nImgHei, nImgWid, nCoff, nSearchR);
69     bf(pSrcG, pDestG, mDctc, pII, pWeights, nImgHei, nImgWid, nCoff, nSearchR);
70     bf(pSrcB, pDestB, mDctc, pII, pWeights, nImgHei, nImgWid, nCoff, nSearchR);
71 
72 
73     for(int i=0; i < nImgHei;i++)
74     {
75         for (int j=0; j < nImgWid; j++)
76         {
77             pDest[i * nImgWid * 3 + j * 3 + 0] = pDestR[i * nImgWid + j];           
78             pDest[i * nImgWid * 3 + j * 3 + 1] = pDestG[i * nImgWid + j];                   
79             pDest[i * nImgWid * 3 + j * 3 + 2] = pDestB[i * nImgWid + j];           
80         }
81     }
82 
83 
84     free(pSrcR);      // 释放临时缓冲区
85     free(pSrcG);
86     free(pSrcB);
87     free(pDestR);
88     free(pDestG);
89     free(pDestB);
90 
91 }

  1 //--------------------------------------------------
  2 /**
  3 双边滤波器图像去噪方法
  4 \param   pDest       去噪处理后图像buffer指针
  5 \param   pSrc        原始图像buffer指针
  6 \paran   nImgWid     图像宽
  7 \param   nImgHei     图像高
  8 \param   pII         积分图缓冲区
  9 \param   pWeights    归一化权重系数 
 10 \param   nCoff       DCT变换系数
 11 \param   nPatchWid   图像块宽度
 12 
 13 return   void  
 14 */
 15 //--------------------------------------------------
 16 void bf (BYTE *pSrc, float *pDest, float *pDctc, float *pII, float *pWeights, int nImgHei, int nImgWid, int nCoff, int nPatchWid)  
 17 {  
 18     if (pDest == NULL || pSrc ==NULL)
 19     {
 20         return;
 21     }
 22 
 23     float *cR  = (float*) malloc((nCoff - 1) * MAX_RANGE * sizeof(float));
 24     float *sR  = (float*) malloc((nCoff - 1) * MAX_RANGE * sizeof(float));
 25     float *dcR = (float*) malloc((nCoff - 1) * MAX_RANGE * sizeof(float));
 26     float *dsR = (float*) malloc((nCoff - 1) * MAX_RANGE * sizeof(float));
 27 
 28     
 29     //  余弦变换查找表
 30     int fx     = 0;
 31     int ck     = 0;
 32     int r2     = pow(2.0*nPatchWid + 1.0, 2.0);         // 这个是图像块的像素点的总个数
 33 
 34     float c0   = pDctc[0];                              // 这是DCT的第一个系数
 35     float c0r2 = pDctc[0] * r2;                         // 这个用于初始化归一化权重之和
 36 
 37 
 38     for (ck = 1; ck < nCoff; ck++)                            // 注意到这里面的系数并不包含C0,所以后面才有把C0额外的加上
 39     {                                                                     // 一个矩阵,用于存放各种系数和数值,便于查找
 40         int ckr = (ck - 1) * MAX_RANGE;                                 // 数组是从0开始的,所以这里减1
 41 
 42         for (fx = 0; fx<MAX_RANGE; fx++)                              // fx就是图像的灰度值
 43         {
 44             float tmpfx = PI * float(fx) * float(ck) / MAX_RANGE;   // ck其实就相当于那个余弦函数里面的t,fx相当于u,PI/MAX相当于前面的那个系数,这都是余弦变换相关的东西
 45             
 46             cR[ckr + fx]  = cos(tmpfx);                                      // 存储余弦变换,这个用在空间域上      
 47             sR[ckr + fx]  = sin(tmpfx);                                      // 存储正弦变换
 48             dcR[ckr + fx] = pDctc[ck]  * cos(tmpfx);                         // 存储余弦变换和系数的乘积,这个则用在强度范围上
 49             dsR[ckr + fx] = pDctc[ck]  * sin(tmpfx);                         // 存储正弦变换和系数的乘积       
 50         }        
 51     }
 52 
 53       
 54     float *pw  = pWeights;                          // 新建一个归一化权重的中间变量进行数据的初始化
 55     float *pwe = pWeights + nImgWid * nImgHei;      // 限定最大位置
 56 
 57     while (pw < pwe) 
 58     {
 59         *pw++ = c0r2;                   // 赋初值,让它们都等于第一个DCT系数乘以图像块中总的像素点的个数
 60     }
 61     
 62     for (int ck = 1; ck < nCoff; ck++) 
 63     {        
 64         int ckr = (ck-1)*MAX_RANGE; // 数组是从0开始的,所以这里减1
 65 
 66         add_lut(pWeights, pSrc, pII,cR + ckr, dcR + ckr, nImgHei, nImgWid, nPatchWid, nPatchWid);  // add cos term to pWeights
 67         add_lut(pWeights, pSrc, pII,sR + ckr, dsR + ckr, nImgHei, nImgWid, nPatchWid, nPatchWid);  // add cos term to pWeights  
 68         
 69     } 
 70 
 71     ImgRectSumO(pDest, pSrc, pII, c0, nImgHei, nImgWid, nPatchWid, nPatchWid);  //加上C0的变换之后,再初始化滤波后的函数     
 72     
 73     for (int ck = 1; ck < nCoff; ck++) 
 74     {        
 75         int ckr = (ck-1)*MAX_RANGE;
 76         
 77         add_f_lut(pDest, pSrc, pII, cR + ckr, dcR + ckr, nImgHei, nImgWid, nPatchWid, nPatchWid);  // add cosine term to dataf
 78         add_f_lut(pDest, pSrc, pII, sR + ckr, dsR + ckr, nImgHei, nImgWid, nPatchWid, nPatchWid);  // add sine term to dataf
 79   
 80     }
 81 
 82 
 83     float *pd = pDest + nPatchWid * nImgWid;
 84     pw        = pWeights + nPatchWid * nImgWid;
 85 
 86     float *pdie  = pd + nImgWid - nPatchWid;
 87     float *pdend = pDest + (nImgHei - nPatchWid) * nImgWid;
 88     
 89     while (pd < pdend) 
 90     {
 91         pd += nPatchWid; //把边都给去掉了
 92         pw += nPatchWid; //这个也是把边去掉了
 93 
 94         while (pd < pdie) 
 95         {
 96             *pd++ /= ( (*pw++)*255);     // 之所以要除以255,是为了把它化到[0,1]之间,便于显示
 97         }
 98 
 99         pd += nPatchWid;                 // 把边都给去掉了
100         pw += nPatchWid;                 // 这个也是把边去掉了
101         pdie += nImgWid;                 // 过渡到下一行       
102     }
103    
104     free(cR); 
105     free(sR); 
106     free(dcR); 
107     free(dsR);   // 释放缓冲区
108 }

//--------------------------------------------------
/**
余弦函数首系数积分图
\param   pDest       去噪处理后图像buffer指针
\param   pSrc        原始图像buffer指针
\paran   nImgWid     图像宽
\param   nImgHei     图像高
\param   pII         积分图缓冲区
\param   c0          DCT变换第一个系数
\param   nPatchWid   图像块宽度
\param   nPatchHei   图像块高度

return   void  
*/
//--------------------------------------------------
void ImgRectSumO (float* pDest, const BYTE* pSrc, float* pII, float c0,const int nImgHei, const int nImgWid, const int nPatchWid, const int nPatchHei) 
{
    if (pDest == NULL || pSrc ==NULL)
    {
        return;
    }

    int ri1 = nPatchWid + 1;                                // 中心像素点
    int rj1 = nPatchHei + 1;
    int ri21 = 2 * nPatchWid + 1;                           // 图像块的宽度
    int rj21 = 2 * nPatchHei + 1;

    const BYTE *pSrcImg    = pSrc;                          // 原始图像数据
    const BYTE *pSrcImgEnd = pSrc + nImgHei * nImgWid;      // 最大的像素点位置    
    const BYTE *pSrcImgWid = pSrcImg + nImgWid;             // 第一行的最大的像素点位置,下面循环用的的变量
    float       *pIITmp     = pII;                           // 积分图数据
    float       *ppII       = pIITmp;                        // 积分图中间变量


    *pIITmp++ = c0 * float( *pSrcImg++ );                    // 第一个系数乘以图像数据

    while (pSrcImg < pSrcImgWid)                             // 遍历第一行进行求积分图,其实这个是图像数据的积分图
    {
        *pIITmp++ = (*ppII++) + c0 * float(*pSrcImg++);      
    }  

    while (pSrcImg < pSrcImgEnd)                             // 遍历所有的像素点的变量
    {    

        pSrcImgWid   += nImgWid;                             // 进行第二行的循环
        ppII          = pIITmp;                              // 积分图中间变量
        *pIITmp++     = c0 * float(*pSrcImg++);              // 第二行第一个像素点的处理

        while (pSrcImg < pSrcImgWid) 
        {
            (*pIITmp++) = (*ppII++) + c0 * float(*pSrcImg++); // 求第二行的积分图
        }        

        float *pIIWid = pIITmp;                        // 当前位置像素点
        pIITmp = pIITmp - nImgWid;                     // 上一行的起始点位置
        float *pIIup  = pIITmp - nImgWid;              // 上上一行的起始点位置

        while (pIITmp < pIIWid)                        // 遍历整个行的每一个数据
        {
            (*pIITmp++) = (*pIITmp) + (*pIIup++);      // 行与行之间的积分图
        }

    }


    float *pres = pDest + ri1 * nImgWid;                    // 最小的行位置
    float *pend = pDest + (nImgHei - nPatchWid) * nImgWid;  // 最大的行位置

    float *pii1 = NULL;
    float *pii2 = NULL;
    float *pii3 = NULL;
    float *pii4 = NULL;                               // 求积分图的四个点

    pii1 = pII + ri21 * nImgWid + rj21;               // 右下角
    pii2 = pII + ri21 * nImgWid;                      // 左下角
    pii3 = pII + rj21;                                // 右上角
    pii4 = pII;                                       // 左上角

    while (pres < pend) 
    {
        float *pe = pres + nImgWid - nPatchHei;
        pres += rj1;

        while (pres < pe)                             // 这个只是求图像数据的积分图
        {
            (*pres++) = (*pii1++) - (*pii2++) - (*pii3++) + (*pii4++);
        }

        pres += nPatchHei;
        pii1 += rj21;
        pii2 += rj21;
        pii3 += rj21;
        pii4 += rj21;
    }

}

//--------------------------------------------------
/**
余弦积分图加函数
\param   pNomalWts   像素点的归一化权重矩阵
\param   pSrc        原始图像buffer指针
\param   pII         积分图
\paran   nImgWid     图像宽
\param   nImgHei     图像高
\param   pII         积分图缓冲区
\param   pCosMtx     余弦函数矩阵
\param   pCosDctcMtx 余弦函数与DCT变换系数乘积矩阵
\param   nPatchWid   图像块宽度
\param   nPatchHei   图像块高度

return   void  
*/
//--------------------------------------------------

void add_lut (float* pNomalWts, const BYTE* pSrc, float* pII, float* pCosMtx, float* pCosDctcMtx, const int nImgHei, const int nImgWid, const int nPatchWid, const int nPatchHei) 
{ 

    int ri1  = nPatchWid + 1;      // kernel相关
    int rj1  = nPatchHei + 1;
    int ri21 = 2 * nPatchWid + 1;  // 这是kernel的宽度和长度
    int rj21 = 2 * nPatchHei + 1;

    const BYTE *pi  = pSrc;           // 这个是图像数据
    float *pii       = pII;            // 这个是中间的缓冲变量,积分图的缓冲区
    const BYTE *piw = pi + nImgWid;   // 也是赋初值的时候使用的中间变量
    float *pii_p     = pii;            // 直线积分图指针的指针


    *pii++ = pCosMtx[*pi++];  //图像数据值所对应的查找表中的余弦或者正弦变换


    while (pi < piw)
    {            
        *pii++ = (*pii_p++) + pCosMtx[*pi++]; // 第一行的积分图
    }    

    const BYTE *piend = pSrc + nImgHei * nImgWid;       // 限定循环位置

    while (pi < piend)                                     // 遍历整个图像数据
    {  

        piw    += nImgWid;                            // 第二行
        pii_p   = pii;                             // 指向积分图指针的指针
        *pii++  = pCosMtx[*pi++];              // 获取第一个图像数据值所对应的查找表中的余弦或者正弦变换

        while (pi < piw) 
        {
            (*pii++) = (*pii_p++) + pCosMtx[*pi++]; // 求这一行的积分图
        }

        float *piiw = pii;
        pii = pii - nImgWid;
        float *pii_p1 = pii - nImgWid;

        while (pii < piiw) 
        {
            (*pii++) = (*pii) + (*pii_p1++);                  // 行与行之间求积分图
        }

    }  


    float *pres = pNomalWts + ri1 * nImgWid;                   // 定位要处理点的像素的那一行
    float *pend = pNomalWts + (nImgHei - nPatchWid) * nImgWid; // 限定了边界

    float *pii1 = NULL;
    float *pii2 = NULL;
    float *pii3 = NULL;
    float *pii4 = NULL;

    pii1 = pII + ri21 * nImgWid + rj21;  // 获得积分图中那个最大的数据右下角
    pii2 = pII + ri21 * nImgWid;         // 积分图左下角
    pii3 = pII + rj21;                   // 积分图右上角
    pii4 = pII;                          // 积分图左上角

    pi = pSrc + ri1 * nImgWid;                  // 定位要处理的像素的位置


    while (pres < pend)                         // 设定高度做循环
    {
        float *pe = pres + nImgWid - nPatchHei; // 限定了宽度的范围
        pres = pres + rj1;                      // 定位了要处理的像素点的归一化系数矩阵的位置
        pi = pi + rj1;                          // 定位了要处理的像素点

        while (pres < pe)                       // 设定宽度做循环
        {
            (*pres++) = (*pres) + pCosDctcMtx[*pi++] * ( (*pii1++) - (*pii2++) - (*pii3++) + (*pii4++) );    // 得到的就是归一化系数矩阵之和
        }

        pres += nPatchHei;                     
        pi   += nPatchHei;                     
        pii1 += rj21;                          
        pii2 += rj21;                          
        pii3 += rj21;                          
        pii4 += rj21;                          // 略过不处理的边界区域
    }    

}

//--------------------------------------------------
/**
积分图
\param   pDest   像素点的归一化权重矩阵
\param   pSrc        原始图像buffer指针
\param   pII         积分图
\paran   nImgWid     图像宽
\param   nImgHei     图像高
\param   pII         积分图缓冲区
\param   pCosMtx     余弦函数矩阵
\param   pCosDctcMtx 余弦函数与DCT变换系数乘积矩阵
\param   nPatchWid   图像块宽度
\param   nPatchHei   图像块高度

return   void  
*/
//--------------------------------------------------

void add_f_lut (float* pDest,const BYTE* pSrc,float* pII,float* pCosMtx,float* pCosDctcMtx,const int nImgHei, const int nImgWid,const int nPatchWid, const int nPatchHei) 
{  

    int ri1 = nPatchWid + 1;      // kernel相关,目标是指向中心像素点
    int rj1 = nPatchHei + 1;      // 目标是指向中心像素点
    int ri21 = 2 * nPatchWid + 1; // 这是kernel的宽度和长度
    int rj21 = 2 * nPatchHei + 1; // 其实就是指向搜索区域的右下角,也就是最大位置的那个像素点,就是边界了

    const BYTE *pi = pSrc;       // 这个是图像数据,图像的灰度值
    float *pii = pII;             // 这是积分图

    const BYTE *piw = pi + nImgWid;  // 指向第一行的末尾位置,用于循环控制
    float *pii_p = pii;               // 指向积分图指针的指针

    *pii++ = float(*pi) * pCosMtx[*pi]; // 灰度值乘以余弦系数
    ++pi;      

    while (pi < piw)                    // 第一行遍历
    {
        *pii++ = (*pii_p++) + float(*pi) * pCosMtx[*pi];
        ++pi;
    }

    const BYTE *piend = pSrc + nImgHei * nImgWid;

    while (pi < piend) 
    {        
        piw   += nImgWid;
        pii_p  = pii;
        *pii++ = float(*pi) * pCosMtx[*pi];
        ++pi;

        while (pi < piw)
        {
            (*pii++) = (*pii_p++) + float(*pi) * pCosMtx[*pi];
            ++pi;
        }

        float *piiw = pii;
        pii = pii - nImgWid;   // 上一行起点
        float *pii_p1 = pii - nImgWid; // 上上一行的起始点

        while (pii < piiw)             // 循环一行
        {
            (*pii++) += (*pii_p1++);  //其实就是在列的位置上加上上一行
        }

    }


    float *pres = pDest + ri1*nImgWid;                     
    float *pend = pDest + (nImgHei - nPatchWid) * nImgWid; 
    float *pii1 = NULL;
    float *pii2 = NULL;
    float *pii3 = NULL;
    float *pii4 = NULL;

    pii1 = pII + ri21 * nImgWid + rj21;   // 积分图搜索区域最大位置的元素,堪称右下角的元素
    pii2 = pII + ri21 * nImgWid;          // 可以看成搜索区域中左下角的像素位置
    pii3 = pII + rj21;                    // 搜索区域右上角像素位置
    pii4 = pII;                           // 搜索区域左上角像素位置
    pi   = pSrc + ri1 * nImgWid;          // 定位要处理的像素的位置的那一行

    while (pres < pend) 
    {
        float *pe = pres + nImgWid - nPatchHei; //限定了宽度的范围

        pres = pres + rj1; //定位了要处理的像素点的归一化系数矩阵的位置
        pi   = pi   + rj1;     //定位了要处理的像素点

        while (pres < pe)  //遍历整个行
        {
            (*pres++) = (*pres) + pCosDctcMtx[*pi++] * ( (*pii1++) - (*pii2++) - (*pii3++) + (*pii4++) ); //这个其实是计算整个像素块
        }

        pres += nPatchHei;   
        pi   += nPatchHei;   

        pii1 += rj21; 
        pii2 += rj21;
        pii3 += rj21;
        pii4 += rj21;
    }
}

 

 

用途 去噪 去雾

 

种种线性滤波器对图像举行平整处理,相关OpenCV函数如下:

 

归壹化块滤波器 (诺玛lized 博克斯 Filter)

§ 

最简便易行的滤波器, 输出像素值是核窗口内像素值的 均值 (
全部像素加权周到相等)

§ 

高斯滤波器 (Gaussian Filter)

§ 

最有效的滤波器 (固然不是最快的)。
高斯滤波是将输入数组的每3个像素点与 高斯根本 卷积将卷积和当作输出像素值。

§ 

要是图像是1维的,那么观看上海体育场面,简单窥见中间像素的加权周详是最大的,
周边像素的加权周到随着它们远离中间像素的距离增大而日趋减小

中值滤波器 (Median Filter)

中值滤波将图像的每一个像素用邻域
(以当下像素为主导的长方形区域)像素的 中值 代替 。

两岸滤波 (Bilateral Filter)

§ 近期我们询问的滤波器都以为了 平滑 图像,
难题是有些时候这个滤波器不仅仅减弱了噪声, 连带着把边缘也给磨掉了。
为防止那样的情状 (至少在必然水平上 ), 大家得以选取双边滤波。

§ 类似于高斯滤波器,双边滤波器也给每3个邻域像素分配贰个加权周详。
那个加权周密包蕴八个部分,
第3有个别加权形式与高斯滤波1样,第一有的的权重则在于该邻域像素与当下像素的灰度差值。

 双边滤波(Bilateral
filter)是壹种能够保边去噪的滤波器。之所以可以直达此去噪效果,是因为滤波器是由四个函数构成。三个函数是由几何空间距离..

 

于是得以达到此去噪效果,是因为滤波器是由三个函数构成。二个函数是由几何空间距离决定滤波器周详。另七个由像素差值决定滤波器周到。能够与其相比较的三个filter:高斯低通滤波器

 

两边滤波器中,输出像素的值注重于邻域像素的值的加权组合

再者考虑了空间域与值域的反差,而Gaussian
Filter和α均值滤波分别只思量了空间域和值域差异。

 

 

两边滤波器能一呵而就这个原因在于它不像一般的高斯/卷积低通滤波,只考

虑了职分对基本像素的震慑,它还思考了卷积核中像素与主导像素之间相似程度的影响,根据任务

潜移默化与像素值之间的相似程度生成三个例外的权重表(WeightTable),在估测计算宗旨像素的时候再说

设想那三个权重,从而达成双方低通滤波。听他们说AdobePhotoshop的高斯磨皮成效就是使用了

双面低通滤波算法710官方网站,实现。

 

 

 

图像平滑处理(归1化块滤波、高斯滤波、中值滤波、双边滤波)

  • xw二〇一〇4898的专辑 – 博客频道 – CSDN.NET.html

 

笔者:: 绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 Ake巴 阿尔 拉帕努伊 ) 

汉字名:艾提拉(艾龙),   EMAIL:1466519819@qq.com

转发请注明来源: http://www.cnblogs.com/attilax/

Atiend

 

 

 

相关文章