使用BufferedImages获取图像每个像素的颜色

27

我正在尝试获取图像每个像素的每种颜色。 我的想法是:

int[] pixels;
BufferedImage image;

image = ImageIO.read(this.getClass.getResources("image.png");
int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();

这是正确的吗?我甚至无法检查“像素”数组包含什么,因为我得到以下错误:

java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferInt

我只想把每个像素的颜色存在数组里,如何实现?

6个回答

44
import java.io.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

public class GetPixelColor {
    public static void main(String args[]) throws IOException {
        File file = new File("your_file.jpg");
        BufferedImage image = ImageIO.read(file);
        // Getting pixel color by position x and y 
        int clr = image.getRGB(x, y);
        int red =   (clr & 0x00ff0000) >> 16;
        int green = (clr & 0x0000ff00) >> 8;
        int blue =   clr & 0x000000ff;
        System.out.println("Red Color value = " + red);
        System.out.println("Green Color value = " + green);
        System.out.println("Blue Color value = " + blue);
    }
}

当然,你必须为所有像素添加一个for循环。

1
抱歉,我对此完全不了解: 我以前见过这个,但是" >> 16"或者" >> 8"是什么意思呢?你能解释一下这行代码吗?int red = (clr & 0x00ff0000) >> 16;谢谢! - user2410644
11
像素/颜色以打包的“int”形式返回,这意味着RGBA值形成了“int”的单独字节。基本上,BlackShadow使用位移来提取单个像素。您可以使用"Color color = new Color(clr, true)"执行相同操作,并使用“Color” API提取组件,这样做更容易和更安全 ;) - MadProgrammer
谢谢大家,我经常看到人们使用这些移位方法编码,但我从来没有真正理解他们在做什么。 - user2410644
2
8:向右移动8个位置,假设red = 00000000 00001111,red>>16表示11111111 00000000,(00001111消失了)
- Black Shadow
@SriP 如果你还在犹豫不决,你需要创建两个嵌套的for循环(一个用于x轴,一个用于y轴),其中x从0到图像的宽度,y从0到图像的高度,然后将其插入Black Shadow的代码中作为x和y的值。 - retrovius
这些循环的一个例子是for (int i = 0; i < ss.getHeight(); i++) { for (int j = 0; j < ss.getWidth(); j++) { int clr = ss.getRGB(i, j); int red = (clr & 0x00ff0000) >> 16; int green = (clr & 0x0000ff00) >> 8; int blue = clr & 0x000000ff; } }``` - AwesomeDude3247

7
问题在于(第一个答案链接中也有这个问题),使用ImageIO读取缓冲图像后,你很少知道它的确切类型。它可能包含DataBufferByte或DataBufferInt。在某些情况下,您可以通过BufferedImage#getType()推断出它的类型,但在最坏的情况下,它的类型是TYPE_CUSTOM,那么您只能退回到一些instanceof测试。
然而,您可以将图像转换为保证具有ARGB值的DataBufferInt BufferedImage,例如:
public static BufferedImage convertToARGB(BufferedImage image)
{
    BufferedImage newImage = new BufferedImage(
        image.getWidth(), image.getHeight(),
        BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = newImage.createGraphics();
    g.drawImage(image, 0, 0, null);
    g.dispose();
    return newImage;
}

否则,您可以调用image.getRGB(x,y),它可以在需要时执行所需的转换。
顺便提一下:请注意,获取BufferedImage的数据缓冲区可能会降低绘画性能,因为图像不再被“管理”并在内部保留VRAM。

5
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedImage bufferedImage = ImageIO.read(new File("norris.jpg"));
        int height = bufferedImage.getHeight(), width = bufferedImage.getWidth();
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int RGBA = bufferedImage.getRGB(x, y);
                int alpha = (RGBA >> 24) & 255;
                int red = (RGBA >> 16) & 255;
                int green = (RGBA >> 8) & 255;
                int blue = RGBA & 255;
            }
        }
    }
}

假设缓冲图像表示一个包含8位RGBA颜色分量的整数像素的图像,我在维基百科上搜索“RGBA color space”并找到以下内容:
在字节顺序方案中,“RGBA”被理解为一个字节R,后跟一个字节G,后跟一个字节B,最后跟一个字节A。这个方案通常用于描述文件格式或网络协议,两者都是面向字节的。
通过简单的按位和移位,您可以获得每种颜色和像素的alpha值。
另一个RGBA的排序方案也非常有趣:
在字的顺序方案中,“RGBA”被理解为一个完整的32位词,其中R比G更重要,G比B更重要,B比A更重要。该方案可用于描述特定系统上的内存布局。其含义取决于系统的大小端。

2
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImageUtil {

    public static Color[][] loadPixelsFromImage(File file) throws IOException {

        BufferedImage image = ImageIO.read(file);
        Color[][] colors = new Color[image.getWidth()][image.getHeight()];

        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                colors[x][y] = new Color(image.getRGB(x, y));
            }
        }

        return colors;
    }

    public static void main(String[] args) throws IOException {
        Color[][] colors = loadPixelsFromImage(new File("image.png"));
        System.out.println("Color[0][0] = " + colors[0][0]);
    }
}

2

会尝试一下。但是这个数组包含什么?十六进制颜色?ARGB颜色? - user2410644
我更喜欢使用getRGB(),它非常有用,你可以试试。getRGB(x,y)会返回(x,y)位置像素的颜色,如果你想要,我可以发布一个相关代码。 - Black Shadow
我在一张红色图片上尝试了这个,输出的整数是:-60160。这个数字代表什么意思?它是一个RGB颜色吗? - user2410644

1
我知道这个问题已经有了答案,但是给出的答案有点复杂,需要改进。 简单的想法就是遍历图像中的每个(x,y)像素,并获取该像素的颜色。
BufferedImage image = MyImageLoader.getSomeImage();
for ( int x = 0; x < image.getWidth(); x++ ) {
    for( int y = 0; y < image.getHeight(); y++ ) {
        Color pixel = new Color( image.getRGB( x, y ) );
        // Do something with pixel color here :)
    }
}

你可以将此方法放入一个类中,并实现Java的Iterable API。

class IterableImage implements Iterable<Color> {

    private BufferedImage image;

    public IterableImage( BufferedImage image ) {
        this.image = image;
    }

    @Override
    public Iterator<Color> iterator() {
        return new Itr();
    }

    private final class Itr implements Iterator<Color> {

        private int x = 0, y = 0;

        @Override
        public boolean hasNext() {
            return x < image.getWidth && y < image.getHeight();
        }

        @Override
        public Color next() {
            x += 1;
            if ( x >= image.getWidth() ) {
                x = 0;
                y += 1;
            }
            return new Color( image.getRGB( x, y ) );
        }

    }

}

使用方式可能如下所示。
BufferedImage image = MyImageLoader.getSomeImage();
for ( Color color : new IterableImage( image ) ) {
    // Do something with color here :)
}

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