Неправильная яркость при преобразовании изображения в оттенки серого в Java - PullRequest
2 голосов
/ 26 ноября 2011

Я преобразую изображение в оттенки серого в Java с помощью следующего кода:

BufferedImage originalImage = ImageIO.read(new File("/home/david/input.bmp"));
BufferedImage grayImage = new BufferedImage(originalImage.getWidth()
                                          , originalImage.getHeight()
                                          , BufferedImage.TYPE_BYTE_GRAY);

ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp colorConvert = new ColorConvertOp(gray, null);
colorConvert.filter(originalImage, grayImage);

ImageIO.write(grayImage, "bmp", new File("/home/david/output_java.bmp"));

Кажется, что это работает, но проблема в том, что выходное изображение сильно отличается от сгенерированного изображения в оттенках серого.от gimp (см. примеры ниже).

  1. Могу ли я каким-то образом контролировать, как генерируется изображение?
  2. Как сделать результат более похожим на результат gimp?

Исходное изображение:

Color original image

Изображение в оттенках серого, созданное на Java:

Gray scale image generated by ColorConvertOp

Изображение в оттенках серого, созданное вGIMP (Image -> Mode -> Grayscale):

Gray scale image generated in Gimp

Кстати: у меня есть куча изображений из ffmpeg (с серой опцией), и они как изображения Gimp, поэтому я хочумое изображение таким образом.

Ответы [ 2 ]

4 голосов
/ 26 ноября 2011

Узнайте формулу конвертации, используемую Gimp. Вероятно, учитывается восприятие человеческого цвета, в то время как реализация Java математическая (R+G+B)/ 3.

2 голосов
/ 02 декабря 2011

Наконец, я написал GrayscaleFilter класс, реализующий интерфейс BufferedImageOp.

Я следовал это действительно хорошее руководство по обработке изображений Java.

Это соответствующий фрагмент кода:

public class GrayscaleFilter extends AbstractFilter
{
    public final static double[] METHOD_AVERAGE = {1.0/3.0, 1.0/3.0, 1.0/3.0};
    public final static double[] METHOD_GIMP_LUMINOSITY = {0.21, 0.71, 0.07};

    public GrayscaleFilter(final double[] rgb)
    {
        this(rgb[0], rgb[1], rgb[2]);
    }

    public BufferedImage filter(BufferedImage src, BufferedImage dest)
    {
        if (src.getType() == BufferedImage.TYPE_BYTE_GRAY)
        {
            dest = src;
            return dest;
        }

        if (dest == null)
            dest = createCompatibleDestImage(src, null);

        final int width = src.getWidth();
        final int height = src.getHeight();

        int[] inPixels = new int[width * height];
        GraphicsUtilities.getPixels(src, 0, 0, width, height, inPixels);
        byte[] outPixels = doFilter(inPixels);
        GraphicsUtilities.setPixels(dest, 0, 0, width, height, outPixels);
        return dest;
    }

    private byte[] doFilter(int[] inputPixels)
    {
        int red, green, blue;
        int i = 0;
        byte[] outPixels = new byte[inputPixels.length];

        for(int pixel : inputPixels)
        {
            // Obtengo valores originales
            red   = (pixel >> 16) & 0xFF;
            green = (pixel >> 8) & 0xFF;
            blue  = pixel & 0xFF;

            // Calculo valores nuevos
            outPixels[i++] = (byte)(
                 red   * red_part   +
                 green * green_part +
                 blue  * blue_part
            );
        }
        return outPixels;
    }

    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM)
    {
        return new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...