图像处理之积分图应用二(快速边缘保留滤波算法)

简介: 图像处理之积分图应用二(快速边缘保留滤波算法)

图像处理之积分图应用二(快速边缘保留滤波算法)

一:基本原理

传统的图像边缘保留滤波算法-如高斯双边模糊、Mean-Shift模糊等计算复杂、效率比较低,虽然有各种手段优化或者快速计算方法,当时算法相对一般码农来说理解起来比较费劲,不是一个的选择,而通过积分图像实现局部均方差的边缘保留模糊算法,计算简单而且可以做到计算量跟半径无关、跟上面提到两种边缘保留滤波(EPF)算法效率高很多。首先局部均方差滤波中计算局部均值的公式如下:

当边缘很弱的时候系数K趋近于0、该点的矫正之后的像素值就接近平均值。而当边缘很强的时候系数K趋近于1、该点的模糊之后的像素值就接近等于输入像素值。上述计算中最中意的是窗口内像素的均值与方差,计算均值可以根据积分图像很容易得到,而计算方差根据一系列的数学推导可以得到如下:

就是说可以根据积分图像通过常量次数的计算得到局部的均值与方差,让这种情况下的滤波变成一个常量时间完成的操作与窗口半径大小无关。

二:算法流程

1. 根据输入的图像计算得到积分图像,参见《图像处理之积分图像算法》

2. 根据输入的半径大小计算窗口内像素均值与方差、计算得到每个像素新的像素值

3. 循环每个个像素,重复第2步计算,得到最终的局部均方差滤波图像

三:代码实现

package com.gloomyfish.ii.demo;
 
import java.awt.image.BufferedImage;
 
/**
 * fast edge preserve filter algorithm base on integral image
 * @author zhigang jia
 * @E-mail:bfnh1998@hotmail.com
 *
 */
public class FastEPFilter extends AbstractImageOptionFilter {
  // 窗口半径大小
  private int xr;
  private int yr;
  private float sigma;
  public FastEPFilter() {
  }
  
  public void setWinsize(int radius) {
    this.xr = radius;
    this.yr = radius;
  }
 
  public float getSigma() {
    return sigma;
  }
 
  public void setSigma(float sigma) {
    this.sigma = sigma;
  }
 
  @Override
  public BufferedImage process(BufferedImage image) {
    long time = System.currentTimeMillis();
    int width = image.getWidth();
    int height = image.getHeight();
    // get image data
    int[] pixels = new int[width * height];
    int[] outPixels = new int[width * height];
    getRGB(image, 0, 0, width, height, pixels);
    int size = (xr * 2 + 1) * (yr * 2 + 1);
    int r = 0, g = 0, b = 0;
    float sigma2 = sigma*sigma;
    
    // per-calculate integral image
    byte[] R = new byte[width*height];
    byte[] G = new byte[width*height];
    byte[] B = new byte[width*height];
    getRGB(width, height, pixels, R, G, B);
    IntIntegralImage rii = new IntIntegralImage();
    rii.setImage(R);
    rii.process(width, height);
    IntIntegralImage gii = new IntIntegralImage();
    gii.setImage(G);
    gii.process(width, height);
    IntIntegralImage bii = new IntIntegralImage();
    bii.setImage(B);
    bii.process(width, height);
    int index = 0;
    
    for (int row = yr; row < height - yr; row++) {
      for (int col = xr; col < width - xr; col++) {
        index = row * width + col;
        r = ((pixels[index] >> 16) & 0xff);
        g = (pixels[index] >> 8) & 0xff;
        b = (pixels[index] & 0xff);
        
        int sr = rii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        int sg = gii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        int sb = bii.getBlockSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        
        float vr = rii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        float vg = gii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        float vb = bii.getBlockSquareSum(col, row, (yr * 2 + 1), (xr * 2 + 1));
        
        // 计算均值
        float mr = sr / size;
        float mg = sg / size;
        float mb = sb / size;
        
        // 计算方差
        float dr = (vr - (sr*sr)/size)/size;
        float dg = (vg - (sg*sg)/size)/size;
        float db = (vb - (sb*sb)/size)/size;
        
        // 计算系数K
        float kr = dr / (dr+sigma2);
        float kg = dg / (dg+sigma2);
        float kb = db / (db+sigma2);
        
        // 得到滤波后的像素值
        r = (int)((1-kr)*mr + kr*r);
        g = (int)((1-kg)*mg + kg*g);
        b = (int)((1-kb)*mb + kb*b);
        
        outPixels[row * width + col] = (0xff << 24) | (clamp(r) << 16) | (clamp(g) << 8) | clamp(b);
      }
    }
    System.out.println("FastEPFilter ->> time duration : " + (System.currentTimeMillis() - time));
    BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    setRGB(dest, 0, 0, width, height, outPixels);
    return dest;
  }
  
  /** Returns the red, green and blue planes as 3 byte arrays. */
  public void getRGB(int width, int height, int[] pixels, byte[] R, byte[] G, byte[] B) {
    int c, r, g, b;
    for (int i=0; i < width*height; i++) {
      c = pixels[i];
      r = (c&0xff0000)>>16;
      g = (c&0xff00)>>8;
      b = c&0xff;
      R[i] = (byte)r;
      G[i] = (byte)g;
      B[i] = (byte)b;
    }
  }
 
}

四:运行效果

半径设置为5,即窗口大小为5的时候,调整参数sigma的值即可得到此效果

其实很多磨皮的算法都是基于这个算法实现的,这个才是我想说的重点,

只有耐心看到此处才可以得到正确的答案。



五:参考:


http://imagej.net/Integral_Image_Filters#Variance


http://www.activovision.com/octavi/doku.php?id=integral_images

相关文章
|
28天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的优化算法及其应用
【10月更文挑战第8天】 本文将探讨深度学习中常用的优化算法,包括梯度下降法、Adam和RMSProp等,介绍这些算法的基本原理与应用场景。通过实例分析,帮助读者更好地理解和应用这些优化算法,提高深度学习模型的训练效率与性能。
139 63
|
12天前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
23 0
|
23天前
|
存储 算法 搜索推荐
这些算法在实际应用中有哪些具体案例呢
【10月更文挑战第19天】这些算法在实际应用中有哪些具体案例呢
26 1
|
29天前
|
机器学习/深度学习 人工智能 算法
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
68 0
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
|
1月前
|
算法 安全 物联网
如何应用SM2算法进行身份认证
【10月更文挑战第5天】如何应用SM2算法进行身份认证
58 1
|
1月前
|
存储 算法 安全
SM2算法的应用场景有哪些?
【10月更文挑战第5天】SM2算法的应用场景有哪些?
67 1
|
23天前
|
监控 算法 数据挖掘
HyperLogLog算法有哪些应用场景呢
【10月更文挑战第19天】HyperLogLog算法有哪些应用场景呢
15 0
|
29天前
|
机器学习/深度学习 算法 数据建模
计算机前沿技术-人工智能算法-生成对抗网络-算法原理及应用实践
计算机前沿技术-人工智能算法-生成对抗网络-算法原理及应用实践
25 0