Невозможно получить оттенки серого изображения в java - PullRequest
1 голос
/ 30 марта 2020

У меня проблема с получением серой шкалы .jpg файла. Я пытаюсь создать новый файл .jpg в оттенках серого, но я просто больше ничего не копирую. Вот мой код:

package training01;

import java.awt.*;
import java.awt.image.BufferedImage;

import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class GrayScale {
    BufferedImage image;
    int width;
    int height;
    public GrayScale() {
        try {
            File input = new File("digital_image_processing.jpg");
            image = ImageIO.read(input);
            width = image.getWidth();
            height = image.getHeight();
            for(int i = width;i < width;i++) {
                for(int j = height;j < height;j++) {
                    Color c =  new Color(image.getRGB(i, j));
                    int red = c.getRed();
                    int green = c.getGreen();
                    int blue = c.getBlue();
                    int val = (red+green+blue)/3;
                    Color temp = new Color(val,val,val);
                    image.setRGB(i, j, temp.getRGB());
                }
            }
            File output = new File("digital_image_processing1.jpg");
            ImageIO.write(image, "jpg", output);
        }catch(Exception e) {
            System.out.println(e);
        }
    }
    public static void main(String[] args) {
        GrayScale gs = new GrayScale();
    }
}

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Основная проблема с вашим кодом состоит в том, что он не будет l oop, потому что вы инициализируете i, j в width, height, что уже больше, чем условие выхода из циклов for (i < width, j < height) , Начните итерацию с 0, инициализируя i и j до 0, и ваш код будет работать так, как задумано.

Для повышения производительности вы также хотите изменить порядок циклов. Поскольку BufferedImage s хранятся в виде непрерывного массива, строка за строкой, вы будете использовать кэш ЦП гораздо лучше, если вы поместите l oop по оси x (строка) во внутренней l oop.

Примечание: я также предлагаю переименовать i и j в x и y для лучшей читаемости.

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


Тем не менее, все это сказано для изображений JPEG, хранящихся как YCbCr (наиболее распространенный способ хранения JPEG), существует гораздо более быстрый, эффективный для памяти и более простой способ преобразования изображения в шкалу серого, а именно простое считывание канала Y (яркости) JPEG и непосредственное использование его в качестве шкалы серого.

Используя Java и ImageIO, вы можете сделать это следующим образом:

public class GrayJPEG {
    public static void main(String[] args) throws IOException {
        try (ImageInputStream stream = ImageIO.createImageInputStream(new File(args[0]))) {
            ImageReader reader = ImageIO.getImageReaders(stream).next(); // Will throw exception if no reader available

            try {
                reader.setInput(stream);
                ImageReadParam param = reader.getDefaultReadParam();

                // The QnD way, just specify the gray type directly
                //param.setDestinationType(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));

                // The very correct way, query the reader if it supports gray, and use that
                Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
                while (types.hasNext()) {
                    ImageTypeSpecifier type = types.next();

                    if (type.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_GRAY) {
                        param.setDestinationType(type);
                        break;
                    }
                }

                BufferedImage image = reader.read(0, param);

                ImageIO.write(image, "JPEG", new File(args[0] + "_gray.jpg"));

            }
            finally {
                reader.dispose();
            }
        }
    }
}
1 голос
/ 30 марта 2020

Вам необходимо изменить следующее. Начните свои i и j с 0.

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

Однако, есть более быстрый способ сделать это. Запишите его в новый объект BufferedImage, для которого задана шкала серого.

      image = ImageIO.read(input);
      width = image.getWidth();
      height = image.getHeight();
      bwImage = new BufferedImage(width,
            height, BufferedImage.TYPE_BYTE_GRAY);
      Graphics g = bwImage.getGraphics();
            g.drawImage(image,0,0,null);

Затем сохраните bwImage.

...