Java Swing 2D. Обработка изображений

Прикладное программирование Программирование на Java Java Swing 2D. Обработка изображений

Помечено: , , ,

  • В этой теме 0 ответов, 1 участник, последнее обновление 1 год, 5 месяцев назад сделано Васильев Владимир Сергеевич.
Просмотр 0 веток ответов
  • Автор
    Сообщения
    • #5247
      @admin

      Обработка изображения

      Используя классы с интерфейсом BufferedImageOp и RasterOp, можно наложить фильтр
      на изображение или применить один из rgb эффектов, как увеличение яркости.

      Успех обработки также зависит от типа изображения. Например, я попробовал применить RescaleOp на изображении с типом BufferedImage.TYPE_3BYTE_BGR, и получил сообщение о крахе джава машины. А с типом BufferedImage.TYPE_INT_BGR все было отлично.

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

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

      public class MyComponent extends JComponent {
      	BufferedImage img;
      	BufferedImage tstimg;
      	
      	public MyComponent() {
      		img = ImageUtil.loadImage("tree.png");
      
      		// применяем один из эффектов
      		tstimg = ImageUtil.gray(img);		
      	}
      
      	@Override
      	protected void paintComponent(Graphics g) {
      		Graphics2D g2 = (Graphics2D) g;
      		g2.drawImage(img, 0, 0, null);
      		g2.drawImage(tstimg, img.getWidth()+5, 0, null);	
      	}	
      }
      

      наложение фильтра

      Для наложения фильтра используется класс ConvolveOp. Матрица фильтра описывается классом Kernel, которому передается одномерный массив чисел типа float, и размеры, каким образом этот массив представлять в виде матрицы. Используемый алгоритм не производит конечного деления на сумму элементов матриц. Так матрица размытия (смягчения) должна задаваться

      float val = 1.0f / 9.0f;
      float[] filter = { val, val, val, val, val, val, val, val, val };
      

      а не

      float val = 1.0f;
      float[] filter = { val, val, val, val, val, val, val, val, val };
      

      Ниже приведен метод blur из класса ImageUtil, накладывающий фильтр размытия

      public static BufferedImage blur(BufferedImage img) {
         float val = 1.0f / 9.0f;
         float[] filter = { val, val, val, val, val, val, val, val, val };
         BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, filter));
         return op.filter(img, null);
      }
      

      Также смотрите метод sharpen, накладывающий выделения краев.

      Для лучшего качества, можно создать увеличенное изображение на (ширина матрицы-1)/2 по ширине и (высота матрицы-1)/2 по высоте. Вывести исходное изображение в центр нового, а затем применить фильтр с опцией не обрабатывать края изображения.

      BufferedImageOp op = 
           new ConvolveOp(new Kernel(3, 3, filter), ConvolveOp.EDGE_NO_OP, null);
      

      пространство цветов

      Класс ColorConvertOp позволяет преобразовать текущее пространство цветов изображения в
      указанное. Это можно использовать, например, для создания черно-белой копии изображения

      public static BufferedImage gray(BufferedImage img) {
          ColorSpace cs = ColorSpace.getInstance(
              ColorSpace.CS_GRAY);
          BufferedImageOp op = new ColorConvertOp(cs, null);
          return op.filter(img, null);
      }
      

      замена цветов

      Класс LookupOp позволяет заменить значения в указанном банке или во всех банках на соответствующие значения из массива. Например, если в красном банке встретилось значение 64, то оно будет заменено на значение 64 элемента массива. Это позволяет достигнуть таких rgb эффектов как огрубление и инверсия (цветной негатив).

      //массив для огрубления
      public static short[] getPosterizePal() {
          short ret[] = new short[256];
          for (int i = 0; i < 256; i++)
              ret[i] = (short) (i - (i % 32));
          return ret;
      }
      
      public static BufferedImage posterize(BufferedImage img) {
          short[] lookup = getPosterizePal();
          BufferedImageOp op = new LookupOp(new ShortLookupTable(0, lookup), null);
          BufferedImage ret = copy(img, BufferedImage.TYPE_INT_RGB);
          op.filter(ret, ret);
          return ret;
      }
      

      масштабирование цвета

      Класс RescaleOp позволяет умножить значения компонент цвета на коэффициент и после добавить указанное смещение.

      newr = (oldr * factor) + offset
      newg = (oldg * factor) + offset
      newb = (oldb * factor) + offset
      

      Множитель указывается числом типа float, а смещение как целое число от 0 до 255 Если смещение равно 0, то результат будет аналогичен фильтрации изображения с матрицой ядра 1х1. Ниже приведен метод увеличение яркости

      // factor = 1.25f увеличит яркость на 25%
      public static BufferedImage bright(BufferedImage img, float factor) {
          RescaleOp op = new RescaleOp(factor, 0, null);
          BufferedImage ret = copy(img,BufferedImage.TYPE_INT_BGR);
          op.filter(ret, ret); 
          return  ret;
      }
      

      Также смотрите метод light для осветления/затемнения изображения.

      аффинные преобразования

      Класс AffineTransformOp> выполняет аффинные преобразование над изображением, используя указанную матрицу преобразования. Например, ниже приведен методмасштабирования изображения. Аргументы большие 1 увеличивают изображение, меньшие 1 — уменьшают.

      public static BufferedImage scale(BufferedImage img, float fw, float fh){		
          AffineTransform mt =
             AffineTransform.getScaleInstance(fw, fh);
          AffineTransformOp op = new AffineTransformOp(mt,
               AffineTransformOp.TYPE_BILINEAR);
          return op.filter(img, null);
      }
      

      Некоторые эффекты аффинных преобразований можно получить методом drawImage.

      public static BufferedImage resize(BufferedImage img, int w, int h) {
          BufferedImage ret = new BufferedImage(w, h, rightTypeImage(img));
          Graphics2D g2 = ret.createGraphics();
          g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                  RenderingHints.VALUE_INTERPOLATION_BILINEAR);
          g2.drawImage(img, 0, 0, w, h, null);
          g2.dispose();
          return ret;
      }
      

      Немного длинее, и пришлось корректировать тип изображения, так как для моего изображения метод getType класса BufferedImage возвращал 0. А это не позволяет выводить в изображение.

      класс ImageUtil

      Несколько слов о вспомогательных методах класса.

      Метод rightTypeImage введен, чтобы корректировать тип изображения, если getType исходного изображения равно 0. Был необходим для эффектов реализуемых методом drawImage класса
      Graphics2D.

      Не все классы смогли создать автоматически корректное результирующее изображение методом filter интерфейса BufferedImageOp. Поэтому я добавил метод copy, делающего копию исходного изображения с коррекцией типа изображения. Чтобы результат теста совпадал с результатом других графических программ (XnView), я убирал альфа-канал из изображения вторым методом copy, где можно указать желаемый тип изображения.

Просмотр 0 веток ответов
  • Для ответа в этой теме необходимо авторизоваться.