需要更快的方法来获取缓冲图像中每个像素的RGB值

9

如何快速获取BufferedImage每个像素的RGB值?

目前我正在使用下面的代码通过两个for循环来获取RGB值,但是对于我的图像嵌套循环运行了总共479999次,获取这些值花费的时间太长了。如果我使用16位图像,这个数字将更高!

我需要一种更快捷的方式来获取像素值。

以下是我目前正在尝试的代码:

BufferedImage bi=ImageIO.read(new File("C:\\images\\Sunset.jpg"));

int countloop=0;  

for (int x = 0; x <bi.getWidth(); x++) {
    for (int y = 0; y < bi.getHeight(); y++) {
        Color c = new Color(bi.getRGB(x, y));
        System.out.println("red=="+c.getRed()+" green=="+c.getGreen()+"    blue=="+c.getBlue()+"  countloop="+countloop++);                                                                                                                                                  
    }
}

2
输出会减慢整个循环速度。尝试不使用它。 - Matthias Bruns
2
没有println可能会快很多。 - Romain Hippeau
请查看此处:https://dev59.com/IFLTa4cB1Zd3GeqPZ2K2 - dash1e
2
去掉 System.out.println() 调用将使其速度显著提高。你可能可以在循环外定义 c,甚至避免实例化 Color,但这可能并不必要。 - beerbajay
@Thomas,它上升是因为16位图像的高度和宽度更大,因为它包含2^16个像素...... - Jony
显示剩余3条评论
5个回答

15

我不确定这是否有帮助,而且我还没有测试过,但你可以通过以下方式获取RGB值:

BufferedImage bi=ImageIO.read(new File("C:\\images\\Sunset.jpg"));
int[] pixel;

for (int y = 0; y < bi.getHeight(); y++) {
    for (int x = 0; x < bi.getWidth(); x++) {
        pixel = bi.getRaster().getPixel(x, y, new int[3]);
        System.out.println(pixel[0] + " - " + pixel[1] + " - " + pixel[2] + " - " + (bi.getWidth() * y + x));
    }
}

您可以看到在循环内部不需要初始化一个新的Color。我也按照onemasse的建议反转了宽度/高度循环,以从我已有的数据中检索计数器。


7
通过从一堆单独的getRGB更改为一个大的getRGB来将整个图像复制到数组中,执行时间从33,000毫秒降至3,200毫秒,而创建数组的时间仅为31毫秒。毫无疑问,将整个读入数组并直接对数组进行索引比许多单独的读取要快得多。
性能差异似乎与在类结尾处使用断点语句有关。虽然断点在循环外部,但类内的每行代码似乎都会被测试以进行断点。更改为单独获取不会提高速度。
由于代码仍然是正确的,因此答案的其余部分仍然可能有用。
旧的读取语句
colorRed=new Color(bi.getRGB(x,y)).getRed();

阅读语句将位图复制到数组中

int[] rgbData = bi.getRGB(0,0, bi.getWidth(), bi.getHeight(), 
                null, 0,bi.getWidth());        

将getRGB放入数组中,将所有三种颜色值放入单个数组元素中,因此必须通过旋转和"and"提取每个颜色。y坐标必须乘以图像的宽度。

从数组中读取单个颜色的代码

colorRed=(rgbData[(y*bi.getWidth())+x] >> 16) & 0xFF; 

colorGreen=(rgbData[(y*bi.getWidth())+x] >> 8) & 0xFF; 

colorBlue=(rgbData[(y*bi.getWidth())+x]) & 0xFF; 

2

你尝试过BufferedImage.getRGB(int, int ,int ,int, int[] , int , int)吗?

类似这样:

int[] rgb = bi.getRGB(0,0, bi.getWidth(), bi.getHeight(), new int[bi.getWidth() * bi.getHeight(), bi.getWidth()])

我没有尝试过,所以不确定是否更快。

编辑 看了代码后,可能不会更快,但还是值得一试。


2
你应该在外循环中循环行,在内循环中循环列。这样你就可以避免缓存未命中。

0

我在这里找到了一个解决方案https://alvinalexander.com/blog/post/java/getting-rgb-values-for-each-pixel-in-image-using-java-bufferedi

BufferedImage bi = ImageIO.read(new File("C:\\images\\Sunset.jpg"));

for (int x = 0; x < bi.getWidth(); x++) {
    for (int y = 0; y < bi.getHeight(); y++) {
        int pixel = bi.getRGB(x, y);
        int red = (pixel >> 16) & 0xff;
        int green = (pixel >> 8) & 0xff;
        int blue = (pixel) & 0xff;
        System.out.println("red: " + red + ", green: " + green + ", blue: " + blue);                                                                                                                                                  
    }
}

这是一个更快的算法吗? - Gerard Rozsavolgyi

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