图像处理之双边滤波效果(Bilateral Filtering for Gray and Color Image)

- created by gloomyfish

图像处理之双边滤波效果(Bilateral Filtering for Gray and Color Image)

基本介绍:

普通的时空域的低通滤波器,在像素空间完成滤波以后,导致图像的边缘部分也变得不那么明显,

整张图像都变得同样的模糊,图像边缘细节丢失。双边滤波器(ABilateral Filter)可以很好的保

留边缘的同时消除噪声。双边滤波器能做到这些原因在于它不像普通的高斯/卷积低通滤波,只考

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

影响与像素值之间的相似程度生成两个不同的权重表(WeightTable),在计算中心像素的时候加以

考虑这两个权重,从而实现双边低通滤波。据说AdobePhotoshop的高斯磨皮功能就是应用了

双边低通滤波算法实现。






程序效果:


看我们的美女lena应用双边滤镜之后



程序关键代码解释:

建立距离高斯权重表(Weight Table)如下:

private void buildDistanceWeightTable() {  
    int size = 2 * radius + 1;  
    cWeightTable = new double[size][size];  
    for(int semirow = -radius; semirow <= radius; semirow++) {  
        for(int semicol = - radius; semicol <= radius; semicol++) {  
            // calculate Euclidean distance between center point and close pixels  
            double delta = Math.sqrt(semirow * semirow + semicol * semicol)/ds;  
            double deltaDelta = delta * delta;  
            cWeightTable[semirow+radius][semicol+radius] = Math.exp(deltaDelta * factor);  
        }  
    }  
}  




程序效果:


看我们的美女lena应用双边滤镜之后



程序关键代码解释:

建立距离高斯权重表(Weight Table)如下:


建立RGB值像素度高斯权重代码如下:
private void buildSimilarityWeightTable() {  
    sWeightTable = new double[256]; // since the color scope is 0 ~ 255  
    for(int i=0; i<256; i++) {  
        double delta = Math.sqrt(i * i ) / rs;  
        double deltaDelta = delta * delta;  
        sWeightTable[i] = Math.exp(deltaDelta * factor);  
    }  
}  




程序效果:


看我们的美女lena应用双边滤镜之后



程序关键代码解释:

建立距离高斯权重表(Weight Table)如下:

private void buildDistanceWeightTable() {  
    int size = 2 * radius + 1;  
    cWeightTable = new double[size][size];  
    for(int semirow = -radius; semirow <= radius; semirow++) {  
        for(int semicol = - radius; semicol <= radius; semicol++) {  
            // calculate Euclidean distance between center point and close pixels  
            double delta = Math.sqrt(semirow * semirow + semicol * semicol)/ds;  
            double deltaDelta = delta * delta;  
            cWeightTable[semirow+radius][semicol+radius] = Math.exp(deltaDelta * factor);  
        }  
    }  
}  

完成权重和计算与像素×权重和计算代码如下

for(int semirow = -radius; semirow <= radius; semirow++) {  
    for(int semicol = - radius; semicol <= radius; semicol++) {  
        if((row + semirow) >= 0 && (row + semirow) < height) {  
            rowOffset = row + semirow;  
        } else {  
            rowOffset = 0;  
        }  
          
        if((semicol + col) >= 0 && (semicol + col) < width) {  
            colOffset = col + semicol;  
        } else {  
            colOffset = 0;  
        }  
        index2 = rowOffset * width + colOffset;  
        ta2 = (inPixels[index2] >> 24) & 0xff;  
        tr2 = (inPixels[index2] >> 16) & 0xff;  
        tg2 = (inPixels[index2] >> 8) & 0xff;  
        tb2 = inPixels[index2] & 0xff;  
          
        csRedWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tr2 - tr))];  
        csGreenWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tg2 - tg))];  
        csBlueWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tb2 - tb))];  
          
        csSumRedWeight += csRedWeight;  
        csSumGreenWeight += csGreenWeight;  
        csSumBlueWeight += csBlueWeight;  
        redSum += (csRedWeight * (double)tr2);  
        greenSum += (csGreenWeight * (double)tg2);  
        blueSum += (csBlueWeight * (double)tb2);  
    }  
}  

完成归一化,得到输出像素点RGB值得代码如下:

tr = (int)Math.floor(redSum / csSumRedWeight);  
tg = (int)Math.floor(greenSum / csSumGreenWeight);  
tb = (int)Math.floor(blueSum / csSumBlueWeight);  
outPixels[index] = (ta << 24) | (clamp(tr) << 16) | (clamp(tg) << 8) | clamp(tb);  

关于什么卷积滤波,请参考:

http://blog.csdn.net/jia20003/article/details/7038938

关于高斯模糊算法,请参考:
http://blog.csdn.net/jia20003/article/details/7234741


最后想说,不给出源代码的博文不是好博文,基于Java完成的双边滤波速度有点慢

可以自己优化,双边滤镜完全源代码如下:

package com.gloomyfish.blurring.study;  
/** 
 *  A simple and important case of bilateral filtering is shift-invariant Gaussian filtering 
 *  refer to - http://graphics.ucsd.edu/~iman/Denoising/ 
 *  refer to - http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html 
 *  thanks to cyber 
 */  
import java.awt.image.BufferedImage;  
  
public class BilateralFilter extends AbstractBufferedImageOp {  
    private final static double factor = -0.5d;  
    private double ds; // distance sigma  
    private double rs; // range sigma  
    private int radius; // half length of Gaussian kernel Adobe Photoshop   
    private double[][] cWeightTable;  
    private double[] sWeightTable;  
    private int width;  
    private int height;  
      
    public BilateralFilter() {  
        this.ds = 1.0f;  
        this.rs = 1.0f;  
    }  
      
    private void buildDistanceWeightTable() {  
        int size = 2 * radius + 1;  
        cWeightTable = new double[size][size];  
        for(int semirow = -radius; semirow <= radius; semirow++) {  
            for(int semicol = - radius; semicol <= radius; semicol++) {  
                // calculate Euclidean distance between center point and close pixels  
                double delta = Math.sqrt(semirow * semirow + semicol * semicol)/ds;  
                double deltaDelta = delta * delta;  
                cWeightTable[semirow+radius][semicol+radius] = Math.exp(deltaDelta * factor);  
            }  
        }  
    }  
      
    /** 
     * for gray image 
     * @param row 
     * @param col 
     * @param inPixels 
     */  
    private void buildSimilarityWeightTable() {  
        sWeightTable = new double[256]; // since the color scope is 0 ~ 255  
        for(int i=0; i<256; i++) {  
            double delta = Math.sqrt(i * i ) / rs;  
            double deltaDelta = delta * delta;  
            sWeightTable[i] = Math.exp(deltaDelta * factor);  
        }  
    }  
      
    public void setDistanceSigma(double ds) {  
        this.ds = ds;  
    }  
      
    public void setRangeSigma(double rs) {  
        this.rs = rs;  
    }  
  
    @Override  
    public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
        width = src.getWidth();  
        height = src.getHeight();  
        //int sigmaMax = (int)Math.max(ds, rs);  
        //radius = (int)Math.ceil(2 * sigmaMax);  
        radius = (int)Math.max(ds, rs);  
        buildDistanceWeightTable();  
        buildSimilarityWeightTable();  
        if ( dest == null )  
            dest = createCompatibleDestImage( src, null );  
  
        int[] inPixels = new int[width*height];  
        int[] outPixels = new int[width*height];  
        getRGB( src, 0, 0, width, height, inPixels );  
        int index = 0;  
        double redSum = 0, greenSum = 0, blueSum = 0;  
        double csRedWeight = 0, csGreenWeight = 0, csBlueWeight = 0;  
        double csSumRedWeight = 0, csSumGreenWeight = 0, csSumBlueWeight = 0;  
        for(int row=0; row> 24) & 0xff;  
                tr = (inPixels[index] >> 16) & 0xff;  
                tg = (inPixels[index] >> 8) & 0xff;  
                tb = inPixels[index] & 0xff;  
                int rowOffset = 0, colOffset = 0;  
                int index2 = 0;  
                int ta2 = 0, tr2 = 0, tg2 = 0, tb2 = 0;  
                for(int semirow = -radius; semirow <= radius; semirow++) {  
                    for(int semicol = - radius; semicol <= radius; semicol++) {  
                        if((row + semirow) >= 0 && (row + semirow) < height) {  
                            rowOffset = row + semirow;  
                        } else {  
                            rowOffset = 0;  
                        }  
                          
                        if((semicol + col) >= 0 && (semicol + col) < width) {  
                            colOffset = col + semicol;  
                        } else {  
                            colOffset = 0;  
                        }  
                        index2 = rowOffset * width + colOffset;  
                        ta2 = (inPixels[index2] >> 24) & 0xff;  
                        tr2 = (inPixels[index2] >> 16) & 0xff;  
                        tg2 = (inPixels[index2] >> 8) & 0xff;  
                        tb2 = inPixels[index2] & 0xff;  
                          
                        csRedWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tr2 - tr))];  
                        csGreenWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tg2 - tg))];  
                        csBlueWeight = cWeightTable[semirow+radius][semicol+radius]  * sWeightTable[(Math.abs(tb2 - tb))];  
                          
                        csSumRedWeight += csRedWeight;  
                        csSumGreenWeight += csGreenWeight;  
                        csSumBlueWeight += csBlueWeight;  
                        redSum += (csRedWeight * (double)tr2);  
                        greenSum += (csGreenWeight * (double)tg2);  
                        blueSum += (csBlueWeight * (double)tb2);  
                    }  
                }  
                  
                tr = (int)Math.floor(redSum / csSumRedWeight);  
                tg = (int)Math.floor(greenSum / csSumGreenWeight);  
                tb = (int)Math.floor(blueSum / csSumBlueWeight);  
                outPixels[index] = (ta << 24) | (clamp(tr) << 16) | (clamp(tg) << 8) | clamp(tb);  
                  
                // clean value for next time...  
                redSum = greenSum = blueSum = 0;  
                csRedWeight = csGreenWeight = csBlueWeight = 0;  
                csSumRedWeight = csSumGreenWeight = csSumBlueWeight = 0;  
                  
            }  
        }  
        setRGB( dest, 0, 0, width, height, outPixels );  
        return dest;  
    }  
      
    public static int clamp(int p) {  
        return p < 0 ? 0 : ((p > 255) ? 255 : p);  
    }  
  
    public static void main(String[] args) {  
        BilateralFilter bf = new BilateralFilter();  
        bf.buildSimilarityWeightTable();  
    }  
}  



你可能感兴趣的:(Opencv,图像处理)