菜单

导向滤波算法的落实。导向滤波算法的实现。

2018年9月23日 - 中甲报道

由上篇导向滤波算法分析,根据(5)~(8)式就可测算输出图像Q

由上篇导向滤波算法分析,根据(5)~(8)式就足以算输出图像Q

图片 1  (5)

图片 2  (5)

图片 3  (6)

图片 4  (6)

图片 5  (7)

图片 6  (7)

图片 7  (8)

图片 8  (8)

其中图片 9图片 10,/ai和/bi的结果如果计算有所覆盖了如素i的窗口Wk的ak和bk的平均值。除了用平均值,在实质上用中,我还察看过其它的计算/ai和/bi的法。比如根据像素i在窗口Wk的职位,给予不同的权重。如果i距离窗口Wk的中心岗位更远,则给予ak和bk越低的权重。如果i位于窗口中心,则ak和bk起最高的权重。最常用的尽管是故高斯分布来予以不同的权重。这样考虑到了隔壁像从距离远近对i影响的高低,最后的结果会再规范一些。

其中图片 11图片 12,/ai和/bi的结果要计算有所覆盖了像素i的窗口Wk的ak和bk的平均值。除了用平均值,在事实上行使被,我还察看过其他的计算/ai和/bi的不二法门。比如根据像素i在窗口Wk的职位,给予不同的权重。如果i距离窗口Wk的主干岗位更远,则给予ak和bk越低的权重。如果i位于窗口中心,则ak和bk来参天的权重。最常用的就是是故高斯分布来与不同之权重。这样考虑到了邻近像从距离远近对i影响的分寸,最后的结果碰头另行准一些。

此处自己要么用最为简单易行的平均值的方法来计算/ai和/bi。我们前面早已使了当窗口Wk内,ak和bk是常数,因此ak和bk只和Wk的职有关。取Wk也半径为r的方形窗口,使窗口的主干像从位置遍历整个图像,那么即使设Wk取到了不同的具有职位,在每个岗位计算产生相应的ak和bk。所有的ak和bk组合了跟输入图像P相同长宽维度的数量集合,记为A及B。对于自由像素i,/ai和/bi便分别吗因i为骨干半径r的窗口Wk内A和B的数据全值,这不亏我们耳熟能详的图像均值模糊的算法为?而图像均值模糊有几乎种植比较成熟之迅速算法,比如积分图算法和依据直方图的迅猛算法。只要出了A和B,就好便宜之动均值模糊得出/ai和/bi,从而以(8)计算起输出图像Q。

此地自己还是用最好简便的平均值的主意来计算/ai和/bi。我们面前都使了以窗口Wk内,ak和bk是常数,因此ak和bk只和Wk的位置有关。取Wk为半径为r的方形窗口,使窗口的中心像从位置遍历整个图像,那么尽管假设Wk收获到了不同的有所位置,在每个岗位计算起相应的ak和bk。所有的ak和bk成了同输入图像P相同长宽维度的数目集合,记为A与B。对于自由像素i,/ai和/bi就算分别吗坐i为核心半径r的窗口Wk内A和B的数均值,这不亏我们熟悉的图像均值模糊的算法也?而图像均值模糊有几乎栽于成熟之短平快算法,比如积分图算法和因直方图的快捷算法。只要出矣A和B,就可以方便的使用均值模糊得出/ai和/bi,从而采取(8)计算出输出图像Q。

为计算A和B,从(6)式看到,需要各自计输入图像P和导向图G的均值模糊结果。而(5)式需要算导向图G的方差,还有P和G的协方差。方差和协方差且干到乘积的求与计量,可以由下的公式,通过积分图来算。这半个公式很轻推导出来,就不赘述了。

以计算A和B,从(6)式看到,需要各自计输入图像P和导向图G的均值模糊结果。而(5)式需要算导向图G的方差,还有P和G的协方差。方差和协方差且关系到乘积的呼吁与计算,可以由下的公式,通过积分图来计量。这点儿只公式很爱推导出来,就无赘述了。

图片 13

图片 14

图片 15

图片 16

一个平方和,一个积及还好为此积分图来算。只是要顾当图像足够好的时,要因此相当的数据类型。假设像从的多寡范围是0~255的整型,如果平方积分图用32个之整型数据,那么只能支持太要命256×256高低的图像。超过这个尺寸,就非得要为此64各类之整型了。下面被来利用模板函数的积积分图函数,可以依据需要利用不同的数据类型。p1和p2是图像数据指针,当它们对相同的数额常常,这个函数就改成了平方积分图。注意积分图的增长宽比原始数据的丰富宽都如大1。

一个平方和,一个积及还可以据此积分图来计量。只是要小心当图像足够好之早晚,要因此相当的数据类型。假设像从的数范围是0~255的整型,如果平方积分图用32各的整型数据,那么只能支持不过充分256×256轻重的图像。超过这个尺寸,就必使用64号的整型了。下面为起下模板函数的积积分图函数,可以依据需要动用不同的数据类型。p1和p2是图像数据指针,当其对准相同的多寡经常,这个函数就改为了平方积分图。注意积分图的长宽比原始数据的增长宽都要大1。

图片 17图片 18

图片 19图片 20

/* Cumulative image of the multiplication of p1.*p2.
 p1 and p2 can be the same pointer and it becomes square cumulative image.
 The returned cumulative image MUST be freed by the caller! */
template <class T1, class T2, class T3>
BOOL MultiplyCumImage(T1 *p1, T2 *p2, T3 **ppCum)
{
    long i, j;
    long Width = GetWidth();
    long Height = GetHeight();
    long integral_len = (Width + 1)*(Height + 1);

    // Only allocate cumulative image memory when *ppCum is NULL
    if (*ppCum == NULL)
    {
        try { *ppCum = new T3[integral_len]; }
        catch (CException *pe)
        {
            pe->Delete();
            return FALSE;
        }
    }
    memset(*ppCum, 0, sizeof(T3)*integral_len);
    // The cumulative values of the leftmost and the topmost pixels are always 0.
    for (i = 1; i <= Height; i++)
    {
        T3 *prow, *puprow;
        prow = *ppCum + i*(Width + 1);
        puprow = *ppCum + (i - 1)*(Width + 1);
        T3 sum = 0;
        long up_row_idx = (i - 1)*Width;
        for (j = 1; j <= Width; j++)
        {
            long idx = up_row_idx + j - 1;
            sum += p1[idx] * p2[idx];
            prow[j] = puprow[j] + sum;
        }
    }
    return TRUE;
}
/* Cumulative image of the multiplication of p1.*p2.
 p1 and p2 can be the same pointer and it becomes square cumulative image.
 The returned cumulative image MUST be freed by the caller! */
template <class T1, class T2, class T3>
BOOL MultiplyCumImage(T1 *p1, T2 *p2, T3 **ppCum)
{
    long i, j;
    long Width = GetWidth();
    long Height = GetHeight();
    long integral_len = (Width + 1)*(Height + 1);

    // Only allocate cumulative image memory when *ppCum is NULL
    if (*ppCum == NULL)
    {
        try { *ppCum = new T3[integral_len]; }
        catch (CException *pe)
        {
            pe->Delete();
            return FALSE;
        }
    }
    memset(*ppCum, 0, sizeof(T3)*integral_len);
    // The cumulative values of the leftmost and the topmost pixels are always 0.
    for (i = 1; i <= Height; i++)
    {
        T3 *prow, *puprow;
        prow = *ppCum + i*(Width + 1);
        puprow = *ppCum + (i - 1)*(Width + 1);
        T3 sum = 0;
        long up_row_idx = (i - 1)*Width;
        for (j = 1; j <= Width; j++)
        {
            long idx = up_row_idx + j - 1;
            sum += p1[idx] * p2[idx];
            prow[j] = puprow[j] + sum;
        }
    }
    return TRUE;
}

View
Code

View
Code

 这样导向滤波实现之关键问题还解决了,算法步骤如下:

 这样导向滤波实现的严重性问题还解决了,算法步骤如下:

  1. 测算引导图G的积分图和平方积分图
  2. 算算输入图像P的积分图, P和G的乘积积分图
  3. 为此上有数步得起的积分图计算P和G的均值,G的方差,P和G的协方差,窗口半径为r
  4. 下一场据此(5)(6)式计算系数图A和B
  5. 计算A和B的积分图
  6. 计算A和B的窗口半径r的均值,并因此(8)式计算输出图Q
  1. 计算引导图G的积分图和平方积分图
  2. 计输入图像P的积分图, P和G的积积分图
  3. 就此上片步得发底积分图计算P和G的均值,G的方差,P和G的协方差,窗口半径为r
  4. 然后用(5)(6)式计算系数图A和B
  5. 计算A和B的积分图
  6. 计算A和B的窗口半径r的均值,并就此(8)式计算输出图Q

 下面的参阅代码中,pData存储输入和输出图像,pGuidedData引导图,radius领域半径

 下面的参阅代码中,pData存储输入和出口图像,pGuidedData引导图,radius领域半径

图片 21图片 22

图片 23图片 24

    long len = Width*Height;

    // Cululative image and square cululative for guided image G
    UINT64 *pCum = NULL, *pSquareCum = NULL;
    CumImage(pGuidedData, &pCum);
    MultiplyCumImage(pGuidedData, pGuidedData, &pSquareCum);

    // Allocate memory for a and b
    float *pa, *pb;
    pa = new float[len];
    pb = new float[len];
    memset(pa, 0, sizeof(float)*len);
    memset(pb, 0, sizeof(float)*len);

    UINT64 *pInputCum = NULL, *pGPCum = NULL;
    CumImage(pData, &pInputCum);
    MultiplyCumImage(pGuidedData, pData, &pGPCum);

    int field_size;
    UINT64 cum, square_cum;
    long uprow, downrow, upidx, downidx;        // In cumulative image
    long leftcol, rightcol;
    float g_mean, g_var;        // mean and variance of guided image
    long row_idx = 0;
    UINT64 p_cum, gp_cum;
    float p_mean;
    // Calculate a and b
    // Since we're going to calculate cumulative image of a and b, we have to calculate the whole image of a and b.
    for (i = 0; i < Height; i++)
    {
        // Check the boundary for radius
        if (i < radius) uprow = 0;
        else uprow = i - radius;
        upidx = uprow*(Width + 1);
        if (i + radius >= Height) downrow = Height;
        else downrow = i + radius + 1;
        downidx = downrow*(Width + 1);
        for (j = 0; j < Width; j++)
        {
            // Check the boundary for radius
            if (j < radius) leftcol = 0;
            else leftcol = j - radius;
            if (j + radius >= Width) rightcol = Width;
            else rightcol = j + radius + 1;
            field_size = (downrow - uprow)*(rightcol - leftcol);
            long p1, p2, p3, p4;
            p1 = downidx + rightcol;
            p2 = downidx + leftcol;
            p3 = upidx + rightcol;
            p4 = upidx + leftcol;
            // Guided image summary in the field
            cum = pCum[p1] - pCum[p2] - pCum[p3] + pCum[p4];
            // Guided image square summary in the field
            square_cum = pSquareCum[p1] - pSquareCum[p2] - pSquareCum[p3] + pSquareCum[p4];
            // Field mean
            g_mean = (float)(cum) / field_size;
            // Field variance
            g_var = float(square_cum) / field_size - g_mean * g_mean;
            // Summary of input image in the field
            p_cum = pInputCum[p1] - pInputCum[p2] - pInputCum[p3] + pInputCum[p4];
            // Input image field mean
            p_mean = float(p_cum) / field_size;
            // Multiply summary in the field
            gp_cum = pGPCum[p1] - pGPCum[p2] - pGPCum[p3] + pGPCum[p4];
            long idx = row_idx + j;
            pa[idx] = (float(gp_cum) / field_size - g_mean*p_mean) / (g_var + epsilon);
            pb[idx] = p_mean - g_mean*pa[idx];
        }
        row_idx += Width;
    }
    // not needed after this
    delete[] pCum;
    delete[] pSquareCum;
    delete[] pInputCum;
    delete[] pGPCum;

    // Cumulative image of a and b
    float *pCuma = NULL, *pCumb = NULL;
    CumImage(pa, &pCuma);
    CumImage(pb, &pCumb);

    // Finally calculate the output image q=ag+b
    float mean_a, mean_b;
    row_idx = Hstart*Width;
    for (i = Hstart; i < Hend; i++)
    {
        // Check the boundary for radius
        if (i < radius) uprow = 0;
        else uprow = i - radius;
        upidx = uprow*(Width + 1);
        if (i + radius >= Height) downrow = Height;
        else downrow = i + radius + 1;
        downidx = downrow*(Width + 1);
        for (j = Wstart; j < Wend; j++)
        {
            // Check the boundary for radius
            if (j < radius) leftcol = 0;
            else leftcol = j - radius;
            if (j + radius >= Width) rightcol = Width;
            else rightcol = j + radius + 1;
            field_size = (downrow - uprow)*(rightcol - leftcol);
            long p1, p2, p3, p4;
            p1 = downidx + rightcol;
            p2 = downidx + leftcol;
            p3 = upidx + rightcol;
            p4 = upidx + leftcol;
            // Field mean
            mean_a = (pCuma[p1] - pCuma[p2] - pCuma[p3] + pCuma[p4]) / field_size;
            // Field mean
            mean_b = (pCumb[p1] - pCumb[p2] - pCumb[p3] + pCumb[p4]) / field_size;
            // New pixel value
            long idx = row_idx + j;
            int value = int(mean_a*pGuidedData[idx] + mean_b);
            CLAMP0255(value);
            pData[idx] = value;
        }
        row_idx += Width;
    }

    delete[] pa;
    delete[] pb;
    delete[] pCuma;
    delete[] pCumb;
    long len = Width*Height;

    // Cululative image and square cululative for guided image G
    UINT64 *pCum = NULL, *pSquareCum = NULL;
    CumImage(pGuidedData, &pCum);
    MultiplyCumImage(pGuidedData, pGuidedData, &pSquareCum);

    // Allocate memory for a and b
    float *pa, *pb;
    pa = new float[len];
    pb = new float[len];
    memset(pa, 0, sizeof(float)*len);
    memset(pb, 0, sizeof(float)*len);

    UINT64 *pInputCum = NULL, *pGPCum = NULL;
    CumImage(pData, &pInputCum);
    MultiplyCumImage(pGuidedData, pData, &pGPCum);

    int field_size;
    UINT64 cum, square_cum;
    long uprow, downrow, upidx, downidx;        // In cumulative image
    long leftcol, rightcol;
    float g_mean, g_var;        // mean and variance of guided image
    long row_idx = 0;
    UINT64 p_cum, gp_cum;
    float p_mean;
    // Calculate a and b
    // Since we're going to calculate cumulative image of a and b, we have to calculate the whole image of a and b.
    for (i = 0; i < Height; i++)
    {
        // Check the boundary for radius
        if (i < radius) uprow = 0;
        else uprow = i - radius;
        upidx = uprow*(Width + 1);
        if (i + radius >= Height) downrow = Height;
        else downrow = i + radius + 1;
        downidx = downrow*(Width + 1);
        for (j = 0; j < Width; j++)
        {
            // Check the boundary for radius
            if (j < radius) leftcol = 0;
            else leftcol = j - radius;
            if (j + radius >= Width) rightcol = Width;
            else rightcol = j + radius + 1;
            field_size = (downrow - uprow)*(rightcol - leftcol);
            long p1, p2, p3, p4;
            p1 = downidx + rightcol;
            p2 = downidx + leftcol;
            p3 = upidx + rightcol;
            p4 = upidx + leftcol;
            // Guided image summary in the field
            cum = pCum[p1] - pCum[p2] - pCum[p3] + pCum[p4];
            // Guided image square summary in the field
            square_cum = pSquareCum[p1] - pSquareCum[p2] - pSquareCum[p3] + pSquareCum[p4];
            // Field mean
            g_mean = (float)(cum) / field_size;
            // Field variance
            g_var = float(square_cum) / field_size - g_mean * g_mean;
            // Summary of input image in the field
            p_cum = pInputCum[p1] - pInputCum[p2] - pInputCum[p3] + pInputCum[p4];
            // Input image field mean
            p_mean = float(p_cum) / field_size;
            // Multiply summary in the field
            gp_cum = pGPCum[p1] - pGPCum[p2] - pGPCum[p3] + pGPCum[p4];
            long idx = row_idx + j;
            pa[idx] = (float(gp_cum) / field_size - g_mean*p_mean) / (g_var + epsilon);
            pb[idx] = p_mean - g_mean*pa[idx];
        }
        row_idx += Width;
    }
    // not needed after this
    delete[] pCum;
    delete[] pSquareCum;
    delete[] pInputCum;
    delete[] pGPCum;

    // Cumulative image of a and b
    float *pCuma = NULL, *pCumb = NULL;
    CumImage(pa, &pCuma);
    CumImage(pb, &pCumb);

    // Finally calculate the output image q=ag+b
    float mean_a, mean_b;
    row_idx = Hstart*Width;
    for (i = Hstart; i < Hend; i++)
    {
        // Check the boundary for radius
        if (i < radius) uprow = 0;
        else uprow = i - radius;
        upidx = uprow*(Width + 1);
        if (i + radius >= Height) downrow = Height;
        else downrow = i + radius + 1;
        downidx = downrow*(Width + 1);
        for (j = Wstart; j < Wend; j++)
        {
            // Check the boundary for radius
            if (j < radius) leftcol = 0;
            else leftcol = j - radius;
            if (j + radius >= Width) rightcol = Width;
            else rightcol = j + radius + 1;
            field_size = (downrow - uprow)*(rightcol - leftcol);
            long p1, p2, p3, p4;
            p1 = downidx + rightcol;
            p2 = downidx + leftcol;
            p3 = upidx + rightcol;
            p4 = upidx + leftcol;
            // Field mean
            mean_a = (pCuma[p1] - pCuma[p2] - pCuma[p3] + pCuma[p4]) / field_size;
            // Field mean
            mean_b = (pCumb[p1] - pCumb[p2] - pCumb[p3] + pCumb[p4]) / field_size;
            // New pixel value
            long idx = row_idx + j;
            int value = int(mean_a*pGuidedData[idx] + mean_b);
            CLAMP0255(value);
            pData[idx] = value;
        }
        row_idx += Width;
    }

    delete[] pa;
    delete[] pb;
    delete[] pCuma;
    delete[] pCumb;

View
Code

View
Code

 导向滤波还有雷同栽高效算法,基本思维是经过下采样输入图P和引图G,得到比较小的图像P’和G’。用她来计量系数A’和B’。然后经过线性插值的计恢复原有大小得到近似之A和B,用来和原始大小的导图来计量输出Q。这样,ak和bk的计算不是于全尺寸图像上,能省掉成千上万运算量,而最后之结果未吃大要命影响。

 导向滤波还有一样种植高效算法,基本思想是透过下采样输入图P和带图G,得到比较小的图像P’和G’。用它们来计算系数A’和B’。然后经过线性插值的法门恢复原来大小得到近似的A和B,用来跟初大小的带图来计算输出Q。这样,ak和bk的算计不是以全尺寸图像上,能省掉成千上万运算量,而最终之结果不受特别酷影响。

 下面坐含有保边平滑特性的导向滤波为条例,来瞧效果。如齐一样篇所说,当输入图P和引图G相同时,导向滤波呈现保边平滑特性。

 下面坐带有保边平滑特性的导向滤波为条例,来瞧效果。如齐同样首所说,当输入图P和带图G相同时,导向滤波呈现保边平滑特性。

图片 25  
图片 26

图片 27  
图片 28

                              
原图                                                                                                
半径3,ε=52

                              
原图                                                                                                
半径3,ε=52

图片 29  
图片 30

图片 31  
图片 32

                   
半径3,ε=102                                                
                                          
半径3,ε=202

                   
半径3,ε=102                                                
                                          
半径3,ε=202

图片 33
  图片 34

图片 35
  图片 36

                         原图            
                                         
 半径5,ε=202

                         原图            
                                         
 半径5,ε=202

 总体来说,P=G时,导向滤波的保边平滑特性和带有保边功能领域平滑滤波有类似之意义。

 总体来说,P=G时,导向滤波的保边平滑特性和包含保边功能领域平滑滤波有接近之功用。

 

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图