710官方网站抱有简易、非。 而制止不感兴趣的有。

1 双边滤波简介

  双边滤波(Bilateral filter)是一致种非线性的滤波方法,是整合图像的空中邻近度同诸如素值相似度的平等种折衷处理,同时考虑空域信息及灰度相似性,达到保边去叫的目的。具有简易、非迭代、局部的性状。

  双边滤波器的补是好开边缘保存(edge preserving),一般过去用底维纳滤波或者高斯滤波夺降噪,都见面较显眼地歪曲边缘,对于频繁细节的维护作用并无明了。双边滤波器顾名思义比高斯滤波多矣一个高斯方差sigma-d,它是根据空间分布之高斯滤波函数,所以于边缘附近,离的较远之像素不见面极其多影响至边缘上之比如说素值,这样就是管了边缘附近像素值的保留。但是由保存了了多的多次信息,对于彩色图像里之屡屡噪声,双边滤波器不能够彻底的滤掉,只能够对低频信息进行较好之滤波。

 

增将处理目的在突出图像中的感谢兴趣有,而制止不感兴趣的一对。

2 双边滤波原理

  滤波算法中,目标点达成的像素值通常是出于该所在位置上之方圆的一个小片段邻居像从的值所决定。在2D高斯滤波中的切实可行落实即是对周围的大势所趋范围外之如素值分别给以不同的高斯权重值,并以加权平均后获取时点的最后结果。而这边的高斯权重因子是采用有限独像素之间的空间距离(在图像被也2D)关系来扭转。通过高斯分布的曲线可以发现,离目标像从越近的触及对最后结果的奉献更是老,反的则越来越小。其公式化的叙述相似如下所陈述:

                     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

  上述三贪图从左到右依次为:双边滤波,原始图像,高斯滤波。从高度图中可肯定看出Bilateral和Gaussian两栽办法的区分,前者较好地维持了边缘处的梯度,而以高斯滤波中,由于该在边缘处的别是线性的,因而就动连累的梯度呈现出渐变的状态,而这展现于图像被的语就是是界的丢(图像的以身作则可见于后述)。         

 

卷积积分和邻域处理

卷积的数学形式吗:

710官方网站 12

一如既往维连续函数的卷积定义

特色了f与经回转和平换的g的叠部分的积聚。
点滴函数之傅里叶变换的乘积,等于他们卷积后底傅里叶变换。
邻域处理:经过一致移卷积模板g[i,j],使该主干走至比如素点[x,y]远在,并盘算模板与像素点[x,y]邻域加权结果。
MATLAB中提供了推行第二维卷积计算的函数conv2()
图像处理工具箱中还提供了根据卷积的图像滤波函数filter2()。其二者是相等价格的。
又不时因此imfilter()函数来落实,因为上面只能处理灰度图片,而且图片大小会生反。
g = imfilter(f, w, option1, option2, ...)
f为使滤波的图像,w为使的模板,option1,option2为而摘参数。见p90
滤波的模版可以由函数fspecial()创建。
h = fspecial(type, parameters)

3 双边滤波实现步骤

  有了上述辩解之后实现Bilateral Filter就比较简单了,其实它们吗与普通的Gaussian Blur没有最好死之分。这里关键概括3部分之操作: 基于空间距离的权重因子变化;基于相似度的权重因子的转移;最终filter颜色的计量。

 

图像的大概平滑

简单平滑就是针对性图像一定领域内之比如说素灰度求平均值,从而将噪声分担到邻域各像素中失去。

710官方网站 13

概括平滑

卷积模板如图,选取9作为衰减因子
h1 = fspecial('average',[3 3]);
g1 = imfilter(i, h1, 'conv', 'replicate');
简简单单平滑往往因牺牲图片清晰度为代价,图像对比度下降比较多。

3.1Spatial Weight

  这就是是司空见惯的Gaussian Blur中使的盘算高斯权重的道,其主要通过个别独pixel之间的去并采用如下公式计算而来:

                 710官方网站 14

 

高斯平滑

平滑线性滤波器就算采用模板对邻域内如素灰度进行加权平均,故同时如全值滤波器。其衰减因子一般为所有权值的以及。
高斯平滑是其余一样种植平滑线性滤波器,模板被益临近邻域中心的职位,权值越怪,权值符合高斯分布。如下

710官方网站 15

高斯平滑

710官方网站 16

二维高斯分布

函数实现:
h = fspecial('gaussian', 7, 2);
g = imfilter(i, h, 'conv');
高斯平滑在保存全局特征方面出深挺改善,但才用高斯平滑,除噪效果往往并无·理想。

3.1Similarity Weight

  与因距离的高斯权重算类似,只不过此处不再根据两独pixel之间的空间距离,而是基于该相似程度(或者简单单pixel的价值内的离)。

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

遭逢值滤波

统计排序滤波器大凡透过对采样窗口外奇数个像从的灰度数值进行排序,并取出中间位置的灰度作为主导像从的灰度。
出于中值排序传感器可直接删除噪声,因此其可以使得之破离散型噪声点,尤其对拍卖椒盐噪声效果显著。
函数实现:
I2 = medfilt2(I1, [m n])
m,n为模板大小。
J = imnoise(I, type, parameters)
这函数可以长噪声,可挑选‘gaussian’或者‘salt&pepper’。

            710官方网站 17

   其中的意味两单如素值之间的偏离,可以一直动用该灰度值之间的差值或者RGB向量之间的欧氏距离。

 

两者滤波

双方滤波是同样栽非线性的滤波方法。
每当高斯平中,权重只及像素之间的空中距离有关,而同像素点无关。双边滤波在聊重吃进入了像素值相似度的取值。
权重如下式:

710官方网站 18

双方滤波权重公式

两头滤波在搭区域和高斯平滑差别不坏,而以边缘区域信息方可充分好的保存下。

3.4 Color Filtering

   其中的相似度分部的权重s主要因两个Pixel之间的颜料差值计算面来。对于灰度图而言,这个差值的克是好预知的,即[-255, 255],因而为增强计算的效率我们得用拖欠有权重因子预计算生成并存表,在采用时快速查询即可。使用上述实现的算法对几乎摆设带有噪声的图像进行滤波后的结果如下所示:

 是同件简单且使用频率非常高之图像处理办法

拉普拉斯锐化

及图像的平滑相反,锐化是为强调图像的边缘与细节。因此得以行使相反的手段,提高邻域内如从的灰度差。
拉普拉斯锐化是利用拉普拉斯算子本着图像进行边缘增强的一模一样种植办法。
模板如下:

710官方网站 19

拉普拉斯锐化模板

那个基本原理为,中心像素灰度高于邻域内平均灰度时,结果吧刚,像素值会多;反的结果也借助,像素值会愈加减少。
matlab编码实现:
h = fspecial('unsharp',alpha)
只要顾,Laplacian算子是Laplacian锐化模板的取反。在使用锐化时,就是应用unsharp滤波器的。
假若直接自行编排模板,是不行的,因为应用unsharp算子时,还会见展开与来自图像的增大,才见面好锐化。

参考资料:
二者滤波器的兑现http://blog.csdn.net/abcjennifer/article/details/7616663

上述内容来《数字图像处理:原理及实践(matlab版)》左飞著,电子工业出版社。此也上学笔记。

 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函数如下:

 

由一化块滤波器 (Normalized Box Filter)

§ 

最为简便易行的滤波器, 输出像素值是核窗口内像素值的 均值 (
所有像素加权系数等)

§ 

高斯滤波器 (Gaussian Filter)

§ 

尽可行之滤波器 (尽管未是极其抢的)。
高斯滤波是以输入数组的各级一个像素点与 高斯根本 卷积以卷积和作输出像素值。

§ 

如若图像是1维的,那么观察上图,不难发现中间像从的加权系数是最为充分的,
周边像从的加权系数随着她远离中间像从的离增大而逐年弱化多少

未遭值滤波器 (Median Filter)

遭到值滤波将图像的每个像素用邻域
(以手上像素为主导的正方形区域)像从的 中值 代替 。

彼此滤波 (Bilateral Filter)

§ 时咱们询问的滤波器都是为了 平滑 图像,
问题是出几时候这些滤波器不仅仅削弱了噪声, 连带在把边缘也叫消灭掉了。
为免这样的情形 (至少在一定水平上 ), 我们得以用双边滤波。

§ 类似于高斯滤波器,双边滤波器也受各级一个邻域像素分配一个加权系数。
这些加权系数包含两单部分,
第一片加权方式同高斯滤波一样,第二片底权重则取决于该邻域像素和时诸如从的灰度差值。

 双边滤波(Bilateral
filter)是一模一样种植可以保边去叫的滤波器。之所以得以达标这个去叫效果,是盖滤波器是由于少只函数构成。一个函数是由几哪空间距离..

 

因此得以齐这去叫效果,是因滤波器是出于少数个函数构成。一个函数是由几哪空间距离决定滤波器系数。另一个由像素差值决定滤波器系数。可以与那个相较的星星个filter:高斯低通滤波器

 

双方滤波器中,输出像从的价乘让邻域像从的价的加权组合

与此同时考虑了空间域与值域的别,而Gaussian
Filter和α均值滤波分别仅考虑了空间域和值域差别。

 

 

双方滤波器能好这些由在她不像平常的高斯/卷积低通滤波,只考

寻思了位置对中心像从的影响,它还考虑了卷积核中像素与中心像素之间相似程度之震慑,根据职务

潜移默化与像素值之间的形似程度深成稀独例外之权重表(WeightTable),在测算中心像从的时再说

考虑这有限独权重,从而实现双方低通滤波。据说AdobePhotoshop的高斯磨皮功能就是用了

双方低通滤波算法实现。

 

 

 

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

  • xw20084898的专栏 – 博客频道 – CSDN.NET.html

 

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

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

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

Atiend

 

 

 

相关文章