Java使用BufferedImage转换图像的灰度和棕褐色版本

我想读取图像并转换并输出原始图像,灰度版本和棕褐色版本。 我在转换时遇到问题,对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] ) ); } } } 

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

在此处输入图像描述 谢谢。

灰度比较容易,棕褐色不是那么多。 我从网上偷了算法……

兑换

 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; } } 

您可以在此处找到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; } 

我用@@ MadProgrammer代码编写了这段代码。 我认为它更有效率。

  1. 使用图像的栅格数据而不是访问图像的每个字节。 虽然它似乎将数据复制到像素arrays中,但它并未在程序中使用。

  2. 你每次调用getRGB + getWidth()+ getHeight()+ getRed(),getGreen()+ getBlue()。

  3. 将颜色直接写入图像,我认为使用setRGB编写颜色是一个瓶颈,您将失去图形处理器的好处。 (我在某处读过,但现在找不到链接。)

  4. 将颜色转换回Color对象并使用getRGB()将其恢复。

我所做的只是使用逐位运算符,它非常快,然后在我使用它之后复制像素数组。 函数调用很昂贵,我避免使用它们。

但是,感谢@MadProgrammer的想法。

 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; } 

您可以为代码重用创建filter接口。

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)); } } 

过滤式

 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://stackoverflow.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; } } 

产量

来源图片

在此处输入图像描述

生成的图像

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述