双边滤波JAVA代码实现
- 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();
- }
- }
- }
需要继承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;
- }
- }
- }
高斯滤波:
双边滤波