How can I control the brightness of an Image?

我与影子孤独终老i 提交于 2019-12-24 12:29:29

问题


I have the following problem:

I want to create a method to control the brightness of an Image. I think I have to convert it to a BufferedImage before.
And if the Image has an alpha channel and I want to convert it with TYPE_INT_RGB the alpha pixels will be black. But it works fine with TYPE_INT_ARGB...
It doesn't work if the image doesn't have an alpha channel and I convert it with TYPE_INT_ARGB. Then not only the brightness changes, but also the color. When I make the image brighter it becomes more yellow an it becomes blue if I darken it.
Can I convert it in another way or is there a possibility to check if the Image has an alpha channel?

Here is my code:

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;
}

回答1:


Take a look in the code below.

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;

    }

}

It will read a image and create a matrix with new images with new brightnesses. Here is the result for my profile image.

EDIT:

Now it supports alpha too. In the previous code, the alpha component of the new pixel was fixed in 255. I changed to use the alpha component of the original pixel (pixel[3]).

EDIT 2:

Each pixel will have a brightness component that varies from 0 to 1. If this component extrapolates the value 1, the pixel will have a "strange" color. You want to have something that seems brighter than the original one, so, you will need to verify if the new brightness value extrapolates 1. The example above will do this. You will have an slider to control what is the maximum percentage that will be calculated to the new pixel brightness component. If this value passes the maximum value (1), the maximum value will be used. I hope that now it finally helps you :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;
        }

    }

}

Take a look in the image below.

I think now you will understand. If not, I will give up :D




回答2:


To check of the alpha channel in a BufferedImage, use 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;
}

You need to cast the Image passed in argument to BufferedImage to use the .getColorModel().hasAlpha() methods.



来源:https://stackoverflow.com/questions/46797579/how-can-i-control-the-brightness-of-an-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!