【问题标题】:How can I control the brightness of an Image?如何控制图像的亮度?
【发布时间】:2018-03-29 14:01:01
【问题描述】:

我有以下问题:

我想创建一种方法来控制图像的亮度。我想我必须先将其转换为 BufferedImage。
如果图像有 alpha 通道并且我想用TYPE_INT_RGB 转换它,则 alpha 像素将为黑色。但它适用于 TYPE_INT_ARGB...
如果图像没有 alpha 通道,它就不起作用,我用TYPE_INT_ARGB 转换它。然后不仅亮度变化,而且颜色也变化。当我使图像变亮时,它会变得更黄,如果我变暗,它会变蓝。
我可以用其他方式转换它还是有可能检查图像是否有 alpha 通道?

这是我的代码:

public static Image brightnessControl(Image image, float brightness) {

    //First I convert the Image to a BufferedImage
    BufferedImage bi = new BufferedImage
            (image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    Graphics bg = bi.getGraphics();
    bg.drawImage(image, 0, 0, null);
    bg.dispose();

    //here I brighten/darken the BufferedImage
    RescaleOp rescaleOp = new RescaleOp(brightness, 0, null);
    rescaleOp.filter(bi, bi);

    //I change the BufferedImage back to the Image again!
    image = bi;

    //Last but not least I return the Image...
    return image;
}

【问题讨论】:

  • 你可以试试image = rescaleOp.filter(bi, null); 代替rescaleOp.filter(bi, bi);(见Javadoc)吗?
  • @howlger 如果我这样做,我无法使用 Alpha 通道使图像变亮。但它解决了奇怪的颜色问题!

标签: java eclipse image bufferedimage alpha


【解决方案1】:

看看下面的代码。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test {

    public static void main( String[] args ) throws IOException {

        Image img = ImageIO.read( new File( "image.jpeg" ) );

        new JFrame(){
            {
                setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                setSize( 800, 600 );
                setLocationRelativeTo( null );
                add( new JPanel(){
                    @Override
                    protected void paintComponent( Graphics g ) {

                        super.paintComponent( g );

                        int imgWidth = img.getWidth( null );
                        int imgHeight = img.getHeight( null );
                        int lines = 4;
                        int columns = 6;
                        int count = 1;

                        for ( int i = 0; i < lines; i++ ) {
                            for ( int j = 0; j < columns; j++ ) {
                                g.drawImage( newBrightness( img, 1f/(lines*columns)*count ), imgWidth * j, imgHeight * i, null );
                                count++;
                            }
                        }
                    }
                });
            }
        }.setVisible( true );

    }

    public static Image newBrightness( Image source, float brightnessPercentage ) {

        BufferedImage bi = new BufferedImage( 
                source.getWidth( null ), 
                source.getHeight( null ), 
                BufferedImage.TYPE_INT_ARGB );

        int[] pixel = { 0, 0, 0, 0 };
        float[] hsbvals = { 0, 0, 0 };

        bi.getGraphics().drawImage( source, 0, 0, null );

        // recalculare every pixel, changing the brightness
        for ( int i = 0; i < bi.getHeight(); i++ ) {
            for ( int j = 0; j < bi.getWidth(); j++ ) {

                // get the pixel data
                bi.getRaster().getPixel( j, i, pixel );

                // converts its data to hsb to change brightness
                Color.RGBtoHSB( pixel[0], pixel[1], pixel[2], hsbvals );

                // create a new color with the changed brightness
                Color c = new Color( Color.HSBtoRGB( hsbvals[0], hsbvals[1], hsbvals[2] * brightnessPercentage ) );

                // set the new pixel
                bi.getRaster().setPixel( j, i, new int[]{ c.getRed(), c.getGreen(), c.getBlue(), pixel[3] } );

            }

        }

        return bi;

    }

}

它将读取图像并创建一个矩阵,其中包含具有新亮度的新图像。这是我的个人资料图片的结果。

编辑:

现在它也支持 alpha。在之前的代码中,新像素的 alpha 分量固定为 255。我改为使用原始像素的 alpha 分量(pixel[3])。

编辑 2:

每个像素都有一个从 0 到 1 变化的亮度分量。如果该分量外推值 1,则该像素将具有“奇怪”的颜色。您想要看起来比原来更亮的东西,因此,您需要验证新的亮度值是否外推为 1。上面的示例将执行此操作。您将有一个滑块来控制将计算到新像素亮度分量的最大百分比。如果此值超过最大值 (1),则将使用最大值。我希望现在它终于可以帮助你了:D

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ChangeImageBrightnessExample2 {

    public static void main( String[] args ) throws IOException {
        new ChangeImageBrightnessExample2().createUI();
    }

    public void createUI() throws IOException {

        Image img = ImageIO.read( new File( "image.jpeg" ) );

        new JFrame(){
            {
                setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                setSize( 800, 600 );
                setLocationRelativeTo( null );

                CustomPanel panel = new CustomPanel();
                panel.setImage( img );

                JSlider slider = new JSlider( 0, 400, 100 );
                slider.setMinorTickSpacing( 10);
                slider.setMajorTickSpacing( 50 );
                slider.setPaintLabels( true );
                slider.setPaintTicks( true );
                slider.setSnapToTicks( true );
                slider.addChangeListener( new ChangeListener() {
                    @Override
                    public void stateChanged( ChangeEvent evt ) {
                        JSlider s = ((JSlider) evt.getSource());
                        if ( s.getValueIsAdjusting() ) {
                            panel.setMaximumBrightnessPercentage( s.getValue()/100f );
                            panel.repaint();
                        }

                    }
                });

                add( panel, BorderLayout.CENTER );
                add( slider, BorderLayout.SOUTH );

            }
        }.setVisible( true );

    }

    public static Image newBrightness( Image source, float brightnessPercentage ) {

        BufferedImage bi = new BufferedImage( 
                source.getWidth( null ), 
                source.getHeight( null ), 
                BufferedImage.TYPE_INT_ARGB );

        int[] pixel = { 0, 0, 0, 0 };
        float[] hsbvals = { 0, 0, 0 };

        bi.getGraphics().drawImage( source, 0, 0, null );

        // recalculare every pixel, changing the brightness
        for ( int i = 0; i < bi.getHeight(); i++ ) {
            for ( int j = 0; j < bi.getWidth(); j++ ) {

                // get the pixel data
                bi.getRaster().getPixel( j, i, pixel );

                // converts its data to hsb to change brightness
                Color.RGBtoHSB( pixel[0], pixel[1], pixel[2], hsbvals );

                // calculates the brightness component.
                float newBrightness = hsbvals[2] * brightnessPercentage;
                if ( newBrightness > 1f ) {
                    newBrightness = 1f;
                }

                // create a new color with the new brightness
                Color c = new Color( Color.HSBtoRGB( hsbvals[0], hsbvals[1], newBrightness ) );

                // set the new pixel
                bi.getRaster().setPixel( j, i, new int[]{ c.getRed(), c.getGreen(), c.getBlue(), pixel[3] } );

            }

        }

        return bi;

    }

    private class CustomPanel extends JPanel {

        private float maximumBrightnessPercentage = 1f;
        private Image image;

        @Override
        protected void paintComponent( Graphics g ) {

            super.paintComponent( g );

            int imgWidth = image.getWidth( null );
            int imgHeight = image.getHeight( null );
            int lines = 4;
            int columns = 6;
            int count = 1;

            for ( int i = 0; i < lines; i++ ) {
                for ( int j = 0; j < columns; j++ ) {
                    float newBrightness = maximumBrightnessPercentage/(lines*columns)*count;
                    g.drawImage( newBrightness( image, newBrightness ), imgWidth * j, imgHeight * i, null );
                    g.drawString( String.format( "%.2f%%", newBrightness*100 ), imgWidth * j, imgHeight * i + 10 );
                    count++;
                }
            }

        }

        public void setMaximumBrightnessPercentage( float maximumBrightnessPercentage ) {
            this.maximumBrightnessPercentage = maximumBrightnessPercentage;
        }

        public void setImage( Image image ) {
            this.image = image;
        }

    }

}

请看下面的图片。

我想现在你会明白的。如果没有,我会放弃:D

【讨论】:

  • 谢谢!这就是我要找的!
  • 我用 PNG 文件试了一下,不知为何 alpha 通道变黑了……为什么?
  • @Andy 现在支持 alpha。
  • @Andy 您需要了解我的代码根据传递给方法的百分比(0 到 1)更改像素的当前亮度。您需要根据需要更改亮度的计算方式。这将需要在这一行中完成:Color c = new Color( Color.HSBtoRGB( hsbvals[0], hsbvals[1], hsbvals[2] * brightnessPercentage ) );,特别是在Color.HSBtoRGB 方法的第三个参数中。
  • @Andy 他们变得很奇怪,因为您在设置亮度时没有考虑原始像素亮度。你想让图像比现在更亮吗?
【解决方案2】:

要检查 BufferedImage 中的 Alpha 通道,请使用 BufferedImage.getColorModel().hasAlpha();

public static Image brightnessControl(Image image, float brightness) {
    // First I convert the Image to a BufferedImage
    BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    Graphics bg = bi.getGraphics();

    if (bi.getColorModel().hasAlpha()) { // This will output true because you have just applied TYPE_INT_ARGB!
        System.out.println("Image has got an alpha channel");
    }

    bg.drawImage(image, 0, 0, null);
    bg.dispose();

    // here I brighten/darken the BufferedImage
    RescaleOp rescaleOp = new RescaleOp(brightness, 0, null);
    rescaleOp.filter(bi, bi);

    // I change the BufferedImage back to the Image again!
    image = bi;

    // Last but not least I return the Image...
    return bi;
}

您需要将传入参数的Image 强制转换为BufferedImage 才能使用.getColorModel().hasAlpha() 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    • 2020-04-04
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多