java.awt.image.BufferedImage Преобразование 24-битного RGB в 8-битное оттенки серого с использованием пользовательского ColorSpace

Я хочу сделать простое преобразование цвета в оттенки серого, используя java.awt.image.BufferedImage. Я новичок в области обработки изображений, поэтому прошу простить, если что-то напутал.

Мое входное изображение представляет собой 24-битное изображение RGB (без альфа-канала), я хотел бы получить на выходе 8-битную шкалу серого BufferedImage, что означает, что у меня есть такой класс (детали опущены для ясности):

public class GrayscaleFilter {
    private BufferedImage colorFrame;
    private BufferedImage grayFrame = 
        new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

До сих пор я успешно пробовал 2 метода преобразования, первый из которых:

    private BufferedImageOp grayscaleConv = 
        new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);

    protected void filter() {
        grayscaleConv.filter(colorFrame, grayFrame);
    }

И второе существо:

    protected void filter() {       
        WritableRaster raster = grayFrame.getRaster();

        for(int x = 0; x < raster.getWidth(); x++) {
            for(int y = 0; y < raster.getHeight(); y++){
                int argb = colorFrame.getRGB(x,y);
                int r = (argb >> 16) & 0xff;
                int g = (argb >>  8) & 0xff;
                int b = (argb      ) & 0xff;

                int l = (int) (.299 * r + .587 * g + .114 * b);
                raster.setSample(x, y, 0, l);
            }
        }
    }

Первый метод работает намного быстрее, но получаемое изображение очень темное, а это означает, что я теряю полосу пропускания, что неприемлемо (существует некоторое сопоставление преобразования цветов, используемое между оттенками серого и sRGB ColorModel, называемое tosRGB8LUT, которое не очень хорошо работает для меня, поскольку как я могу сказать, но я не уверен, я просто предполагаю, что эти значения используются). Второй способ работает медленнее, но эффект очень приятный.

Есть ли способ объединить эти два, например. используя пользовательский индекс ColorSpace для ColorConvertOp? Если да, не могли бы вы привести пример?

Заранее спасибо.


person mmm    schedule 13.10.2010    source источник


Ответы (4)


здесь есть пример, который отличается от вашего первого примера в один небольшой аспект, параметры ColorConvertOp. Попробуй это:

protected void filter() {
   BufferedImageOp grayscaleConv = 
      new ColorConvertOp(colorFrame.getColorModel().getColorSpace(), 
                         grayFrame.getColorModel().getColorSpace(), null);
   grayscaleConv.filter(colorFrame, grayFrame);
}
person Mark Ransom    schedule 02.01.2012
comment
Этот предлагаемый метод также дает более темное изображение. Интересно, решил ли кто-нибудь эту проблему. - person ecem; 07.06.2013
comment
@ecem, возможно, это та же причина, что и в этом вопросе: stackoverflow.com/questions/15399653/ - person Mark Ransom; 05.02.2014

Попробуйте изменить второй подход. Вместо того, чтобы работать с одним пикселем, извлеките массив значений argb int, преобразуйте его и установите обратно.

person AnonymousCoward    schedule 06.02.2011

Второй метод основан на яркости пикселя, поэтому он дает более благоприятные визуальные результаты. Это можно немного ускорить, оптимизировав дорогостоящую арифметическую операцию с плавающей запятой при вычислении l с использованием массива поиска или хеш-таблицы.

person Nguyễn Minh Vũ    schedule 20.02.2013

Вот решение, которое сработало для меня в некоторых ситуациях.

Возьмите высоту изображения y, ширину изображения x, глубину цвета изображения m и размер целого числа в битах n. Работает, только если (2^m)/(x*y*2^n) >= 1. Сохраняйте n-битное целое число для каждого цветового канала при обработке начальных значений шкалы серого. Разделите каждую сумму на (x*y) для среднего значения avr[channel] каждого канала. Добавьте (192 - avr[channel]) к каждому пикселю для каждого канала.

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

person AaronF    schedule 04.04.2016