Как я могу обработать BufferedImage быстрее - PullRequest
0 голосов
/ 10 апреля 2020

Я создаю базовый c редактор изображений, чтобы улучшить свои навыки обработки изображений. У меня 12 фильтров (пока). Все фильтры имеют кликабельную JLabel с изображением Я обновляю изображения всех из них, когда все фильтры применяются с этой функцией:

public static void buttonImagesUpdater(){
    for(int i = 0; i < effects.size(); i++){
        effects.get(i).getButton().setImage(new ImageIcon(effects.get(i).process(image)));
    }
}

Все фильтры имеют такую ​​функцию процесса:

public BufferedImage process(BufferedImage base) {
    BufferedImage product = new BufferedImage(base.getWidth(), base.getHeight(), base.getType());
    for(int indisY = 0; indisY < base.getHeight(); indisY++){
        for(int indisX = 0; indisX < base.getWidth(); indisX++){
            Color currentColor = new Color(base.getRGB(indisX, indisY));
            int greyTone = 0;
            greyTone = (int) (currentColor.getRed()*0.315) +
                    (int) (currentColor.getGreen()*0.215) 
                    + (int) (currentColor.getBlue()*0.111);
            product.setRGB(indisX, indisY, new Color(greyTone,greyTone,greyTone).getRGB());

        }
    }
    return product;
}

Программа работает так медленно. Когда я нажимаю кнопку эффекта, это происходит через 45 секунд, когда я использую изображение 5000x3000. Как я могу исправить эту проблему производительности?

Ответы [ 3 ]

0 голосов
/ 10 апреля 2020

Я согласен с @Jason - проблема в том, что вы создаете (и уничтожаете) 15 миллионов объектов Color.

Однако я не думаю, что одного использования нескольких потоков вам достаточно увеличения производительности, потому что вы по-прежнему будете сильно нагружать память и сборщик мусора, поскольку вы все равно будете создавать и уничтожать 15 миллионов объектов, вы просто будете делать несколько параллельно.

Я думаю, что вы можете как полностью отказаться от создания объектов Color, так и сделать меньше циклов, напрямую используя результат метода BufferedImage class 'getRGB(), вместо создания объекта Color. Кроме того, вы можете использовать перегрузку getRGB(), которая возвращает массив целых чисел, чтобы получить, скажем, ряд пикселей (или более) за раз, чтобы уменьшить количество вызовов, которые вы должны делать внутри l oop. Вы также можете использовать версию setRGB(), которая принимает массив значений пикселей.

Хитрость заключается в том, чтобы иметь возможность преобразовать значение цвета int в значение серого (или все, что вам нужно сделать) без разделение значений R, G и B или поиск эффективного способа разделения R, G и B - более эффективный, чем создание, использование и уничтожение объекта Color.

Что касается получения значений R, G и B из int, возвращаемого getRGB (), обратите внимание, что документация для Color.getRGB() гласит:

"Возвращает RGB значение, представляющее цвет в sRGB ColorModel по умолчанию (биты 24-31 - альфа, 16-23 - красный, 8-15 - зеленый, 0-7 - синий). "

После того, как вы получите что работает, вы можете подумать о его распараллеливании.

0 голосов
/ 10 апреля 2020

Вы можете попробовать это, чтобы увидеть, если вещи немного ускоряются.

  • Использует DataBuffer из Image Raster.
  • И использует карту для сохранения предыдущих преобразованных цветов. Это может помочь в течение определенного периода времени в зависимости от типа изображения.
  • И работает с двойными значениями, поскольку буфер данных поддерживает различные типы.

Я также умножил ваши значения на степени 2, чтобы переместить их в правильное положение. Методы get * для Color возвращают значения от 0 до 255 включительно. RGB занимают младшие 24 бита для целого числа (альфа находится в самом левом байте).

Все, что я вижу, - это темное изображение, но я проверил это с другими параметрами, и я знаю, что это работает. Длинный столб в палатке, кажется, читает и пишет изображения. Я использовал 6637 3787 изображение и мог читать, изменять и записывать его за 12 секунд. Для более сложной обработки вы можете проверить AffineTransformOp.

    static Map<Color, Double> colorMap = new HashMap<>();

    public BufferedImage process(BufferedImage base) {
        DataBuffer db = base.getRaster().getDataBuffer();
        for (int i = 0; i < db.getSize(); i++) {
            Color currentColor = new Color(db.getElem(i));
            double greyTone = colorMap.computeIfAbsent(currentColor, v-> 
            currentColor.getRed() * .315 *256*256
                        + currentColor.getGreen() *.215 * 256
                            + currentColor.getBlue()*.115);

            db.setElemDouble(i, greyTone);

        }
        return base;    
    }
0 голосов
/ 10 апреля 2020

Вы должны помнить, что 3000 * 5000 - это 15 000 000, поэтому вы создаете 15 000 000 объектов Color, вы вызываете setRGB 15 000 000 раз. На вашем месте я бы изучил возможность использования ForkJoinPool для этого.

...