Более быстрый способ извлечь гистограмму из изображения - PullRequest
12 голосов
/ 22 ноября 2011

Я ищу более быстрый способ извлечения данных гистограммы из изображения.В настоящее время я использую этот фрагмент кода, который требует около 1200 мс для изображения JPEG 6 мегапикселей:

        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)]++;

            }

У вас есть предложения?

Ответы [ 2 ]

6 голосов
/ 22 ноября 2011

Вы делаете лот из getSamples вызовов методов, и они в свою очередь выполняют вызовы и вызовы и т. Д.

Я часто работаю с изображениями, и типичный трюк для увеличения скорости заключается в непосредственном манипулировании базовым int [] (в этом случае ваш BufferedImage должен быть поддержан int [] ).

Разница между доступом к int [] и, скажем, getRGB может быть гигантской. Когда я пишу гигантский, я имею в виду целых два порядка (попробуйте сделать getRGB на OS X 10,4 против int [x] , и вы увидите увеличение производительности) .

Кроме того, три раза нет вызова getSamples . Я бы просто получил одно целое число, соответствующее вашему пикселю ARGB, а затем смещение по битам, чтобы получить полосы RGB (вы делаете одну гистограмму на компоненты R, G и B, верно?).

Вы можете получить доступ к массиву пикселей, выполнив что-то вроде этого:

final int[] a = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

Также вы можете делать то, что хотите, с помощью одного цикла с циклом по всем пикселям.

Вместо:

for ( int x = 0; x < width; x++ ) {
    for ( int y = 0; y < height; y++ ) {
        ....

Вы можете сделать:

for ( int p = 0; p < width*height; p++ ) {

Теперь, если вы хотите заняться более странными оптимизациями, вряд ли вы окажетесь эффективными:

  • использовать развертывание цикла (итерация более 6 миллионов пикселей - один из редких случаев, когда это может помочь)

  • инвертировать цикл: для (p = ширина * высота - 1; p> = 0; p -)

1 голос
/ 22 ноября 2011

Вы можете использовать метод getSamples (int x, int y, int w, int h, int b, double [] dArray) Возможно, этот метод имеет внутреннюю оптимизацию. Также вы можете попробовать поменять ширину и высоту.

for (int i = 0; i < width; i++) 
   for (int j = 0; j < height; j++) {
   }
}

А

for (int i = 0; i < height; i++) 
   for (int j = 0; j < width; j++) {
   }
}

Между этими двумя вариантами разница в производительности будет огромной. Это влияние кеша процессора

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...