【问题标题】:How to change the brightness of an Image如何更改图像的亮度
【发布时间】:2012-10-10 10:53:06
【问题描述】:

我的问题:我希望能够更改资源图像的亮度并将其三个实例作为 ImageIcons。一个亮度为 50%(如此暗),另一个亮度为 75%(稍微亮一点),最后另一个亮度为 100%(与原始图像相同)。我也想保持透明度。

我尝试过的:我已经四处搜索,看起来最好的解决方案是使用RescaleOp,但我就是想不通。我不知道 scaleFactor 和 offset 是什么意思。这是我尝试过的代码。

public void initialize(String imageLocation, float regularBrightness, float focusedBrightness, float pressedBrightness, String borderTitle) throws IOException {
  BufferedImage bufferedImage = ImageIO.read(ButtonIcon.class.getResource(imageLocation));
  setRegularIcon(getAlteredImageIcon(bufferedImage, regularBrightness));
  setFocusedIcon(getAlteredImageIcon(bufferedImage, focusedBrightness));
  setPressedIcon(getAlteredImageIcon(bufferedImage, pressedBrightness));
  setTitle(borderTitle);
  init();
}

private ImageIcon getAlteredImageIcon(BufferedImage bufferedImage, float brightness) {
  RescaleOp rescaleOp = new RescaleOp(brightness, 0, null);
  return new ImageIcon(rescaleOp.filter(bufferedImage, null));
}

调用会是这样的:

seeATemplateButton.initialize("/resources/templateIcon-regular.png", 100f, 75f, 50f, "See A Template");
//I think my 100f, 75f, 50f variables need to change, but whenever I change them it behaves unexpectedly (changes colors and stuff).

该代码会发生什么: 图像显示为“不可见”,我知道它存在,因为它位于带有鼠标单击事件的 JLabel 上,并且效果很好。如果我只是跳过亮度变化部分并说setRegularIcon(new ImageIcon(Button.class.getResource(imageLocation)); 它工作得很好,但显然它并没有变暗。

我认为我需要什么:一些帮助理解 offsetscaleFactorfilter 方法的含义/作用,以及因此要为亮度变量提供什么数字。

任何帮助将不胜感激!谢谢!

【问题讨论】:

标签: java swing image-manipulation brightness imageicon


【解决方案1】:

文档说:

缩放操作的伪代码如下:

for each pixel from Source object {
    for each band/component of the pixel {
        dstElement = (srcElement*scaleFactor) + offset
    }
}

这只是每个像素的线性变换。该转换的参数是scaleFactoroffset。如果你想要 100% 的亮度,这个变换必须是一个身份,即dstElement = srcElement。设置 scaleFactor = 1offset = 0 就可以了。

现在假设您想使图像更暗,如您所说,亮度为 75%。这相当于将像素值乘以 0.75。你想要:dstElement = 0.75 * srcElement。所以设置 scaleFactor = 0.75offset = 0 应该可以解决问题。你的值的问题是它们从 0 到 100,你需要使用 0 到 1 之间的值。

【讨论】:

  • 感谢您的解释。不幸的是,当我将亮度更改为 1.0f 并将偏移量更改为 0 时,它仍然不可见。如果我将我的filter 调用更改为filter(bufferedImage, bufferedImage) 而不是filter(bufferedImage, null),这是一种有趣的蓝色。有什么想法吗?
  • 这些是 RGB 还是灰度图像?这是相关的。检查this link
  • 你的代码和例子一样,应该没问题。在显示之前是否对图标进行了其他操作?尝试在调用filter 后立即将其保存到磁盘并查看保存的图像。
  • 如果 bufferedImage.getType()==BufferedImage.TYPE_INT_ARGB 那么如何使用 new RescaleOp(new float[]{1.2f,1.2f,1.2f,1.0f},new float[] { 0f,0f,0f,0f},null);而不是 new RescaleOp(1.2f, 0f, null);
  • @dario_ramos,我只是尝试将其保存到磁盘。它是隐形的……太奇怪了!
【解决方案2】:

我建议只用半透明黑色覆盖图像。

假设你想直接在图片上写:

Graphics g = img.getGraphics();
float percentage = .5f; // 50% bright - change this (or set dynamically) as you feel fit
int brightness = (int)(256 - 256 * percentage);
g.setColor(new Color(0,0,0,brightness));
g.fillRect(0, 0, img.getWidth(), img.getHeight());

或者,如果您只是将图像用于显示目的,请使用 paintComponent 方法。这是一个 SSCCE:

import java.awt.*;
import java.awt.image.*;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;


public class ImageBrightener extends JPanel{

    BufferedImage img;
    float percentage = 0.5f;

    public Dimension getPreferredSize(){
        return new Dimension(img.getWidth(), img.getHeight());
    }

    public ImageBrightener(){
        try {
            img = ImageIO.read(new URL("http://media.giantbomb.com/uploads/0/1176/230441-thehoff_super.jpeg"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(img, 0, 0, this);
        int brightness = (int)(256 - 256 * percentage);
        g.setColor(new Color(0,0,0,brightness));
        g.fillRect(0, 0, getWidth(), getHeight());
    }

    public static void main(String[] args){
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new ImageBrightener());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

编辑

假设与上面的代码相同,您可以通过弄乱光栅化器来操作除 Alpha 之外的所有内容。这是一个示例(如果使用此示例,则绘制 shadedImage 而不是 img)。请注意,这不会捕获 RGB 值大于 256 且小于 0 的边缘情况。

        img = ImageIO.read(new URL("http://media.giantbomb.com/uploads/0/1176/230441-thehoff_super.jpeg"));
        shadedImage = new BufferedImage(img.getWidth(), img.getWidth(), BufferedImage.TYPE_INT_ARGB);
        shadedImage.getGraphics().drawImage(img, 0, 0, this);

        WritableRaster wr = shadedImage.getRaster();
        int[] pixel = new int[4];

        for(int i = 0; i < wr.getWidth(); i++){
            for(int j = 0; j < wr.getHeight(); j++){
                wr.getPixel(i, j, pixel);
                pixel[0] = (int) (pixel[0] * percentage);
                pixel[1] = (int) (pixel[1] * percentage);
                pixel[2] = (int) (pixel[2] * percentage);
                wr.setPixel(i, j, pixel);
            }
        }

【讨论】:

  • 如果图像具有透明度,这会影响背景吗?我想会的。不会吗?
  • @kentcdodds Touche - 当你说“我也想保持透明度”时,我假设。你的意思只是它应该仍然是透明的(但更暗)。因此,如果它应该只是透明的,那就不同了。
  • 是的,但是您的 SSCCE 工作得很好,帮助我了解发生了什么。希望它适用于我的用例!
  • @kentcdodds 添加了解决透明度问题的更新。作为单独的答案可能会更好 - 也许我会删除我的第一个答案(让我知道你的想法)。
  • 如果百分比为 0f,这将遇到异常,因为随后将使用 256 的 alpha 分量创建颜色。亮度应为 (int) (256 - 256 * percentage)
【解决方案3】:

还有几个例子供学习:

  • AlphaTest 仅在零和一之间重新调整图像的 alpha 透明度,没有偏移。巧合的是,它还将图像重新采样为四分之三的大小。

  • RescaleOpTest 使用固定比例且无偏移执行相同操作。

  • RescaleTest 在零到二之间缩放图像的所有波段,没有偏移。

API 中所述,比例和偏移分别作为线性函数的斜率和y-截距应用于每个波段。

dstElement = (srcElement*scaleFactor) + offset

【讨论】:

    【解决方案4】:

    基本逻辑是获取每个像素的RGB值,添加一些因子,再次将其设置为结果矩阵(缓冲图像)

        import java.io.*;
        import java.awt.Color;
        import javax.imageio.ImageIO;
        import java.io.*;
        import java.awt.image.BufferedImage;
    
    
    
            class psp{
    
        public static void main(String a[]){
        try{
    
        File input=new File("input.jpg");
        File output=new File("output1.jpg");
                BufferedImage picture1 = ImageIO.read(input);   // original
        BufferedImage picture2= new BufferedImage(picture1.getWidth(), picture1.getHeight(),BufferedImage.TYPE_INT_RGB);      
                int width  = picture1.getWidth();
                int height = picture1.getHeight();
    
        int factor=50;//chose it according to your need(keep it less than 100)
        for (int y = 0; y < height ; y++) {//loops for image matrix
        for (int x = 0; x < width ; x++) {
    
        Color c=new Color(picture1.getRGB(x,y));
    
        //adding factor to rgb values
    int r=c.getRed()+factor;
        int b=c.getBlue()+factor;
        int g=c.getGreen()+factor;
        if (r >= 256) {
         r = 255;
        } else if (r < 0) {
        r = 0;
        }
    
        if (g >= 256) {
        g = 255;
        } else if (g < 0) {
        g = 0;
        }
    
         if (b >= 256) {
        b = 255;
        } else if (b < 0) {
        b = 0;
         }
        picture2.setRGB(x, y,new Color(r,g,b).getRGB());
    
    
        }
        }
         ImageIO.write(picture2,"jpg",output);       
        }catch(Exception e){
        System.out.println(e);
        }
         }}
    

    【讨论】:

      猜你喜欢
      • 2020-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 2021-07-04
      • 1970-01-01
      相关资源
      最近更新 更多