原创文章地址:点击打开链接
双边滤波源代码如下:
package test;
/**
* 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.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
/**
* 双边滤波
* 转载:http://blog.csdn.net/jia20003/article/details/7740683
* @author Bob
* 2017年9月9日12:25:41
*/
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(double ds,double rs) {
this.ds = ds;
this.rs = rs;
}
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);
}
}
}
/**
* 灰度图像
* @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) {
try {
long l1=System.currentTimeMillis();
BilateralFilter bf = new BilateralFilter(3,8);//初始化 距离西格玛 和 半径西格玛
Image a = ImageIO.read(new File("e://old_1504255184945.png"));
int width = a.getWidth(null);
int height = a.getHeight(null);
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.drawImage(a, 0, 0, width, height, null);
g.dispose();
BufferedImage dest =new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
image=bf.filter(image, dest);
ImageIO.write(image, "png",new File("e:/new_" + new Date().getTime() + ".png"));
long l2=System.currentTimeMillis();
System.out.println(l2-l1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
> 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) {
try {
long l1=System.currentTimeMillis();
BilateralFilter bf = new BilateralFilter(3,8);//初始化 距离西格玛 和 半径西格玛
Image a = ImageIO.read(new File("e://old_1504255184945.png"));
int width = a.getWidth(null);
int height = a.getHeight(null);
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.drawImage(a, 0, 0, width, height, null);
g.dispose();
BufferedImage dest =new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
image=bf.filter(image, dest);
ImageIO.write(image, "png",new File("e:/new_" + new Date().getTime() + ".png"));
long l2=System.currentTimeMillis();
System.out.println(l2-l1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
需要继承AbstractBufferedImageOp:
package test;
/*
Copyright 2006 Jerry Huxtable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
/**
* A convenience class which implements those methods of BufferedImageOp which are rarely changed.
*/
public abstract class AbstractBufferedImageOp implements BufferedImageOp, Cloneable {
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
if ( dstCM == null )
dstCM = src.getColorModel();
return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null);
}
public Rectangle2D getBounds2D( BufferedImage src ) {
return new Rectangle(0, 0, src.getWidth(), src.getHeight());
}
public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) {
if ( dstPt == null )
dstPt = new Point2D.Double();
dstPt.setLocation( srcPt.getX(), srcPt.getY() );
return dstPt;
}
public RenderingHints getRenderingHints() {
return null;
}
/**
* A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
* penalty of BufferedImage.getRGB unmanaging the image.
* @param image a BufferedImage object
* @param x the left edge of the pixel block
* @param y the right edge of the pixel block
* @param width the width of the pixel arry
* @param height the height of the pixel arry
* @param pixels the array to hold the returned pixels. May be null.
* @return the pixels
* @see #setRGB
*/
public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
int type = image.getType();
if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
return image.getRGB( x, y, width, height, pixels, 0, width );
}
/**
* A convenience method for setting ARGB pixels in an image. This tries to avoid the performance
* penalty of BufferedImage.setRGB unmanaging the image.
* @param image a BufferedImage object
* @param x the left edge of the pixel block
* @param y the right edge of the pixel block
* @param width the width of the pixel arry
* @param height the height of the pixel arry
* @param pixels the array of pixels to set
* @see #getRGB
*/
public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
int type = image.getType();
if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
image.getRaster().setDataElements( x, y, width, height, pixels );
else
image.setRGB( x, y, width, height, pixels, 0, width );
}
public Object clone() {
try {
return super.clone();
}
catch ( CloneNotSupportedException e ) {
return null;
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/3ae3ffbe7a8b405c92aa82286fbf4f32.png)
高斯滤波:
![](https://i-blog.csdnimg.cn/blog_migrate/b674541d632d10e68fb090a4d0b590fc.png)
双边滤波
![](https://i-blog.csdnimg.cn/blog_migrate/a63d2e16096538ae315ccd146114b15a.png)