Java转换一个灰度和sepia版本的图像与BufferedImage。

时间:2021-03-06 16:34:22

I want to read an image and convert and output the original image, a greyscale version, and a sepia version. I am having trouble with the conversion, not very familiar with BufferedImage, and especially having problems with getRGB and setRGB method. I have this so far

我想要读取一个图像,并转换和输出原始图像,一个灰度版本,和一个sepia版本。我在转换过程中遇到了麻烦,不太熟悉BufferedImage,特别是getRGB和setRGB方法有问题。到目前为止。

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;

public class ChangeColor{
  static BufferedImage readImage( String Pic ) throws Exception {

    BufferedImage image = ImageIO.read( new File("Pic.jpg") );
    return( image );
  }

  public static void saveImage( BufferedImage img, File file ) throws IOException {

        ImageWriter      writer = null;
        java.util.Iterator iter = ImageIO.getImageWritersByFormatName("jpg");

        if( iter.hasNext() ){
            writer = (ImageWriter)iter.next();
        }

        ImageOutputStream ios = ImageIO.createImageOutputStream( file );
        writer.setOutput(ios);

        ImageWriteParam param = new JPEGImageWriteParam( java.util.Locale.getDefault() );
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) ;
        param.setCompressionQuality(0.98f);

        writer.write(null, new IIOImage( img, null, null ), param);

    }

  public static BufferedImage color2gray( BufferedImage inImage ) {

    int            width    = inImage.getWidth();
    int            height   = inImage.getHeight();
    BufferedImage  outImage = new BufferedImage( width, height, BufferedImage.TYPE_3BYTE_BGR );

    for(int i=0; i<height; i++){
        for(int j=0; j<width; j++){
           Color c = new Color(image.getRGB(j, i));
           int red = (int)(c.getRed() * 0.2126);
           int green = (int)(c.getGreen() * 0.7152);
           int blue = (int)(c.getBlue() *0.0722);
           Color newColor = new Color(red+green+blue,
           red+green+blue,red+green+blue);
           image.setRGB(j,i,newColor.getRGB());
           }
    }

    return( outImage );
  }

  public static BufferedImage color2sepia( BufferedImage inImage ) {

    int            width    = inImage.getWidth();
    int            height   = inImage.getHeight();
    BufferedImage  outImage = new BufferedImage( width, height, BufferedImage.TYPE_3BYTE_BGR );
    for(int i=0; i<height; i++){
        for(int j=0; j<width; j++){
           Color c = new Color(image.getRGB(j, i));
           int red = (int)(c.getRed());
           int green = (int)(c.getGreen());
           int blue = (int)(c.getBlue());
           Color newColor = new Color(red* .393)+(green*.769)+(blue* .189),
           (red* .349)+(green*.686)+(blue* .168),(red* .272)+(green*.534)+(blue* .131);
           image.setRGB(j,i,newColor.getRGB());
           }
    }
    return( outImage );
  }



  public static void main(String[] args) throws Exception {

    BufferedImage colorImage, grayImage, sepiaImage;

    if (args.length != 1)
        System.out.println( "" );
    else
    {
        colorImage = readImage  ( args[0] );
    grayImage  = color2gray ( colorImage );
    sepiaImage = color2sepia( colorImage );

    saveImage( grayImage,  new File( "greyPic.jpg" + args[0] ) );
    saveImage( sepiaImage, new File( "sepiaPic.jpg"+ args[0] ) );
    }
  }

}

This is an image of what the output should look like:

这是一个输出应该是什么样子的图像:

Java转换一个灰度和sepia版本的图像与BufferedImage。 Thank you.

谢谢你!

3 个解决方案

#1


7  

Gray scaling is rather easy, sepia not so much. I stole the algorithm off the net...

灰度的缩放很简单,乌贼不那么容易。我从网上偷走了算法…

Java转换一个灰度和sepia版本的图像与BufferedImage。

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorAlteration {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                try {
                    BufferedImage master = ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
                    BufferedImage gray = toGrayScale(master);
                    BufferedImage sepia = toSepia(master, 80);

                    JPanel panel = new JPanel(new GridBagLayout());
                    panel.add(new JLabel(new ImageIcon(master)));
                    panel.add(new JLabel(new ImageIcon(gray)));
                    panel.add(new JLabel(new ImageIcon(sepia)));

                    JOptionPane.showMessageDialog(null, panel);

                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static BufferedImage toGrayScale(BufferedImage master) {
        BufferedImage gray = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);

        // Automatic converstion....
        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        op.filter(master, gray);

        return gray;
    }

    public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {

        BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
        // Play around with this.  20 works well and was recommended
        //   by another developer. 0 produces black/white image
        int sepiaDepth = 20;

        int w = img.getWidth();
        int h = img.getHeight();

        WritableRaster raster = sepia.getRaster();

        // We need 3 integers (for R,G,B color values) per pixel.
        int[] pixels = new int[w * h * 3];
        img.getRaster().getPixels(0, 0, w, h, pixels);

        //  Process 3 ints at a time for each pixel.  Each pixel has 3 RGB
        //    colors in array
        for (int i = 0; i < pixels.length; i += 3) {
            int r = pixels[i];
            int g = pixels[i + 1];
            int b = pixels[i + 2];

            int gry = (r + g + b) / 3;
            r = g = b = gry;
            r = r + (sepiaDepth * 2);
            g = g + sepiaDepth;

            if (r > 255) {
                r = 255;
            }
            if (g > 255) {
                g = 255;
            }
            if (b > 255) {
                b = 255;
            }

            // Darken blue color to increase sepia effect
            b -= sepiaIntensity;

            // normalize if out of bounds
            if (b < 0) {
                b = 0;
            }
            if (b > 255) {
                b = 255;
            }

            pixels[i] = r;
            pixels[i + 1] = g;
            pixels[i + 2] = b;
        }
        raster.setPixels(0, 0, w, h, pixels);

        return sepia;
    }
}

You can find the original posting for the sepia algorithm here

你可以在这里找到sepia算法的原始贴子。

And because I'm stubborn...I changed the sepia algorithm to work with alpha based images...

因为我固执……我改变了sepia算法来处理基于alpha的图像…

public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {

    BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
    // Play around with this.  20 works well and was recommended
    //   by another developer. 0 produces black/white image
    int sepiaDepth = 20;

    int w = img.getWidth();
    int h = img.getHeight();

    WritableRaster raster = sepia.getRaster();

    // We need 3 integers (for R,G,B color values) per pixel.
    int[] pixels = new int[w * h * 3];
    img.getRaster().getPixels(0, 0, w, h, pixels);

    for (int x = 0; x < img.getWidth(); x++) {
        for (int y = 0; y < img.getHeight(); y++) {

            int rgb = img.getRGB(x, y);
            Color color = new Color(rgb, true);
            int r = color.getRed();
            int g = color.getGreen();
            int b = color.getBlue();
            int gry = (r + g + b) / 3;

            r = g = b = gry;
            r = r + (sepiaDepth * 2);
            g = g + sepiaDepth;

            if (r > 255) {
                r = 255;
            }
            if (g > 255) {
                g = 255;
            }
            if (b > 255) {
                b = 255;
            }

            // Darken blue color to increase sepia effect
            b -= sepiaIntensity;

            // normalize if out of bounds
            if (b < 0) {
                b = 0;
            }
            if (b > 255) {
                b = 255;
            }

            color = new Color(r, g, b, color.getAlpha());
            sepia.setRGB(x, y, color.getRGB());

        }
    }

    return sepia;
}

#2


2  

I used @@MadProgrammer code to write this code. Which I think it is much more efficient.

我用@@ mad程序员代码来编写这段代码。我认为这更有效率。

  1. Using raster data of the image instead of accessing each byte of image. Although it seems it copys the data into pixels array, it is not used in the program.

    使用图像的光栅数据,而不是访问图像的每个字节。尽管它似乎将数据复制到像素数组中,但它并没有被应用到程序中。

  2. You are calling getRGB each time + getWidth() + getHeight() + getRed(), getGreen() + getBlue().

    您调用getRGB每次+ getWidth() + getHeight() + getRed(), getGreen() + getBlue()。

  3. Writing colors directly into your image, I think it is a bottleneck once you write a color using setRGB, you will lose graphic processor benefits. (I read it somewhere, but can't find the link now.)

    直接把颜色写进你的图像,我认为这是一个瓶颈,一旦你用setRGB来写颜色,你将失去图形处理器的好处。(我在什么地方读过,但现在找不到链接。)

  4. Converting the color back to Color object and getting it back using getRGB().

    将颜色转换回颜色对象,并使用getRGB()返回。

All I did was using bit-wise operators which it is very fast and then copied the pixel arrays once I was done working with it. Function call is expensive and I avoided them.

我所做的只是使用了位运算符,它是非常快的,然后复制了像素阵列一旦我完成了它。函数调用很昂贵,我避免了它们。

However, thanks for the idea, @MadProgrammer.

但是,谢谢你的想法,@ mad程序员。

public static BufferedImage toSepia(BufferedImage image, int sepiaIntensity) {

    int width = image.getWidth();
    int height = image.getHeight();
    int sepiaDepth = 20;

    int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);

    for (int i = 0; i < imagePixels.length; i++) {
        int color = imagePixels[i];

        int r = (color >> 16) & 0xff;
        int g = (color >> 8) & 0xff;
        int b = (color) & 0xff;
        int gry = (r + g + b) / 3;

        r = g = b = gry;
        r = r + (sepiaDepth * 2);
        g = g + sepiaDepth;

        if (r > 255) {
            r = 255;
        }
        if (g > 255) {
            g = 255;
        }
        if (b > 255) {
            b = 255;
        }

        // Darken blue color to increase sepia effect
        b -= sepiaIntensity;

        // normalize if out of bounds
        if (b < 0) {
            b = 0;
        }
        if (b > 255) {
            b = 255;
        }

        imagePixels[i] = (color & 0xff000000) + (r << 16) + (g << 8) + b;
    }

    BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    res.setRGB(0, 0, width, height, imagePixels, 0, width);
    return res;
}

#3


0  

You can create a filter interface for code reuse.

您可以为代码重用创建一个过滤器接口。

FilterApp

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class FilterApp {
    public static ClassLoader loader = FilterApp.class.getClassLoader();
    public static String outputDir = "build";

    public static void main(String[] args) {
        try {
            BufferedImage srcImage = loadImage("lobster.jpg");
            File dir = new File(outputDir);

            if (!dir.exists()) {
                dir.mkdirs();
            }

            for (FilterType filter : FilterType.values()) {
                BufferedImage filteredImage = filter.applyFilter(srcImage);
                String filename = String.format("%s/lobster_%s", outputDir, filter.name().toLowerCase());
                writeImage(filteredImage, filename, "jpg");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static BufferedImage loadImage(String filename) throws IOException {
        return ImageIO.read(loader.getResourceAsStream("resources/" + filename));
    }

    private static void writeImage(BufferedImage image, String filename, String ext) throws IOException {
        ImageIO.write(image, ext, new File(filename + '.' + ext));
    }
}

FilterType

import java.awt.image.BufferedImage;

import filter.GreyscaleFilter;
import filter.ImageFilter;
import filter.InvertFilter;
import filter.SepiaFilter;

public enum FilterType {
    GREYSCALE(new GreyscaleFilter()),
    INVERT(new InvertFilter()),
    SEPIA_10(new SepiaFilter(10));

    private ImageFilter filter;

    public ImageFilter getFilter() { return filter; }

    public BufferedImage applyFilter(BufferedImage img) {
        return this.filter.apply(img);
    }

    private FilterType(ImageFilter filter) {
        this.filter = filter;
    }
}

ImageFilter

package filter;

import java.awt.image.BufferedImage;

/** Common Interface for different filters. */ 
public interface ImageFilter {
    public BufferedImage apply(BufferedImage img);
}

GreyscaleFilter

package filter;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;

public class GreyscaleFilter implements ImageFilter {
    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

        op.filter(img, result);

        return result;
    }
}

InvertFilter

package filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class InvertFilter implements ImageFilter {
    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb, true);
                int r = 255 - color.getRed();
                int g = 255 - color.getGreen();
                int b = 255 - color.getBlue();

                color = new Color(r, g, b, color.getAlpha());
                result.setRGB(x, y, color.getRGB());
            }
        }

        return result;
    }
}

SepiaFilter

package filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

// Algorithm obtained from http://*.com/questions/21899824
public class SepiaFilter implements ImageFilter {
    private int intensity;

    public void setIntensity(int intensity) { this.intensity = intensity; }
    public int getIntensity() { return intensity; }

    public SepiaFilter(int intensity) {
        this.intensity = intensity;
    }

    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
        // Play around with this.
        // 20 works well and was recommended by another developer.
        // 0 produces black/white image
        int sepiaDepth = 20;

        int w = img.getWidth();
        int h = img.getHeight();

        // We need 3 integers (for R,G,B color values) per pixel.
        int[] pixels = new int[w * h * 3];
        img.getRaster().getPixels(0, 0, w, h, pixels);

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb, true);
                int r = color.getRed();
                int g = color.getGreen();
                int b = color.getBlue();
                int gry = (r + g + b) / 3;

                r = g = b = gry;
                r = r + (sepiaDepth * 2);
                g = g + sepiaDepth;

                if (r > 255) { r = 255; }
                if (g > 255) { g = 255; }
                if (b > 255) { b = 255; }

                // Darken blue color to increase sepia effect
                b -= this.intensity;

                // normalize if out of bounds
                if (b < 0)   { b = 0; }
                if (b > 255) { b = 255; }

                color = new Color(r, g, b, color.getAlpha());
                result.setRGB(x, y, color.getRGB());
            }
        }

        return result;
    }
}

Output

Source Image

源图像

Java转换一个灰度和sepia版本的图像与BufferedImage。

Generated Images

生成的图像

Java转换一个灰度和sepia版本的图像与BufferedImage。 Java转换一个灰度和sepia版本的图像与BufferedImage。 Java转换一个灰度和sepia版本的图像与BufferedImage。

#1


7  

Gray scaling is rather easy, sepia not so much. I stole the algorithm off the net...

灰度的缩放很简单,乌贼不那么容易。我从网上偷走了算法…

Java转换一个灰度和sepia版本的图像与BufferedImage。

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorAlteration {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                try {
                    BufferedImage master = ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
                    BufferedImage gray = toGrayScale(master);
                    BufferedImage sepia = toSepia(master, 80);

                    JPanel panel = new JPanel(new GridBagLayout());
                    panel.add(new JLabel(new ImageIcon(master)));
                    panel.add(new JLabel(new ImageIcon(gray)));
                    panel.add(new JLabel(new ImageIcon(sepia)));

                    JOptionPane.showMessageDialog(null, panel);

                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static BufferedImage toGrayScale(BufferedImage master) {
        BufferedImage gray = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);

        // Automatic converstion....
        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        op.filter(master, gray);

        return gray;
    }

    public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {

        BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
        // Play around with this.  20 works well and was recommended
        //   by another developer. 0 produces black/white image
        int sepiaDepth = 20;

        int w = img.getWidth();
        int h = img.getHeight();

        WritableRaster raster = sepia.getRaster();

        // We need 3 integers (for R,G,B color values) per pixel.
        int[] pixels = new int[w * h * 3];
        img.getRaster().getPixels(0, 0, w, h, pixels);

        //  Process 3 ints at a time for each pixel.  Each pixel has 3 RGB
        //    colors in array
        for (int i = 0; i < pixels.length; i += 3) {
            int r = pixels[i];
            int g = pixels[i + 1];
            int b = pixels[i + 2];

            int gry = (r + g + b) / 3;
            r = g = b = gry;
            r = r + (sepiaDepth * 2);
            g = g + sepiaDepth;

            if (r > 255) {
                r = 255;
            }
            if (g > 255) {
                g = 255;
            }
            if (b > 255) {
                b = 255;
            }

            // Darken blue color to increase sepia effect
            b -= sepiaIntensity;

            // normalize if out of bounds
            if (b < 0) {
                b = 0;
            }
            if (b > 255) {
                b = 255;
            }

            pixels[i] = r;
            pixels[i + 1] = g;
            pixels[i + 2] = b;
        }
        raster.setPixels(0, 0, w, h, pixels);

        return sepia;
    }
}

You can find the original posting for the sepia algorithm here

你可以在这里找到sepia算法的原始贴子。

And because I'm stubborn...I changed the sepia algorithm to work with alpha based images...

因为我固执……我改变了sepia算法来处理基于alpha的图像…

public static BufferedImage toSepia(BufferedImage img, int sepiaIntensity) {

    BufferedImage sepia = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
    // Play around with this.  20 works well and was recommended
    //   by another developer. 0 produces black/white image
    int sepiaDepth = 20;

    int w = img.getWidth();
    int h = img.getHeight();

    WritableRaster raster = sepia.getRaster();

    // We need 3 integers (for R,G,B color values) per pixel.
    int[] pixels = new int[w * h * 3];
    img.getRaster().getPixels(0, 0, w, h, pixels);

    for (int x = 0; x < img.getWidth(); x++) {
        for (int y = 0; y < img.getHeight(); y++) {

            int rgb = img.getRGB(x, y);
            Color color = new Color(rgb, true);
            int r = color.getRed();
            int g = color.getGreen();
            int b = color.getBlue();
            int gry = (r + g + b) / 3;

            r = g = b = gry;
            r = r + (sepiaDepth * 2);
            g = g + sepiaDepth;

            if (r > 255) {
                r = 255;
            }
            if (g > 255) {
                g = 255;
            }
            if (b > 255) {
                b = 255;
            }

            // Darken blue color to increase sepia effect
            b -= sepiaIntensity;

            // normalize if out of bounds
            if (b < 0) {
                b = 0;
            }
            if (b > 255) {
                b = 255;
            }

            color = new Color(r, g, b, color.getAlpha());
            sepia.setRGB(x, y, color.getRGB());

        }
    }

    return sepia;
}

#2


2  

I used @@MadProgrammer code to write this code. Which I think it is much more efficient.

我用@@ mad程序员代码来编写这段代码。我认为这更有效率。

  1. Using raster data of the image instead of accessing each byte of image. Although it seems it copys the data into pixels array, it is not used in the program.

    使用图像的光栅数据,而不是访问图像的每个字节。尽管它似乎将数据复制到像素数组中,但它并没有被应用到程序中。

  2. You are calling getRGB each time + getWidth() + getHeight() + getRed(), getGreen() + getBlue().

    您调用getRGB每次+ getWidth() + getHeight() + getRed(), getGreen() + getBlue()。

  3. Writing colors directly into your image, I think it is a bottleneck once you write a color using setRGB, you will lose graphic processor benefits. (I read it somewhere, but can't find the link now.)

    直接把颜色写进你的图像,我认为这是一个瓶颈,一旦你用setRGB来写颜色,你将失去图形处理器的好处。(我在什么地方读过,但现在找不到链接。)

  4. Converting the color back to Color object and getting it back using getRGB().

    将颜色转换回颜色对象,并使用getRGB()返回。

All I did was using bit-wise operators which it is very fast and then copied the pixel arrays once I was done working with it. Function call is expensive and I avoided them.

我所做的只是使用了位运算符,它是非常快的,然后复制了像素阵列一旦我完成了它。函数调用很昂贵,我避免了它们。

However, thanks for the idea, @MadProgrammer.

但是,谢谢你的想法,@ mad程序员。

public static BufferedImage toSepia(BufferedImage image, int sepiaIntensity) {

    int width = image.getWidth();
    int height = image.getHeight();
    int sepiaDepth = 20;

    int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);

    for (int i = 0; i < imagePixels.length; i++) {
        int color = imagePixels[i];

        int r = (color >> 16) & 0xff;
        int g = (color >> 8) & 0xff;
        int b = (color) & 0xff;
        int gry = (r + g + b) / 3;

        r = g = b = gry;
        r = r + (sepiaDepth * 2);
        g = g + sepiaDepth;

        if (r > 255) {
            r = 255;
        }
        if (g > 255) {
            g = 255;
        }
        if (b > 255) {
            b = 255;
        }

        // Darken blue color to increase sepia effect
        b -= sepiaIntensity;

        // normalize if out of bounds
        if (b < 0) {
            b = 0;
        }
        if (b > 255) {
            b = 255;
        }

        imagePixels[i] = (color & 0xff000000) + (r << 16) + (g << 8) + b;
    }

    BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    res.setRGB(0, 0, width, height, imagePixels, 0, width);
    return res;
}

#3


0  

You can create a filter interface for code reuse.

您可以为代码重用创建一个过滤器接口。

FilterApp

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class FilterApp {
    public static ClassLoader loader = FilterApp.class.getClassLoader();
    public static String outputDir = "build";

    public static void main(String[] args) {
        try {
            BufferedImage srcImage = loadImage("lobster.jpg");
            File dir = new File(outputDir);

            if (!dir.exists()) {
                dir.mkdirs();
            }

            for (FilterType filter : FilterType.values()) {
                BufferedImage filteredImage = filter.applyFilter(srcImage);
                String filename = String.format("%s/lobster_%s", outputDir, filter.name().toLowerCase());
                writeImage(filteredImage, filename, "jpg");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static BufferedImage loadImage(String filename) throws IOException {
        return ImageIO.read(loader.getResourceAsStream("resources/" + filename));
    }

    private static void writeImage(BufferedImage image, String filename, String ext) throws IOException {
        ImageIO.write(image, ext, new File(filename + '.' + ext));
    }
}

FilterType

import java.awt.image.BufferedImage;

import filter.GreyscaleFilter;
import filter.ImageFilter;
import filter.InvertFilter;
import filter.SepiaFilter;

public enum FilterType {
    GREYSCALE(new GreyscaleFilter()),
    INVERT(new InvertFilter()),
    SEPIA_10(new SepiaFilter(10));

    private ImageFilter filter;

    public ImageFilter getFilter() { return filter; }

    public BufferedImage applyFilter(BufferedImage img) {
        return this.filter.apply(img);
    }

    private FilterType(ImageFilter filter) {
        this.filter = filter;
    }
}

ImageFilter

package filter;

import java.awt.image.BufferedImage;

/** Common Interface for different filters. */ 
public interface ImageFilter {
    public BufferedImage apply(BufferedImage img);
}

GreyscaleFilter

package filter;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;

public class GreyscaleFilter implements ImageFilter {
    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

        op.filter(img, result);

        return result;
    }
}

InvertFilter

package filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class InvertFilter implements ImageFilter {
    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb, true);
                int r = 255 - color.getRed();
                int g = 255 - color.getGreen();
                int b = 255 - color.getBlue();

                color = new Color(r, g, b, color.getAlpha());
                result.setRGB(x, y, color.getRGB());
            }
        }

        return result;
    }
}

SepiaFilter

package filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

// Algorithm obtained from http://*.com/questions/21899824
public class SepiaFilter implements ImageFilter {
    private int intensity;

    public void setIntensity(int intensity) { this.intensity = intensity; }
    public int getIntensity() { return intensity; }

    public SepiaFilter(int intensity) {
        this.intensity = intensity;
    }

    @Override
    public BufferedImage apply(BufferedImage img) {
        BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
        // Play around with this.
        // 20 works well and was recommended by another developer.
        // 0 produces black/white image
        int sepiaDepth = 20;

        int w = img.getWidth();
        int h = img.getHeight();

        // We need 3 integers (for R,G,B color values) per pixel.
        int[] pixels = new int[w * h * 3];
        img.getRaster().getPixels(0, 0, w, h, pixels);

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb, true);
                int r = color.getRed();
                int g = color.getGreen();
                int b = color.getBlue();
                int gry = (r + g + b) / 3;

                r = g = b = gry;
                r = r + (sepiaDepth * 2);
                g = g + sepiaDepth;

                if (r > 255) { r = 255; }
                if (g > 255) { g = 255; }
                if (b > 255) { b = 255; }

                // Darken blue color to increase sepia effect
                b -= this.intensity;

                // normalize if out of bounds
                if (b < 0)   { b = 0; }
                if (b > 255) { b = 255; }

                color = new Color(r, g, b, color.getAlpha());
                result.setRGB(x, y, color.getRGB());
            }
        }

        return result;
    }
}

Output

Source Image

源图像

Java转换一个灰度和sepia版本的图像与BufferedImage。

Generated Images

生成的图像

Java转换一个灰度和sepia版本的图像与BufferedImage。 Java转换一个灰度和sepia版本的图像与BufferedImage。 Java转换一个灰度和sepia版本的图像与BufferedImage。