如何改变图像的亮度

11

我的问题:我想改变一个资源图片的亮度并作为三个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方法的意义/作用,并因此知道应该给亮度变量提供哪些值。

非常感谢任何帮助!谢谢!


1
请参考以下类似问题:https://dev59.com/VXA75IYBdhLWcg3wK10p。 - David Kroukamp
4个回答

5

文件中写道:

重缩放操作的伪代码如下:

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
谢谢您的解释。不幸的是,当我将亮度更改为1.0f并将偏移量更改为0时,它仍然是看不见的。如果我将我的“filter”调用更改为“filter(bufferedImage, bufferedImage)”而不是“filter(bufferedImage, null)”,它会变成一个有趣的蓝色。有什么想法吗? - kentcdodds
这些是RGB还是灰度图像?这很重要。请查看此链接:http://www.exampledepot.com/egs/java.awt.image/Bright.html - dario_ramos
你的代码就像例子一样,应该没问题。在显示图标之前是否进行了其他操作?尝试在调用“filter”后立即将其保存到磁盘并查看保存的图像。 - dario_ramos
1
如果 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); 如何? - aterai
@dario_ramos,我刚试着将它保存到磁盘上。它是不可见的...太奇怪了! - kentcdodds
虽然我还没有在我的机器上完全实现,但我认为我的程序肯定还有其他问题,所以我会说这是正确的答案。感谢您的帮助。 - kentcdodds

4

我建议用半透明的黑色直接覆盖在图像上。

假设您想直接在图片上书写:

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
@kentcdodds 没错 - 我原以为你说“我也想保留透明度。”的意思是它仍然应该是透明的(但更暗)。所以如果它只是应该是透明的,那就不同了。 - Nick Rippe
是的,但是你提供的SSCCE非常好用,帮助我理解了正在发生的事情。但愿它也能适用于我的用例! - kentcdodds
@kentcdodds 添加了更新,解决了透明度问题。也许把它作为一个单独的答案会更好 - 也许我会删除我的第一个答案(请告诉我你的想法)。 - Nick Rippe
如果百分比为0,这将会遇到一个异常,因为颜色将会被创建为带有256个alpha组件。亮度应该是(int) (256 - 256 * percentage) - FThompson

1

更多的学习示例:

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

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

  • RescaleTest 将图像的所有波段重新调整到零到二之间,没有偏移。

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

dstElement = (srcElement*scaleFactor) + offset

0

基本逻辑是获取每个像素的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);
    }
     }}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接