miércoles, 19 de octubre de 2011

Manipulacion y tratamiento de imagenes con Swing. Escala de grises, imagen espejo, imagen translucida

5 comentarios
Hola de nuevo amigos, hoy vamos a deleitarnos con algunas de las herramientas que nos ofrece Java2D para el tratamiento de imágenes.

En primer lugar os presentaré una imagen original y sobre esta iremos aplicando diversas transformaciones para hacer que parezca una imagen totalmente distinta.

En primer lugar os dejo el código para lanzar nuestra aplicación y a medida que vayamos avanzando, iremos explicando cada una de las transformaciones que hemos aplicado a nuestra imagen original.



package tratamientoImagenes;

import javax.swing.JFrame;


public class Main {

 private static void createAndShowGUI() {
  JFrame frame = new JFrame("Tratamiento de imágenes con Swing");

  Expositor panel = new Expositor();

     frame.getContentPane().add(panel);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setSize(800, 534);
     frame.setVisible(true);
 }

 public static void main(String[] args) {

  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    createAndShowGUI();
   }
  });
 }
}

Este es nuestro panel expositor, mediante un GridLayout añadiremos 4 paneles, cada uno de ellos con una imagen de fondo y un aspecto distinto a pesar de ser la misma imagen de base.

package tratamientoImagenes;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Expositor extends JPanel {

 /**
  * Constructor.
  */
 public Expositor() {
  /*
   * Creamos un layout de 4 paneles, en cada uno mostraremos una imagen
   * "aparentemente" distinta
   */
  super(new GridLayout(2, 2));
  setPreferredSize(new Dimension(800, 534));

  // Los paneles con las imagenes
  Original original = new Original();
  EscalaDeGrises escalaDeGrises = new EscalaDeGrises();
  Espejo espejo = new Espejo();
  Translucida translucida = new Translucida();

  Dimension photoDimension = new Dimension(400, 267);
  original.setPreferredSize(photoDimension);
  escalaDeGrises.setPreferredSize(photoDimension);
  espejo.setPreferredSize(photoDimension);
  translucida.setPreferredSize(photoDimension);

  original.setOpaque(false);
  escalaDeGrises.setOpaque(false);
  espejo.setOpaque(false);
  translucida.setOpaque(false);

  // Etiquetas
  JLabel originalLabel = new JLabel("ORIGINAL");
  JLabel escalaDeGrisesLabel = new JLabel("ESCALA DE GRISES");
  JLabel espejoLabel = new JLabel("ESPEJO");
  JLabel translucidaLabel = new JLabel("TRANSLUCIDA");
  originalLabel.setForeground(Color.WHITE);
  escalaDeGrisesLabel.setForeground(Color.WHITE);
  espejoLabel.setForeground(Color.WHITE);
  translucidaLabel.setForeground(Color.WHITE);

  original.add(originalLabel);
  escalaDeGrises.add(escalaDeGrisesLabel);
  espejo.add(espejoLabel);
  translucida.add(translucidaLabel);

  this.add(original);
  this.add(escalaDeGrises);
  this.add(espejo);
  this.add(translucida);

 }

 /**
  * Para recuperar una imagen de un archivo...
  *
  * @param path Ruta de la imagen relativa al proyecto
  * @return una imagen
  */
 public static ImageIcon createImage(String path) {
  URL imgURL = Expositor.class.getResource(path);
  if (imgURL != null) {
   return new ImageIcon(imgURL);
  } else {
   System.err.println("Couldn't find file: " + path);
   return null;
  }
 }

}

Y ahora empezamos con los paneles, primero presentamos la imagen original para que podáis apreciar los cambios que iremos realizando, el como pintar un panel transparente con una imagen de fondo ya lo tratamos en una entrada anterior JPanel con imagen de fondo.

package tratamientoImagenes;

import java.awt.Graphics;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Original extends JPanel {

 // Cargamos la imagen original
 private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");

 @Override
 public void paint(Graphics g) {

  g.drawImage(photo.getImage(), 0, 0, null);

  // Pintamos el resto de componentes
  super.paint(g);
 }

}

Una transformación que personalmente me gusta bastante, pasaremos la imagen original por uno de los filtros de RGBImageFilter, en este caso el filtro de escala de grises. Este tipo de filtro hará que los pixeles se vean mas claros para posteriormente aplicarle tonos grises a la imagen. Así es como lo hemos usado:

package tratamientoImagenes;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;

import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class EscalaDeGrises extends JPanel {

 // Cargamos la imagen original
 private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");

 @Override
 public void paint(Graphics g) {

  // Imagen
  Image img = photo.getImage();

  // Filtro de escala de grises
  ImageFilter filter = new GrayFilter(true, 50);
  ImageProducer producer = new FilteredImageSource(img.getSource(), filter);

  ImageIcon newIcon = new ImageIcon(this.createImage(producer));
  newIcon.paintIcon(this, g, 0, 0);

  // Pintamos el resto de componentes
  super.paint(g);
 }

}

Cuando dibujamos una imagen, podemos aplicarle una transformada para girarla como nos apetezca, usamos para ello el método drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer); del objeto Graphics2D. Este método nos permite cosas como dibujar parte de una imagen en otra imagen, escalar una imagen y otras tantas. Tomamos la imagen y una serie de coordenadas del rectángulo destino (dx, dy) así como del rectángulo origen (sx, sy). Manipulando estas coordenadas podemos hacer que la imagen se voltee como queramos.

En Java las coordenadas empiezan en la esquina superior izquierda y terminan en la inferior derecha, así pues para girar una imagen como si estuviésemos frente a un espejo modificamos las coordenadas del rectángulo origen para que empiecen en el borde superior derecho y terminen en el inferior izquierdo.

En el ejemplo las modificamos para voltear la imagen 180 grados, es decir, como si viésemos un reflejo en un lago. Tomaremos entonces como origen la esquina inferior izquierda y terminamos en la superior derecha.

package tratamientoImagenes;

import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Espejo extends JPanel {

 // Cargamos la imagen original
 private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");

 @Override
 public void paint(Graphics g) {

  // Imagen
  Image img = photo.getImage();

  int width = photo.getIconWidth();
  int height = photo.getIconHeight();

  // Rotamos la imagen
  g.drawImage(img, 0, 0, width, height, 0, height, width, 0, null);

  // Pintamos el resto de componentes
  super.paint(g);
 }


Y por último haremos translucida la imagen original, para ello deberemos cargar todos los pixeles de la imagen en una BufferedImage, y sobre esta aplicar un filtro modificando el componente alpha de cada pixel.

package tratamientoImagenes;

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Translucida extends JPanel {

 @Override
 public void paint(Graphics g) {

  // En este caso tendremos que trabajar con una BufferedImage
  URL imgURL = Expositor.class.getResource("imagenes/ER.jpg");
  BufferedImage img = null;
  try {
   img = ImageIO.read(imgURL);
  } catch (IOException e) {
   e.printStackTrace();
  }
  int w = img.getWidth(null);
  int h = img.getHeight(null);

  // Necesitaremos una imagen auxiliar a la que aplicar un filtro
  BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
  Graphics gI = bi.getGraphics();

  // Sobre esta imagen dibujaremos la imagen original
  gI.drawImage(img, 0, 0, null);

  Graphics2D g2d = (Graphics2D) g;
  // Establecemos la componente alpha de nuestros graficos 50%
  g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
  /* Draw the image, applying the filter */
  g2d.drawImage(bi, null, 0, 0);

  // Pintamos el resto de componentes
  super.paint(g);
 }

}

Y así termina todo, espero que os haya resultado útil este mini-tutorial sobre tratamiento de imágenes.

Un saludo y hasta pronto.