更快的方法从图像中提取直方图。

时间:2022-11-02 21:19:16

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缓存的影响。