JavaRush /Blog Java /Random-ES /World of Bytes 1. Trabajar con imágenes.
Joysi
Nivel 41

World of Bytes 1. Trabajar con imágenes.

Publicado en el grupo Random-ES
Especial para Antes de esto, lo expliqué con ejemplos secos. Pidieron trabajar con imágenes, consíguelo.
Establecer una tarea de aprendizaje.
Dado un archivo gráfico (jpeg, png...). Es necesario realizar algunas manipulaciones con él y escribir el resultado en otro archivo. Para simplificar, consideremos tres tareas: - obtener una imagen negativa - obtener una versión en blanco y negro de la imagen (restablecer el color) - cambiar la saturación del verde en la imagen. Tenga en cuenta que de manera similar podemos, agregando nuevos métodos, implementar otras tareas: - aumentar la nitidez o el desenfoque - cambiar las dimensiones - rotar en sentido horario o antihorario. - y otras posibilidades de Photoshop :) en general, implementar cualquier algoritmo en la imagen, siempre que tengamos suficiente imaginación y conocimiento de matan (por ejemplo, reconocer el número de gatos posibles en la imagen).
Una pequeña teoría seca.
Estamos considerando imágenes rasterizadas (también las hay vectoriales y otras). Es decir, cuando el archivo, además del propio encabezado con información del servicio, almacena una matriz rectangular de puntos. Similar a la pantalla de un televisor HD moderno, que tiene una resolución de 1920x1080 píxeles y cada píxel se representa como los valores de tres componentes de color: R(ed), G(verde), B(lue) = Rojo, Verde y azul. Estos colores son independientes y este modelo está tomado de la biología de la percepción del color. En el ojo tenemos conos y bastones. Los conos de tres variedades (reaccionan al correspondiente de los tres rangos de longitud de onda), los bastones "procesan" el brillo del color (la amplitud de la onda de luz). En el modelo RGB, las varillas son responsables del valor del componente (0 - ausencia, 255 - la luz más brillante) y los conos - respectivamente, en cuál de los R / G / B colocar la intensidad correspondiente. Por ejemplo: Falta de luz: los bastones/conos no reaccionan y RGB = (0,0,0). Luz blanca brillante: todos los conos reaccionan de manera uniforme, los bastones se vuelven locos y RGB = (255,255,255). El ratón gris lo atravesó: todos los conos reaccionaron de manera uniforme, los bastones reaccionaron de manera promedio y RGB = (127,127,127). Naranja oscuro: los sticks R y G reaccionan, los sticks apenas responden, RGB=(30, 30, 0)...
Empecemos a practicar.
Escribí un ejemplo de cómo trabajar con bytes, por lo que el código no está pulido de acuerdo con todas las reglas y está lejos de ser óptimo: no verificamos los parámetros de entrada, no realizamos una verificación completa de errores, etc. Fue escrito de forma sencilla, sin refactorización. El objetivo principal es trabajar con bytes-bits. Escribamos, por analogía con las tareas de JavaRush, una utilidad de consola que, cuando se llama en la línea de comando con los argumentos apropiados, modifica la imagen. Imagen de origen: gatito
llamar con parámetros -n gatito.jpg newkitten.jpg creará una imagen: negativo
llamar con parámetros -b gatito.jpg newkitten.jpg creará una imagen: gatito blanco y negro
llamar con parámetros -gr gatito.jpg newkitten.jpg creará una imagen : crepúsculo
En realidad, eso es todo .
package com.joysi.byteworld; import com.sun.imageio.plugins.jpeg.*; import com.sun.imageio.plugins.png.*; import javax.imageio.*; import javax.imageio.stream.*; import java.awt.image.BufferedImage; import java.io.*; public class image { public static void main(String[] args) throws IOException { CoolImage picture = new CoolImage(args[1]); // загружаем файл изображения if ("-n".equals(args[0])) picture.convertToNegative(); if ("-g".equals(args[0])) picture.addColorGreenChannel(-100); if ("-bw".equals(args[0])) picture.convertToBlackAndWhite(); picture.saveAsJpeg(args[2]); } public static class CoolImage{ private int height; // высота изображения private int width; // ширина изображения private int[] pixels; // собственно массив цветов точек составляющих изображение public int getPixel(int x, int y) { return pixels[y*width+x]; } // получить пиксель в формате RGB public int getRed(int color) { return color >> 16; } // получить красную составляющую цвета public int getGreen(int color) { return (color >> 8) & 0xFF; } // получить зеленую составляющую цвета public int getBlue(int color) { return color & 0xFF;} // получить синюю составляющую цвета // Конструктор - создание изображения из archivo public CoolImage(String fileName) throws IOException { BufferedImage img = readFromFile(fileName); this.height = img.getHeight(); this.width = img.getWidth(); this.pixels = copyFromBufferedImage(img); } // Чтение изображения из archivo в BufferedImage private BufferedImage readFromFile(String fileName) throws IOException { ImageReader r = new JPEGImageReader(new JPEGImageReaderSpi()); r.setInput(new FileImageInputStream(new File(fileName))); BufferedImage bi = r.read(0, new ImageReadParam()); ((FileImageInputStream) r.getInput()).close(); return bi; } // Формирование BufferedImage из массива pixels private BufferedImage copyToBufferedImage() { BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) bi.setRGB(j, i, pixels[i*width +j]); return bi; } // Формирование массива пикселей из BufferedImage private int[] copyFromBufferedImage(BufferedImage bi) { int[] pict = new int[height*width]; for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) pict[i*width + j] = bi.getRGB(j, i) & 0xFFFFFF; // 0xFFFFFF: записываем только 3 младших byteа RGB return pict; } // Запись изображения в jpeg-формате public void saveAsJpeg(String fileName) throws IOException { ImageWriter writer = new JPEGImageWriter(new JPEGImageWriterSpi()); saveToImageFile(writer, fileName); } // Запись изображения в png-формате (другие графические форматы по аналогии) public void saveAsPng(String fileName) throws IOException { ImageWriter writer = new PNGImageWriter(new PNGImageWriterSpi()); saveToImageFile(writer, fileName); } // Собственно запись archivo (общая для всех форматов часть). private void saveToImageFile(ImageWriter iw, String fileName) throws IOException { iw.setOutput(new FileImageOutputStream(new File(fileName))); iw.write(copyToBufferedImage()); ((FileImageOutputStream) iw.getOutput()).close(); } // конвертация изображения в негатив public void convertToNegative() { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) // Применяем логическое отрицание и отбрасываем старший byte pixels[i*width + j] = ~pixels[i*width + j] & 0xFFFFFF; } // конвертация изображения в черно-белый вид public void convertToBlackAndWhite() { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { // находим среднюю арифметическую интенсивность пикселя по всем цветам int intens = (getRed(pixels[i * width + j]) + getGreen(pixels[i * width + j]) + getBlue(pixels[i * width + j])) / 3; // ... и записываем ее в каждый цвет за раз , сдвигая byteы RGB на свои места pixels[i * width + j] = intens + (intens << 8) + (intens << 16); } } // изменяем интесивность зеленого цвета public void addColorGreenChannel(int delta) { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { int newGreen = getGreen(pixels[i * width + j]) + delta; if (newGreen > 255) newGreen=255; // Отсекаем при превышении границ byteа if (newGreen < 0) newGreen=0; // В итоговом пикселе R и B цвета оставляем без изменений: & 0xFF00FF // Полученный новый G (зеленый) засунем в "серединку" RGB: | (newGreen << 8) pixels[i * width + j] = pixels[i * width + j] & 0xFF00FF | (newGreen << 8); } } } }
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION