Tema 14 - Imágenes en Java
Tema 14 - Imágenes en Java
Tema 14 - Imágenes en Java
Imgenes en Java
Una imagen es un arreglo bidimensional de colores. Cada elemento de un arreglo se llama pixel. Una imagen es diferente de una superficie de dibujo. Los pixeles de una imagen no coinciden necesariamente con un pixel en la superficie de dibujo. Una imagen tiene ancho y un alto, medido en pixeles y un sistema de coordenadas que es independiente de la superficie de dibujo. En Java 2D, una imagen se representa por las clases Image y BufferedImage, figura 14.1. La clase abstracta Image representa una imagen como un arreglo rectangular de pixeles. La clase BufferedImage le permite a la aplicacin trabajar directamente con los datos de la imagen (por ejemplo obteniendo o estableciendo el color de un pixel). Esta clase administra directamente la imagen en memoria y provee mtodos para almacenar, interpretar y obtener datos de los pixeles.
ITSON
548
Imgenes en Java
Un objeto de tipo BufferedImage es esencialmente un objeto del tipo Image con un buffer de datos accesible, por lo que la hace ms eficiente para trabajar que con un objeto del tipo Image. Un objeto de tipo BufferedImage tiene un modelo de color, un objeto del tipo ColorModel y un entramado de los datos de la imagen, un objeto del tipo Raster, figura 14.2.
Figura 14.2 Un objeto de Tipo Buffered Image El objeto de tipo ColorModel provee una interpretacin de los pixeles de la imagen dentro del espacio de color. Un espacio de color es esencialmente una coleccin de todos los colores que pueden representarse en un dispositivo particular. Los monitores, por ejemplo, por lo general definen su espacio de color usando el color de espacio GB. Una impresora, por otro lado puede usar el espacio de color CMYK. Las imgenes pueden usar una de varias subclases de ColorModel en las bibliotecas de la API de java 2D: ComponentColorModel, en la que un pixel se representa por varios valores discretos, tipicamente bytes, cada uno representando una componente del color, como el componente rojo en la representacin RGB. DirectColorModel, en la que todos los componentes de un color estn empaquetados juntos en bits separados del mismo valor de un pixel. IndexColorModel, en la que cada pixel es un valor representado como un ndice en una paleta de colores. El objeto de tipo Raster almacena los datos reales de los pixeles para una imagen en un arreglo rectangular accesado por las coordenadas x, y. Est formado de dos partes: Un buffer de datos, que contiene los datos crudos de la imagen. Un modelo de muestreo, que describe como los datos estn organizados en el buffer. El entramado, realiza las siguientes tareas: Representa las coordenadas rectangulares de la imagen. Mantiene la imagen en memoria. Provee de mecanismos para crear mltiples subimgenes a partir de un solo buffer de los datos de la imagen. Provee de mtodos para accesar a los pixeles especficos de una imagen.
ITSON
Tema 14
Imgenes en Java
549
La clase BufferedImage una serie de constantes para los diferentes tipos de imgenes (modelos de colores). La tabla 14.1 describe los diferentes tipos de imgenes. Tabla 14.1 Tipos de Imagen de la clase BufferedImage.
Tipo TYPE_3BYTE_BGR TYPE_4BYTE_ABGR Descripcin Representa una imagen con componentes RGB de 8 bits, con los colores azul, verde y rojo almacenados en 3 bytes. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo almacenados en 3 bytes y un byte para el valor de alfa. Los datos de los colores no estn premultiplicados con el valor de alfa. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo almacenados en 3 bytes y un byte para el valor de alfa. Los datos de los colores estn premultiplicados con el valor de alfa. Representa una imagen con pixeles opacos de 1, 2 o 4 bits empaquetados. Los valores de los pixeles representan indices a una tabla de colores. Representa una imagen con pixeles en tonos de grises. El valor del pixel es un tono de gris (0 a 255). Representa una imagen con pixeles opacos de 1 byte. Los valores de los pixeles representan indices a una tabla de colores de 256 valores, 216 colores y el resto de tonos de grises. Tipo de imagen no reconocido. Debe ser una imagen con formato especial. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores no estn premultiplicados con el valor de alfa. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores estn premultiplicados con el valor de alfa. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo empacados en enteros. No hay valor de alfa. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y empacados en enteros. No hay valor de alfa. Representa una imagen con componentes RGB de 5-5-5 bits para los colores azul, verde y rojo. No hay valor de alfa. Representa una imagen con componentes RGB de 5-6-5 bits para los colores azul, verde y rojo. No hay valor de alfa. Representa una imagen con pixeles en tonos de grises. Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores no estn premultiplicados con el valor de alfa.
TYPE_4BYTE_ABGR_PRE
TYPE_BYTE_BINARY
TYPE_BYTE_GRAY TYPE_BYTE_INDEXED
TYPE_CUSTOM TYPE_INT_ARGB
TYPE_INT_ARGB_PRE
TYPE_INT_BGR
ITSON
550
Imgenes en Java
Dibujado de Imgenes
Al igual que con las grficas, podemos dibujar una figura sobre cualquier componente de swing que sea desplegable. La clase Graphics2D dispone del mtodo drawImage() cuya sintaxis se muestra en la tabla 14.4. Tabla 14.4 Mtodo para dibujar una Imagen BufferedImage.
public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) Despliega una imagen del tipo BufferedImage, que es filtrada con un filtro descrito por el objeto op, en las coordenadas (x, y).
Tema 14
Imgenes en Java
551
JOptionPane.showMessageDialog(lienzo, "No hay una imagen para desplegar"); return; } // Obtiene el tamao de la imagen int altoImagen = dbi.getHeight(); int anchoImagen = dbi.getWidth(); // Establece el tamao del panel al tamao de la imagen lienzo.setPreferredSize(new Dimension(altoImagen, anchoImagen)); lienzo.revalidate(); Graphics g = lienzo.getGraphics(); Graphics2D g2 = (Graphics2D) g; // Dibuja la imagen sobre el panel g2.drawImage(dbi, null, 1, 1); } ... }
ITSON
552
Imgenes en Java
Creacin de Imgenes
Podemos crear una nueva imagen (una imagen con todos los pixeles en cero) para posteriormente dibujar sobre ella. Para ello se sigue el siguiente procedimiento: 1. Crear un objeto del tipo BufferedImage. 2. Obtener del objeto del tipo BufferedImage, un objeto del tipo Graphics2D, para dibujar sobre la imagen. 3. Dibujar sobre la imagen usando los mtodos del objeto del tipo Graphics2D. El siguiente cdigo muestra un mtodo que permite crear una imagen nueva.
public class Control { ... // Imagen original private BufferedImage obi; /** * Este mtodo crea un objeto de tipo BufferedImage del * tamao del panel del parametro * @param lienzo Panel que establece el tamao de la imagen. */ public void nuevaImagen(JPanel lienzo) { // Obtiene el tamao del panel int altoImagen = lienzo.getHeight(); int anchoImagen = lienzo.getWidth(); // Crea una imagen del tamao del panel obi = new BufferedImage(anchoImagen, altoImagen, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = obi.createGraphics(); // Establece el color de fondo g2.setBackground(Color.white); g2.clearRect(0, 0, anchoImagen, altoImagen); // Hace que la referencia dbi apunte a obi dbi = obi; } ... }
ITSON
Tema 14
Imgenes en Java
553
/** * Este mtodo dibuja una figura sobre la imagen obi * @param frame Ventana sobre la que se despliega el * mensaje de error */ public void dibujaEnImagen(JFrame frame) { // Si no hay una imagen para dibujar if (obi == null) { JOptionPane.showMessageDialog(frame, "No hay una imagen para dibujar"); return; } // Obtiene el contexto de graficacin de la imagen Graphics2D g2 = obi.createGraphics(); // Establece el color de una trayectoria g2.setPaint(Color.black); // crea una trayectoria Path2D trayectoria = new Path2D.Double(Path2D.WIND_EVEN_ODD); trayectoria.moveTo(50, 50); trayectoria.lineTo(70, 44); trayectoria.curveTo(100, 10, 140, 80, 160, 80); trayectoria.lineTo(190, 40); trayectoria.lineTo(200, 56); trayectoria.quadTo(100, 150, 70, 60); trayectoria.closePath(); // Dibuja la trayectoria sobre la imagen obi g2.draw(trayectoria); // Hace que la referencia dbi apunte a obi dbi = obi; }
Las figuras 14.4 y 14.5 muestran una figura sobre una nueva imagen y sobre una imagen existente, dibujada por el mtodo anterior, respectivamente.
ITSON
554
Imgenes en Java
ITSON
Tema 14
Imgenes en Java
555
Figura 14.6 Clase ImageIO La tabla 14.5 muestra los mtodos de la clase ImageIO. Tabla 14.5 Mtodos de la Clase ImageIO
public static BufferedImage read(File input) throws IOException Regresa un objeto del tipo BufferedImage como resultado de decodificar el archivo dado por el parmetro, usando el objeto del tipo ImageReader seleccionado automaticamente de los registrados. public static BufferedImage read(ImageInputStream stream) throws IOException Regresa un objeto del tipo BufferedImage como resultado de decodificar el objeto del tipo ImageInputStream dado por el parmetro, usando el objeto del tipo ImageReader seleccionado automaticamente de los registrados. public static BufferedImage read(InputStream input) throws IOException Regresa un objeto del tipo BufferedImage como resultado de decodificar el objeto del tipo InputStream dado por el parmetro, usando el objeto del tipo ImageReader seleccionado automaticamente de los registrados. public static BufferedImage read(URL input) throws IOException Regresa un objeto del tipo BufferedImage como resultado de decodificar el objeto del tipo URL dado por el parmetro, usando el objeto del tipo ImageReader seleccionado automaticamente de los registrados. public static boolean write(RenderedImage im, String formatName, File output) throws IOException Escribe la imagen del parmetro im con el formato dado por formatName al archivo dado por output.
ITSON
556
Imgenes en Java
Como ejemplo de entrada / salida de imgenes se tiene un programa con una interfaz de usuario grfica. El programa permitir leer y guardar imgenes as como procesar esas imgenes. La opcin para leer una imagen de un archivo se muestra en la figura 14.7. Al seleccionar esa opcin se despliega un cuadro de dilogo para seleccionar el nombre del archivo con la imagen a leer, figuras 14.8 y 14.9.
Figura 14.7
ITSON
Tema 14
Imgenes en Java
557
Figura 14.8
Figura 14.9 El cdigo que permite leer una imagen de un archivo es el siguiente:
ITSON
558
Imgenes en Java
/** * Este metodo lee una imagen bmp, gif, jpg, png y la * guarda en el atributo dbi del tipo BufferedImage * @param frame Ventana sobre la que se despliega el cuadro * de dialogo JFileChooser */ public void leeImagen(JFrame frame) { JFileChooser fc = new JFileChooser(); // Elimina el filtro *.* fc.setAcceptAllFileFilterUsed(false); // Crea el filtro para las extenciones validas FileNameExtensionFilter extFiltro = new FileNameExtensionFilter( "Images", "bmp", "gif", "jpg", "png"); // Establece el filtro para las extenciones validas fc.setFileFilter(extFiltro); // Despliega el cuadro de dialogo para seleccionar la imagen a // abrir int returnVal = fc.showOpenDialog(frame); // Si se selecciono una imagen if (returnVal == JFileChooser.APPROVE_OPTION) { // Obtiene el objeto File de la imagen seleccionada file = fc.getSelectedFile(); try { // lee la imagen y la guarda en el atributo obi // del tipo BufferedImage obi = ImageIO.read(file); // Hace que la referencia dbi apunte a obi dbi = obi; } catch (IOException e) { JOptionPane.showMessageDialog(frame, "Error al cargar imagen"); return; } } }
La opcin para guardar una imagen de un archivo se muestra en la figura 14.7. Al seleccionar esa opcin se despliega un cuadro de dilogo para seleccionar el nombre del archivo en el que se guardar la imagen, figuras 14.10.
ITSON
Tema 14
Imgenes en Java
559
Figura 14.10 El cdigo que permite guardar una imagen a un archivo es el siguiente:
/** * Este metodo guarda la imagen bmp, gif, jpg, png del * atributo bi del tipo BufferedImage en un archivo * @param frame Ventana sobre la que se despliega el cuadro * de dialogo JFileChooser */ public void GuardaImagenComo(JFrame frame) { File fileSel = null; JFileChooser fc = new JFileChooser(); // Elimina el filtro *.* fc.setAcceptAllFileFilterUsed(false); // Agrega varios filtros de imagenes fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen //Establece el nombre inicial de la imagen ITSON
560
Imgenes en Java
fc.setSelectedFile(file); // Despliega cuadro de dialogo para obtener el nombre // del archivo en el que se va a guardar la imagen int returnVal = fc.showSaveDialog(frame); if (returnVal == JFileChooser.APPROVE_OPTION) { String nombreExt = null; // Obtiene el nombre del archivo seleccionado fileSel = fc.getSelectedFile(); // Obtiene el nombre del filtro seleccionado FileNameExtensionFilter extFiltro = (FileNameExtensionFilter) fc.getFileFilter(); // Obtiene la extension del nombre del filtro seleccionado String ext = extFiltro.getExtensions()[0]; String path = fileSel.getPath(); // Obtiene la extension del nombre del archivo seleccionado nombreExt = getExtension(fileSel); // Si el nombre seleccionado no corresponde a uno de imagen if(nombreExt != null && !esImageExtension(nombreExt)) { JOptionPane.showMessageDialog(frame, "No es un archivo de imagen"); return; } // Si no hay extension del nombre del archivo seleccionado if (nombreExt == null) { // Agregale la extension del nombre del filtro // seleccionado path += "." + ext; fileSel = new File(path); nombreExt = ext; } try { // Guarda la imagen ImageIO.write(bi, nombreExt, fileSel); } catch (IOException e) { JOptionPane.showMessageDialog(frame, "Error al guardar la imagen"); } } } /** * Este metodo despliega la imagen del atributo bi
ITSON
Tema 14
Imgenes en Java
561
* del tipo BufferedImage sobre el panel lienzo * @param lienzo Panel sobre el que se despliega la imagen */ public void despliegaimagen(JPanel lienzo) { // Obtiene el tamao de la imagen int altoImagen = bi.getHeight(); int anchoImagen = bi.getWidth(); lienzo.setPreferredSize(new Dimension(altoImagen, anchoImagen)); lienzo.revalidate(); Graphics g = lienzo.getGraphics(); Graphics2D g2 = (Graphics2D) g; g2.drawImage(bi, null, 1, 1); } /** * Este metodo estatico borra el contenido del panel de * su parametro * un conjunto de lineas * @param lienzo Panel a borrar */ public void borra(JPanel lienzo) { // Obtiene un objeto de tipo Graphics del panelLienzo Graphics g = lienzo.getGraphics(); // Al invocar al metodo paint se borra su contenido lienzo.paint(g); } /** * Este metodo estatico obtiene la extension de un archivo * @param file Objeto de tipo File de la que se obtiene * la extension * @return Extension de un archivo */ public static String getExtension(File file) { String ext = null; // Obtiene el nombre del archivo String s = file.getName(); // busca el separador de la extension int pos = s.lastIndexOf('.'); // Si hay un punto en el nombre y hay una // extension despues del punto if (pos > 0 && pos < s.length() - 1) { ext = s.substring(pos + 1).toLowerCase();
ITSON
562
Imgenes en Java
} return ext; } /** * Este medodo determina si la extension del nombre de archivo * corresponte a una imagen * @param ext Extension del nombre de archivo * @return true si si la extension del nombre de archivo * corresponte a una imagen, false en caso contrario */ public boolean esImageExtension(String ext) { String[] imagenesExt = {"bmp", "gif", "jpg", "png"}; for(int i = 0; i < imagenesExt.length; i++) { if(ext.equals(imagenesExt[i])) return true; } return false; } }
Procesamiento de Imgenes
El procesamiento de imgenes describe la forma de manipular matemticamente las imgenes. Procesar una imagen consiste en calcular un nuevo coor para cada pixel de una imagen. Ese nuevo color puede depender del color actual del pixel, del color de los pixeles vecinos, de otros parmetros o una combinacin de los anteriores. El API 2D de Java nos permite una forma sencilla de procesar imgenes basada en la clase BufferedImage y un conjunto de operaciones representadas en la interfaz BufferedImageOp. Las clases que implementan esta interfaz saben como procesar una imagen del tipo BufferedImage, llamada imagen fuente para producir una nueva imagen llamada imagen destino. Este proceso se muestra en la figura 14.11.
Figura 14.11.
ITSON
Tema 14
Imgenes en Java
563
Con la API 2D de Java, el procesamiento de imgenes es un procedimiento de dos pasos: 1. Instance la clase que represente la operacin a realizar. 2. Invoque a su mtodo filter() con la imagen como parmetro. La interfaz BufferedImageOp, las clases que implementan los mtodos de la interfaz y las clases que las soportan se muestran en la figura 14.12.
Figura 14.11. Las operaciones que realizan las clases que implementan la interfaz BufferedImageOp se muestran en la tabla 14.6. Tabla 14.6. Operaciones de Procesamiento de Imgenes
Clase ConvolveOp LookupOp ColorConvertOp RescaleOp AffineTransformOp Operacin Convolucin: Suavizado, intensificado, deteccin de orillas. Tabla de bsquedas: Posterizar, binarizar. Conversin de colores: Convertir a tonos de grises. Reescalar colores: Aclarar, oscurecer. Transformar: Escalar, rotar.
ITSON
564
Imgenes en Java
Convolucin
Una operacin de convolucin permite combinar el color de un pixel origen con los pixeles de sus vecinos para producir un pixel destino. Esa combinacin se especifica mediante un operador lineal llamado kernel (ncleo) que determina la proporcin de cada pixel de origena usarce para calcular el pixel destino. Un kernel es una matriz donde el centro de la matriz representa el pixel origen y los otros elementos sus vecinos. El color destino se calcula multiplicando cada color pixel por su correspondiente coeficiente del kernel y sumndolos, figura 14.12. La clase Kernel representa un kernel. Para construir un kernel podemos usar el constructor de la tabla 14.7.
Figura 14.12. Convolucin de un Solo Pixel. Tabla 14.7 Constructor de la clase Kernel.
public Kernel(int width, int height, float[] data) Construye un kernel a partir del arreglo de nmeros flotantes dados por el parmetro data. Las dimensiones del kernel estn dados por los parmetros width, height.
En un kernel, la suma de todos sus elementos debe ser 1.0. Si es mayor la imagen resultante ser ms clara. Si es menor, ser ms oscura. La operacin de convolucin est representada por la clase ConvolveOp. Los mtodos de la clase ConvolveOp se muestran en la tabla 14.8. Tabla 14.8 Mtodos de la clase ConvolveOp.
public ConvolveOp(Kernel kernel) public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) Construye un objeto del tipo ConvolveOp a partir de un kernel o un kernel, una constante que represente una condicinde orilla y una sugerencia de despliegue, la cual puede ser nula.
ITSON
Tema 14
Imgenes en Java
565
El parmetro edgeCondition establece la forma en que se calculan los colores de los pixeles de la orilla de la imagen destino. Tabla 14.9. Tipos de Condiciones de Orilla
Tipo EDGE_ZERO_FILL EDGE_NO_OP Descripcin Los pixeles en las orillas de la imagen destino se establecen a cero. Este es el valor por ausencia. Los pixeles en las orillas de la imagen fuente son copiados a sus correspondientes pixeles en la imagen destino sin modificacin.
Suavizado de Imgenes
Una de las operaciones de convolucin es el suavizado. En esta operacin el color de un pixel destino es el promedio de su correspondiente pixel origen con sus pixeles vecinos. Este tipo de filtrado es til para reducir el ruido de las imgenes. El siguiente cdigo muestra la implementacin de un filtro suavizador.
/** * Este metodo suaviza una imagen * @param frame Ventana sobre la que se despliega el mensaje de error */ public void suaviza(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define un kernel suavizador float ninth = 1.0f / 9.0f; float[] blurKernel = { ninth, ninth, ninth, ninth, ninth, ninth, ninth, ninth, ninth }; // crea una operacin de convolucin a partir del kernel ConvolveOp op = new ConvolveOp(new Kernel(3, 3, blurKernel));
ITSON
566
Imgenes en Java
// Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; } /** * Este metodo verifica que haya una imagen lista para ser procesada * @param frame Ventana sobre la que se despliega el mensaje de error */ private boolean preparaImagenProcesar(JFrame frame) { // Si no hay se ha creado una imagen vacia o se ha // cargado una imagen desde un archivo if (obi == null) { JOptionPane.showMessageDialog(frame, "No hay una imagen para procesar"); return false; } // Si no hay una imagen a procesar if (pbi == null) { // Crea una copia de la imagen original y la asigna a la // imagen a procesar pbi = obi.getSubimage(0, 0, obi.getWidth(), obi.getHeight()); // Obtiene el tamao de la imagen int altoImagen = pbi.getHeight(); int anchoImagen = pbi.getWidth(); // Convierte la imagen a una imagen RGB normalizada pbi = new BufferedImage(anchoImagen, altoImagen, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = pbi.createGraphics(); g2.drawImage(dbi, null, 0, 0); } return true; }
ITSON
Tema 14
Imgenes en Java
567
Figura 14.13. Filtro Suavizador. Izquierda: Imagen original, derecha: Imagen Suavizada.
Intensificado de Imgenes
Otra de las operaciones de convolucin es el intensificado. En esta operacin se busca resaltar el cambio en los colores de los pixeles, manteniendo los colores originales. El siguiente cdigo muestra la implementacin de un filtro intensificador.
/** * Este metodo intensifica una imagen * @param frame Ventana sobre la que se despliega el mensaje de error */ public void intensifica(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define un kernel intensificador float[] sharpKernel = { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0f }; // crea una operacin de convolucin a partir del kernel ConvolveOp op = new ConvolveOp(new Kernel(3, 3, sharpKernel)); ITSON Manuel Domitsu Kono
568
Imgenes en Java
// Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
Figura 14.14. Filtro Intensificador. Izquierda: Imagen original, derecha: Imagen Intensificada.
Deteccin de Orillas
Otra operacin de convolucin muy empleada es la de deteccin de orillas. En esta operacin se busca resaltar el cambio brusco en los colores de los pixeles. El siguiente cdigo muestra la implementacin de un filtro detector de orillas.
/** * Este metodo detecta las orillas de una imagen * @param frame Ventana sobre la que se despliega el mensaje de error */ public void detectorOrillas(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return;
ITSON
Tema 14
Imgenes en Java
569
// Define un kernel detector de orillas float[] edgeKernel = { 0.0f, -1.0f, 0.0f, -1.0f, 4.0f, -1.0f, 0.0f, -1.0f, 0.0f }; // crea una operacin de convolucin a partir del kernel ConvolveOp op = new ConvolveOp(new Kernel(3, 3, edgeKernel)); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
La figura 14.15 muestra la imagen original y la imagen con las orillas detectadas.
Figura 14.15. Filtro Detector de Orillas. Izquierda: Imagen original, derecha: Imagen Filtrada.
Tablas de Bsqueda
Otra operacin sobre las imgenes utiliza una tabla de bsqueda. En esta operacin, los pixeles de la imagen fuente se transforman a los pixeles de la imagen destino mediante el uso de una tabla. Tres tablas con 256 entradas cada
ITSON Manuel Domitsu Kono
570
Imgenes en Java
una son suficientes para transformar una imagen de color origen a una imagen de color destino. El valor de cada color de un pixel en la imagen origen se utiliza como ndice en su correspondiente tabla para obtener el valor del pixel de la imagen destino. Se puede utilizar una tabla para cada color, o la misma tabla para los tres colores. Cada tabla est encapsulada por la clase abstracta LookupTable y sus implementaciones ByteLookupTable y ShortLookupTable, que contienen arreglos de bytes y enteros cortos, respectivamente. Para construir tablas de bsqueda se tienen los constructores de las tablas 14.10. Tabla 14.10 Constructores de las clases ByteLookupTable y ShortLookupTable
public ByteLookupTable(int offset, byte[] data) Construye un objeto del tipo ByteLookupTable del arreglo de bytes del parmetro data que representa una tabla de bsqueda que se aplicar a todas las bandas. El valor del parmetro offset se le quitar a los valores de entrada antes de usarlos como ndices al arreglo. public ByteLookupTable(int offset, byte[][] data) Construye un objeto del tipo ByteLookupTable del arreglo de arreglos de bytes del parmetro data que representan una tabla de bsqueda para cada banda. El valor del parmetro offset se le quitar a los valores de entrada antes de usarlos como ndices a los arreglos. El nmero de bandas es es la longitud del parmetro data. public ShortLookupTable(int offset, short[] data) Construye un objeto del tipo ShortLookupTable del arreglo de enteros cortos del parmetro data que representa una tabla de bsqueda que se aplicar a todas las bandas. El valor del parmetro offset se le quitar a los valores de entrada antes de usarlos como ndices al arreglo. public ShortLookupTable(int offset, short[][] data) Construye un objeto del tipo ShortLookupTable del arreglo de arreglos de bytes del parmetro data que representan una tabla de bsqueda para cada banda. El valor del parmetro offset se le quitar a los valores de entrada antes de usarlos como ndices a los arreglos. El nmero de bandas es es la longitud del parmetro data.
La operacin usando tablas de bsqueda est representada por la clase LookUpOp. Los mtodos de la clase LookUpOp se muestran en la tabla 14.11.
ITSON
Tema 14
Imgenes en Java
571
Negativo de Imgenes
Una de las operaciones usando tablas de bsqueda es la inversin de colores. En esta operacin el color de un pixel destino se obtiene restndole a 255, el valor de su correspondiente pixel origen. La imagen resultante luce como el negativo de color de una pelcula convencional. El siguiente cdigo muestra la implementacin de un filtro inversor de colores.
/** * Este metodo invierte los colores de los pixeles de una image, * haciendo los pixeles claros oscuros y viceversa. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void invertir(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define una tabla de busqueda para invertir los tres canales. // Se aplica la misma tabla para los tres canales short[] invert = new short[256]; for (int i = 0; i < 256; i++) { invert[i] = (short) (255 - i); } LookupTable table = new ShortLookupTable(0, invert); // crea una operacin de busqueda a partir de la tabla LookupOp op = new LookupOp(table, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
La figura 14.16 muestra la imagen original y la imagen con los colores invertidos.
ITSON Manuel Domitsu Kono
572
Imgenes en Java
Figura 14.16. Inversin de colores. Izquierda: Imagen original, derecha: Imagen Negativa. En el siguiente cdigo se muestra una tabla de bsqueda en la que se tiene una tabla para cada canal. La operacin elimina la componente verde de la imagen haciendo ceros todos los elementos del arreglo asociado a la banda verde.
/** * Este metodo elimina la componente verde de una imagen. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void eliminarVerdes(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define una tabla de busqueda para eliminar la componente // verde de la imagen. Se aplican tabla diferentes para los // canales short[] zero = new short[256]; short[] straight = new short[256]; for (int i = 0; i < 256; i++) { zero[i] = (short) 0; straight[i] = (short) i; } short[][] greenRemove = {straight, zero, straight}; LookupTable table = new ShortLookupTable(0, greenRemove); // crea una operacin de busqueda a partir de la tabla LookupOp op = new LookupOp(table, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); ITSON Manuel Domitsu Kono
Tema 14
Imgenes en Java
573
La figura 14.17 muestra la imagen original y la imagen con los colores verdes removidos.
Figura 14.17. Remocin de colores. Izquierda: Imagen original, derecha: Imagen con los colores verdes removidos.
574
Imgenes en Java
La figura 14.19 muestra la imagen original y la imagen aclarada usando un mapeo lineal.
ITSON
Tema 14
Imgenes en Java
575
Figura 14.19. Abrillantando una imagen con un mapeo lineal. Izquierda: Imagen original, derecha: Imagen aclarada.
Figura 14.20. Abrillantando una imagen con un mapeo raz cuadrtica. El siguiente cdigo muestra la implementacin de un filtro aclarador raz cuadrtica.
ITSON
576
Imgenes en Java
/** * Este metodo aumenta la brillantez de una imagen * utilizando una transformacion raiz cuadratica. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void aclaradoRaiz(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define una tabla de busqueda para aumentar la // brillantez de una imagen usando una transformacion // raiz cuadratica. short[] rootBrighten = new short[256]; for (int i = 0; i < 256; i++) { rootBrighten[i] = (short) (Math.sqrt((double) i / 255.0) * 255.0); } LookupTable table = new ShortLookupTable(0, rootBrighten); // crea una operacin de busqueda a partir de la tabla LookupOp op = new LookupOp(table, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
La figura 14.21 muestra la imagen original y la imagen aclarada usando un mapeo raz cuadrtica.
Posterizacin
El efecto de posterizacin es la reduccin del nmero de colores usados para desplegar una imagen. Para ello podemos usar una tabla de bsqueda que mapea valores de entrada a un conjunto pequeo de valores de salida. El siguiente cdigo muestra la implementacin de un filtro posterizador.
ITSON
Tema 14
Imgenes en Java
577
Figura 14.21. Abrillantando una imagen con un mapeo raz cuadrtica. Izquierda: Imagen original, derecha: Imagen aclarada.
/** * Este metodo reduce el maximo numero de colores de * 2^24 = 16777216 a 2^9 = 256. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void posterizar(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define una tabla de busqueda para reducir el maximo // numero de colores de 2^24 = 16777216 a 2^9 = 256. short[] posterize = new short[256]; for (int i = 0; i < 256; i++) { posterize[i] = (short) (i - (i % 32)); } LookupTable table = new ShortLookupTable(0, posterize); // crea una operacin de busqueda a partir de la tabla LookupOp op = new LookupOp(table, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
ITSON
578
Imgenes en Java
Figura 14.22. Posterizado de una imagen Izquierda: Imagen original, derecha: Imagen posterizada.
Binarizado
En esta operacin, se usan tres valores: un valor lmite, un valor mnimo y un valor mximo para controlar de los colores de cada pixel de la imagen. A los valores de un color por debajo del lmite se les asigna el valor mnimo. A los valores de un color por encima del lmite se les asigna el valor mximo. El siguiente cdigo muestra la implementacin de un filtro posterizador con un valor mnimo de 0, un valor mximo de 255. Por lo que la imagen resultante contendr slo los siguientes 8 colores: 1. 2. 3. 4. 5. 6. 7. 8. negro (rojo = 0, verde = 0, azul = 0) blanco (rojo = 255, verde = 255, azul = 255) rojo (rojo = 255, verde = 0, azul = 0) verde (rojo = 0, verde = 255, azul = 0) azul (rojo = 0, verde = 0, azul = 255) amarillo (rojo = 255, verde = 255, azul = 0) magenta (rojo = 255, verde = 0, azul = 255) cian (rojo = 0, verde = 255, azul = 255)
ITSON
Tema 14
Imgenes en Java
579
/** * Este metodo binariza una imagen reduciendo cada banda * de color a dos posibles valores 0 o 1, reduciendo el * numero de colores a 2^3 = 8. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void binarizar(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Define una tabla de busqueda para binarizar una imagen short[] threshold = new short[256]; for (int i = 0; i < 256; i++) { threshold[i] = (i < 128) ? (short) 0 : (short) 255; } LookupTable table = new ShortLookupTable(0, threshold); // crea una operacin de busqueda a partir de la tabla LookupOp op = new LookupOp(table, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
Figura 14.23. Binarizado de una imagen Izquierda: Imagen original, derecha: Imagen binarizada.
ITSON
580
Imgenes en Java
CS_LINEAR_RGB El espacio de color RGB predefinido. TYPE_CMY TYPE_CMYK Cualquiera de los espacios de color CMY. Cualquiera de los espacios de color CMYK.
Para obtener una instancia de la clase ColorSpace podemos utilizar uno de sus mtodos getInstance() cuya sintaxis se muestra en la tabla 14.13. Tabla 14.13 Mtodo getInstance de la clase ColorSpace
public static ColorSpace getInstance(int colorspace) Regresa un objeto del tipo ColorSpace representando uno de los espacios de color predefinidos.
La operacin para convertir los colores de un espacio de color a otro est representada por la clase ColorConvertOp. Los mtodos de la clase ColorConvertOp se muestran en la tabla 14.14. Tabla 14.14 Mtodos de la clase LookUpOp.
public ColorConvertOp(ColorSpace cspace, RenderingHints hints) Construye un objeto del tipo ColorConvertOp a partir de un objeto del tipo ColorSpace y una sugerencia de despliegue, la cual puede ser nula. public final BufferedImage filter(BufferedImage src, BufferedImage dst) Convierte el espacio de color de de la imagen bufereada dada por el parmetro src. Si el parmetro dst es null, se crear una nueva imagen con el modelo de color de la imagen fuente.
ITSON
Tema 14
Imgenes en Java
581
/** * Este metodo convierte una imagen de color a tonos de grises. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void toGrises(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Crea una operacion de conversion de colores para cambiar // de colores a tonos de grises ColorConvertOp op = new ColorConvertOp(ColorSpace. getInstance(ColorSpace.CS_GRAY), null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
Reescalamiento de Color
Esta operacin se utiliza para ajustar la brillantez de una imagen multiplicando cada componente de color de cada pixel por un factor de escala. La operacin para reescalar la brillantez de una imagen est representada por la clase RescaleOp. La clase soporta un desplazamiento adems del factor de
ITSON Manuel Domitsu Kono
582
Imgenes en Java
escala. Ese desplazamiento se le agrega al valor de la componente de color despus de escalarla. Los mtodos de la clase ColorConvertOp se muestran en la tabla 14.15. Tabla 14.15 Mtodos de la clase RescaleOp
public RescaleOp(float scaleFactor, float offset, RenderingHints hints) Construye un objeto del tipo RescaleOp con el factor de escala y desplazamiento deseados y una sugerencia de despliegue, la cual puede ser nula. El mismo escalamiento se aplica a todos las bandas de color. public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) Construye un objeto del tipo RescaleOp con los factores de escala y desplazamientos deseados y una sugerencia de despliegue, la cual puede ser nula. public final BufferedImage filter(BufferedImage src, BufferedImage dst) Escala la imagen bufereada dada por el parmetro src. Si el parmetro dst es null, se crear una nueva imagen con el modelo de color de la imagen fuente.
ITSON
Tema 14
Imgenes en Java
583
Figura 14.25. Izquierda: Imagen original, derecha: Imagen abrillantada 20%. El siguiente cdigo disminuye la brillantez de una imagen en un 20%.
/** * Este metodo disminuye la brillantez de una imagen en un 20%, * Haciendo un reescalamiento de colores. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void oscurece(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Crea una operacion de escalamiento para oscurecer una imagen // en 20% RescaleOp op = new RescaleOp(0.8f, 0, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
ITSON
584
Imgenes en Java
Figura 14.26. Izquierda: Imagen original, derecha: Imagen oscurecida 20%. El siguiente cdigo modifica la brillantez de una imagen, aclarando la banda roja un 20 %, oscureciendo la banda azul un 20% y dejando la banda verde sin modificar. .
/** * Este metodo modifica la brillantez de cada banda por separado * de una imagen, haciendo reescalamiento de colores. * @param frame Ventana sobre la que se despliega el mensaje de error */ public void ajustaBrillantezBandas(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Crea una operacion de escalamiento de color para aclarar // la banda roja un 20 % y oscurecer la banda azul un 20% // dejando la banda verde sin modificar RescaleOp op = new RescaleOp(new float[]{1.2f, 1.0f, 0.8f}, new float[]{32.0f, 0f, 0.0f}, null); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
ITSON
Tema 14
Imgenes en Java
585
La figura 14.27 muestra la imagen original y la imagen con las bandas modificadas en su brillantez por separado
Figura 14.27. Izquierda: Imagen original, derecha: Imagen con las bandas modificadas en su brillantez por separado.
Transformacin de Imgenes
Esta operacin transforma una imagen escalandola, rotndola o deformndola. Las transformaciones estn representadas por la clase AffineTransform. Esta clase define una serie de mtodos que regresan las diferentes transformaciones. Esos mtodos se muestran en la tabla 14.16. Tabla 14.16 Mtodo de la clase AffineTransform
public static AffineTransform getRotateInstance(double theta); Regresa una transformacin que rota la imagen alrededor del origen, el ngulo del parmetro en radianes. public static AffineTransform getRotateInstance(double theta, double anchorx, double anchory); Regresa una transformacin que rota la imagen alrededor de las coordenadas 8x, y), el ngulo del parmetro en radianes. public static AffineTransform getScaleInstance(double sx, double sy) Regresa una transformacin que escala las dimensiones de la imagen en los valores de sus parmetros.
ITSON
586
Imgenes en Java
La operacin para transformar una imagen est representada por la clase AffineTransformOp. Los mtodos de la clase ColorConvertOp se muestran en la tabla 14.17. Tabla 14.17 Mtodos de la clase AffineTransformOp.
public AffineTransformOp(AffineTransform xform, int interpolationType) Construye un objeto del tipo AffineTransformOp a partir de una transformacin y un tipo de interpolacin. public AffineTransformOp(AffineTransform xform, RenderingHints hints) Construye un objeto del tipo AffineTransformOp a partir de una transformacin y una sugerencia de despliegue, la cual puede ser nula. public final BufferedImage filter(BufferedImage src, BufferedImage dst) Transforma la imagen bufereada dada por el parmetro src. Si el parmetro dst es null, se crear una nueva imagen con el modelo de color de la imagen fuente.
La tabla 14.18 muestra las constantes que definen los tipos de interpolaci. Son constantes enteras estticas. Tabla 14.18 Tipos de interpolacin
Constante TYPE_BILINEAR TYPE_BICUBIC Interpolacin bilinear Interpolacin bicbica. Descripcin TYPE_NEAREST_NEIGHBOR Interpolacin del tipo vecino ms cercano..
ITSON
Tema 14
Imgenes en Java
587
if(!preparaImagenProcesar(frame)) return; // Crea una transformacion para aumentar el ancho de la imagen // en 20% y disminuir la altura en 20% AffineTransform at = AffineTransform.getScaleInstance(1.2, 0.8); RenderingHints rh = new RenderingHints( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); AffineTransformOp op = new AffineTransformOp(at, rh); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
La figura 14.28 muestra la imagen original y la imagen aumentada 20% en el eje de X y disminuida 20% en el eje Y.
Figura 14.28. Izquierda: Imagen original, derecha: Imagen aumentada 20% en el eje de X y disminuida 20% en el eje Y. El siguiente cdigo rota una imagen 60 alrededor de su centro.
/** * Este metodo rota una imagen en 60 grados alrededor de su centro. * haciendo una operacion de transformacion. * @param frame Ventana sobre la que se despliega el mensaje de error
ITSON
588
Imgenes en Java
*/ public void rota(JFrame frame) { // verifica que haya una imagen lista para ser procesada if(!preparaImagenProcesar(frame)) return; // Obtiene el tamao de la imagen int altoImagen = pbi.getHeight(); int anchoImagen = pbi.getWidth(); // Crea una transformacion para rotar una imagen en 60 grados // alrededor de su centro AffineTransform at = AffineTransform.getRotateInstance( Math.PI / 6, altoImagen/2, anchoImagen/2); RenderingHints rh = new RenderingHints( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); AffineTransformOp op = new AffineTransformOp(at, rh); // Filtra la imagen usando la operacion pbi = op.filter(pbi, null); // Hace que la referencia dbi apunte a obi dbi = pbi; }
Figura 14.29. Izquierda: Imagen original, derecha: Imagen rotada 60 alrededor de su centro.
ITSON