use*_*892 3 java bufferedimage image grayscale
我在将带有透明像素的彩色图像转换为灰度时遇到问题.我在这个网站上搜索并发现了相关的问题,但我没有用来解决我的问题.
我已经定义了一个方法"convertType",如下所示:
/*------------------------------
attempts to convert the type of the image argument to the chosen type
for example: BufferedImage newImage= ImageUtilities.convertType(oldImage, BufferedImage.TYPE_3BYTE_BGR);
11/28/2013 WARNING-it remains to be seen how well this method will work for various type conversions
------------------------------*/
public static BufferedImage convertType (BufferedImage image,int newType){
if (image.getType() == newType){
return (image);
}else {
int w= image.getWidth();
int h= image.getHeight ();
BufferedImage modifiedImage = new BufferedImage( w,h,newType);
Graphics2D g = ( Graphics2D)modifiedImage.getGraphics();
g.drawImage( image, null, 0,0);
g.dispose();
return (modifiedImage);
}
}
Run Code Online (Sandbox Code Playgroud)
我从一个TYPE_4BYTE_ABGR名为"result" 的BufferedImage开始,然后:
result= convertType (result, BufferedImage.TYPE_BYTE_GRAY);//transparency is lost
result=convertType (result, BufferedImage.TYPE_INT_ARGB);//pixels will now support transparency
Run Code Online (Sandbox Code Playgroud)
对于原始图像中的彩色不透明像素,上述序列工作正常:例如,(32,51,81,255) - >(49,49,49,255)
但是,原始图像中的透明像素变为不透明:例如,(0,0,0,0) - >(0,0,0,255)
我理解发生了什么,如果我可以使用用于转换为灰度的Java算法,我可以解决这个问题.我已经下载了源代码并且四处寻找,但是无法找到算法.如果有人可以,我将非常感激:
你考虑过使用ColorConvertOp过滤器吗?
例如...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAlphaGrayScale {
public static void main(String[] args) {
new TestAlphaGrayScale();
}
public TestAlphaGrayScale() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage gray;
public TestPane() {
setBackground(Color.RED);
try {
master = ImageIO.read(new File("C:\\hold\\thumbnails\\Miho_Alpha.png"));
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);
setLayout(new GridLayout(1, 2));
add(new JLabel(new ImageIcon(master)));
add(new JLabel(new ImageIcon(gray)));
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我写这篇文章的时候,你得到了你的"怎么做"的答案,所以我只想对正在发生的事情以及你没有成功的原因加上一些解释.
您可能知道何时以ARGB(TYPE_INT_ARGB)表示图像透明度存储在第四个字节(A-Alpha通道)中.A = 0透明,A = 255不透明.
TYPE_BYTE_GRAY表示只是具有亮度分量的单个字节,在该表示中没有Alpha通道.将图像绘制到新缓冲区时,亮度将从RGB通道计算并存储.Alpha通道被删除.
实现您正在做的最简单的方法是自己计算亮度并将其存储在新ARGB图像的三个RGB通道中,将Alpha通道从原始图像复制到现在的灰度图像.
亮度是YCbCr图像表示中的Y分量.维基百科有关于如何计算它的详细信息(它只是R,G和B的加权平均值).
这种方法的问题是你失去了硬件加速.幸运的是,Java提供了转换颜色空间的类,这些颜色空间(取决于平台)应该是硬件加速的,并且更加健壮,因为它们不依赖于输入图像是ARGB.@MadProgrammer的详细答案显示了如何做到这一点.
重要提示ColorConvertOp:如果您想要正确的灰度转换,您可能应该使用@MadProgrammers解决方案( )。我对此投了赞成票。:-)
这个答案更加完整:
如果您确实想要BufferedImage具有CS_GRAY颜色空间和透明度的 ,则可以创建自定义(将导致TYPE_CUSTOM)BufferedImage。下面的代码将生成类似“TYPE_2BYTE_GRAY_ALPHA”类型的内容(每个样本 8 位,每个像素 2 个样本)。TYPE_INT_ARGB它将使用或图像的一半内存TYPE_4BYTE_ABGR,但很可能会失去硬件加速,并且可能会错过 Java2D 绘图管道中的一些优化循环(也就是说,我的测试显示在 OS X 上完全可以接受的性能)。
/** Color Model usesd for raw GRAY + ALPHA */
private static final ColorModel CM_GRAY_ALPHA =
new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY),
true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE
);
public static BufferedImage create2ByteGrayAlphaImage(int width, int height) {
int[] bandOffsets = new int[] {1, 0}; // gray + alpha
int bands = bandOffsets.length; // 2, that is
// Init data buffer of type byte
DataBuffer buffer = new DataBufferByte(width * height * bands);
// Wrap the data buffer in a raster
WritableRaster raster =
Raster.createInterleavedRaster(buffer, width, height,
width * bands, bands, bandOffsets, new Point(0, 0));
// Create a custom BufferedImage with the raster and a suitable color model
return new BufferedImage(CM_GRAY_ALPHA, raster, false, null);
}
Run Code Online (Sandbox Code Playgroud)