JavaRush /Blogue Java /Random-PT /Mundo dos Bytes 1. Trabalhando com imagens.
Joysi
Nível 41

Mundo dos Bytes 1. Trabalhando com imagens.

Publicado no grupo Random-PT
Especial para Antes disso, expliquei com exemplos áridos. Eles pediram para trabalhar com imagens - entenda.
Definir uma tarefa de aprendizagem.
Dado um arquivo gráfico (jpeg, png...). É necessário fazer algumas manipulações e gravar o resultado em outro arquivo. Para simplificar, vamos considerar três tarefas: - obter uma imagem negativa - obter uma versão em preto e branco da imagem (redefinir a cor) - alterar a saturação do verde na imagem. Observe que de forma semelhante podemos, adicionando novos métodos, implementar outras tarefas: - aumentar a nitidez ou desfoque - alterar dimensões - girar no sentido horário/anti-horário. - e outras possibilidades do Photoshop :) em geral, implementamos qualquer algoritmo na imagem, desde que tenhamos imaginação e conhecimento suficientes de matan (por exemplo, reconheça a quantidade de gatos possíveis na imagem).
Um pouco de teoria seca.
Estamos considerando imagens raster (também existem imagens vetoriais e outras). Ou seja, quando o arquivo, além do próprio cabeçalho com informações do serviço, armazena uma matriz retangular de pontos. Semelhante à tela de uma TV HD moderna, que tem resolução de 1920x1080 pixels e cada pixel é representado como os valores de três componentes de cor: R(ed), G(reen), B(lue) = Vermelho, Verde e Azul. Essas cores são independentes e este modelo é retirado da biologia da percepção das cores. No olho temos cones e bastonetes. Cones de três variedades (reagem à correspondente das três faixas de comprimento de onda), os bastonetes “processam” o brilho da cor (a amplitude da onda de luz). No modelo RGB, os bastonetes são responsáveis ​​pelo valor do componente (0 - ausência, 255 - luz mais brilhante), e os cones - respectivamente, em qual dos R/G/B colocar a intensidade correspondente. Por exemplo: Falta de luz - bastonetes/cones não reagem e RGB = (0,0,0). Luz branca brilhante - todos os cones reagem uniformemente, os bastonetes enlouquecem e RGB = (255.255.255). O rato cinza passou - todos os cones reagiram uniformemente, os bastonetes reagiram medianamente e RGB = (127.127.127). Laranja escuro - os bastões R e G reagem, os bastões mal respondem, RGB=(30, 30, 0) ...
Vamos começar a praticar.
Escrevi um exemplo de trabalho com bytes, portanto o código não é polido de acordo com todas as regras e está longe de ser ideal: não verificamos parâmetros de entrada, não fazemos verificação completa de erros, etc. Foi escrito de forma direta, sem refatoração. O foco principal é trabalhar com bytes-bits. Vamos escrever, por analogia com as tarefas JavaRush, um utilitário de console que, quando chamado na linha de comando com os argumentos apropriados, modifica a imagem. Imagem de origem: gatinha
chamar com parâmetros -n gatinho.jpg newkitten.jpg criará uma imagem: negativo
chamar com parâmetros -b gatinho.jpg newkitten.jpg criará uma imagem: gatinho preto e branco
chamar com parâmetros -gr gatinho.jpg newkitten.jpg criará uma imagem : crepúsculo
Na verdade, é isso .
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;} // получить синюю составляющую цвета // Конструктор - создание изображения из file public CoolImage(String fileName) throws IOException { BufferedImage img = readFromFile(fileName); this.height = img.getHeight(); this.width = img.getWidth(); this.pixels = copyFromBufferedImage(img); } // Чтение изображения из file в 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); } // Собственно запись file (общая для всех форматов часть). 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); } } } }
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION