有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java试图设置颜色变化的alpha值

我创建此代码是为了从图像中删除所有半透明颜色并使其完全不透明。由于某种原因,图像的颜色发生了剧烈的变化,即使我只是改变了alpha。附加的是代码和图像发生了什么的例子

之前:

https://i.stack.imgur.com/PLU1v.png

之后:

https://i.stack.imgur.com/8SObz.png

public class Main {
    
    public static void main(String args[]) throws IOException
    {
        
        File file = new File("karambitlore.png");
        FileInputStream fis = new FileInputStream(file);
        BufferedImage image = ImageIO.read(fis);
        
        image = convertToType(image, BufferedImage.TYPE_INT_ARGB);
        
        BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        
        for (int width = 0; width < image.getWidth(); width++)
        {
            for (int height = 0; height < image.getHeight(); height++)
            {

                int rgb = image.getRGB(width, height);

                boolean transparent = (rgb & 0xFF000000) == 0x0;
                boolean opaque = (rgb & 0xFF000000) == 0xFF000000;
                
                if (!transparent && !opaque)
                {
                    
                    rgb = rgb | 0xFF000000;
                    
                    image2.setRGB(width, height, rgb);
                    
                } else
                {
                    image2.setRGB(width, height, image.getRGB(width, height));

                }
                
            }
        }
       
        fis.close();
        ImageIO.write(image2, "png", file);
        
        System.out.println(image.getType());
        
    }
    
    public static BufferedImage convertToType(BufferedImage image, int type) {
        BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
        Graphics2D graphics = newImage.createGraphics();
        graphics.drawImage(image, 0, 0, null);
        graphics.dispose();
        return newImage;
            
    }

}

共 (1) 个答案

  1. # 1 楼答案

    输入图像的主要问题是,它在完全透明的像素周围有一个近乎透明的“光晕”,有点像“抖动”的透明度。当您将这些像素设置为完全不透明时,它们a)在您不需要的位置创建不透明像素,b)使这些像素过于饱和,因为像素没有与alpha进行预乘(如果您对alpha合成/混合感兴趣,可以在谷歌上搜索“预乘alpha”)。请注意,像素并不是真的“改变颜色”,只是它们通常对最终结果贡献不大,因为它们几乎是完全透明的

    不管背景颜色如何,简单的解决方法是使用一个阈值来决定像素是否应该是透明的

    如果知道背景色(纯色或某种“平均色”),可以使用alpha值将像素颜色与背景色混合。这将创建更平滑的边,但仅限于此背景。在这种情况下,可以使用较低的阈值

    以下是代码的修改版本,可为您的输入生成更好的结果:

    public static void main(String args[]) throws IOException {
        File file = new File(args[0]);
    
        BufferedImage image = convertToType(ImageIO.read(file), BufferedImage.TYPE_INT_ARGB);
    
        Color bg = Color.ORANGE; // Change to the color of your background, if you want to blend
    
        int bgR = bg.getRed();
        int bgG = bg.getGreen();
        int bgB = bg.getBlue();
    
    
        for (int width = 0; width < image.getWidth(); width++) {
            for (int height = 0; height < image.getHeight(); height++) {
                int rgb = image.getRGB(width, height);
    
                int opaqueness = (rgb >>> 24) & 0xFF;
    
                if (opaqueness > 100) { // The threshold 100 works fine for your current input, tune to suit other needs
                    // Fully opaque
                    image.setRGB(width, height, rgb | 0xFF000000);
    
                    // Or if you prefer blending the background:
    /*
                    // Multiply alpha
                    int r = ((rgb >> 16 & 0xFF) * opaqueness) + (bgR * (0xFF - opaqueness)) >> 8;
                    int g = ((rgb >>  8 & 0xFF) * opaqueness) + (bgG * (0xFF - opaqueness)) >> 8;
                    int b = ((rgb       & 0xFF) * opaqueness) + (bgB * (0xFF - opaqueness)) >> 8;
    
                    image.setRGB(width, height, r << 16 | g << 8 | b | 0xFF000000);
    */
                } else {
                    // Fully transparent
                    image.setRGB(width, height, rgb & 0xFFFFFF);
                }
            }
        }
    
        ImageIO.write(image, "png", new File(file.getParentFile(), file.getName() + "_copy_bg_mult.png"));
    }
    
    public static BufferedImage convertToType(BufferedImage image, int type) {
        BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
        Graphics2D graphics = newImage.createGraphics();
        graphics.setComposite(AlphaComposite.Src);
        graphics.drawImage(image, 0, 0, null);
        graphics.dispose();
        return newImage;
    
    }
    

    按原样编写的代码将创建这样的图像,它的边缘将略微参差不齐,但“光环”将被删除:

    enter image description here

    或者,如果您注释掉“完全不透明”版本,并在“倍增alpha”部分进行注释,您可以得到这样的图像(显然,只有在黄色背景下才好看):

    enter image description here