I'm looking for a faster way to extract histogram data from an image. I'm currently using this piece of code that needs about 1200ms for a 6mpx JPEG image:
我正在寻找一种更快的方法从图像中提取直方图数据。我目前正在使用的这段代码需要1200ms来处理6mpx JPEG图像:
ImageReader imageReader = (ImageReader) iter.next();
imageReader.setInput(is);
BufferedImage image = imageReader.read(0);
int height = image.getHeight();
int width = image.getWidth();
Raster raster = image.getRaster();
int[][] bins = new int[3][256];
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
bins[0][raster.getSample(i, j, 0)]++;
bins[1][raster.getSample(i, j, 1)]++;
bins[2][raster.getSample(i, j, 2)]++;
}
Do you have any suggestions?
你有什么建议吗?
2 个解决方案
#1
6
You're doing a lot of getSamples method calls and they're in turn doing calls and calls etc.
你做了很多getSamples方法调用,它们反过来又做调用和调用等等。
I work often with pictures and the typical trick to gain speed is to manipulate directly the underlying int[] (in this case your BufferedImage must be backed by an int[]).
我经常使用图片,获得速度的典型技巧是直接操作底层int[](在这种情况下,您的BufferedImage必须由int[]支持)。
The difference between accessing the int[] and doing, say, a getRGB can be gigantic. When I write gigantic, I mean by as much as two orders of magnitude (try doing a getRGB on OS X 10.4 vs int[x] and you'll see the perf gain).
访问int[]和执行getRGB之间的区别可能是巨大的。当我写巨量的时候,我的意思是有两个数量级(试着在OS X 10.4 vs int[X]上做一个getRGB,你会看到perf增益)。
Also, there's no call three times getSamples. I'd simply retrieve one int corresponding to your ARGB pixel and then bitshift to get the RGB bands (you're doing one histogram per R, G and B component right?).
另外,没有三次调用getSamples。我只需要检索一个与ARGB像素对应的整数,然后进行位移,以获得RGB波段(您正在对每个R、G和B分量做一个直方图,对吗?)
You can gain access to the pixels array by doing something like this:
您可以通过以下操作获得对像素数组的访问:
final int[] a = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
Also you can do what you want to do with a single loop, looping over all the pixels.
你也可以用一个循环来做你想做的事情,循环遍历所有的像素。
Instead of:
而不是:
for ( int x = 0; x < width; x++ ) {
for ( int y = 0; y < height; y++ ) {
....
You can do:
你能做什么:
for ( int p = 0; p < width*height; p++ ) {
Now if you want to get into weirder optimizations, not as likely to prove effective you could:
现在,如果你想要进行更奇怪的优化,你不太可能证明你是有效的:
-
use loop unrolling (iterating over 6 million pixels is one of the rare case where it may help)
使用循环展开(迭代超过600万像素是一种很少见的情况)
-
invert the loop: for ( p = width*height - 1; p >= 0; p--)
反转循环:for (p = width*height - 1;p > = 0;p——)
#2
1
You can use getSamples(int x, int y, int w, int h, int b, double[] dArray) method It's possible that this method have internal optimisations. Also, you can try to swap width and height.
您可以使用getSamples(int x, int, int, int, int, b, double[] dArray)方法,这种方法可能有内部优化。此外,您可以尝试交换宽度和高度。
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
}
}
And
和
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
}
}
Between this two variants performance difference will be huge. This is influence of the cpu cache
在这两种变体之间,性能差异将是巨大的。这是cpu缓存的影响。
#1
6
You're doing a lot of getSamples method calls and they're in turn doing calls and calls etc.
你做了很多getSamples方法调用,它们反过来又做调用和调用等等。
I work often with pictures and the typical trick to gain speed is to manipulate directly the underlying int[] (in this case your BufferedImage must be backed by an int[]).
我经常使用图片,获得速度的典型技巧是直接操作底层int[](在这种情况下,您的BufferedImage必须由int[]支持)。
The difference between accessing the int[] and doing, say, a getRGB can be gigantic. When I write gigantic, I mean by as much as two orders of magnitude (try doing a getRGB on OS X 10.4 vs int[x] and you'll see the perf gain).
访问int[]和执行getRGB之间的区别可能是巨大的。当我写巨量的时候,我的意思是有两个数量级(试着在OS X 10.4 vs int[X]上做一个getRGB,你会看到perf增益)。
Also, there's no call three times getSamples. I'd simply retrieve one int corresponding to your ARGB pixel and then bitshift to get the RGB bands (you're doing one histogram per R, G and B component right?).
另外,没有三次调用getSamples。我只需要检索一个与ARGB像素对应的整数,然后进行位移,以获得RGB波段(您正在对每个R、G和B分量做一个直方图,对吗?)
You can gain access to the pixels array by doing something like this:
您可以通过以下操作获得对像素数组的访问:
final int[] a = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
Also you can do what you want to do with a single loop, looping over all the pixels.
你也可以用一个循环来做你想做的事情,循环遍历所有的像素。
Instead of:
而不是:
for ( int x = 0; x < width; x++ ) {
for ( int y = 0; y < height; y++ ) {
....
You can do:
你能做什么:
for ( int p = 0; p < width*height; p++ ) {
Now if you want to get into weirder optimizations, not as likely to prove effective you could:
现在,如果你想要进行更奇怪的优化,你不太可能证明你是有效的:
-
use loop unrolling (iterating over 6 million pixels is one of the rare case where it may help)
使用循环展开(迭代超过600万像素是一种很少见的情况)
-
invert the loop: for ( p = width*height - 1; p >= 0; p--)
反转循环:for (p = width*height - 1;p > = 0;p——)
#2
1
You can use getSamples(int x, int y, int w, int h, int b, double[] dArray) method It's possible that this method have internal optimisations. Also, you can try to swap width and height.
您可以使用getSamples(int x, int, int, int, int, b, double[] dArray)方法,这种方法可能有内部优化。此外,您可以尝试交换宽度和高度。
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
}
}
And
和
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
}
}
Between this two variants performance difference will be huge. This is influence of the cpu cache
在这两种变体之间,性能差异将是巨大的。这是cpu缓存的影响。