JavaRush /Java Blog /Random-IT /Mondo di byte 1. Lavorare con le immagini.
Joysi
Livello 41

Mondo di byte 1. Lavorare con le immagini.

Pubblicato nel gruppo Random-IT
Speciale per Prima di questo, ho spiegato con esempi aridi. Hanno chiesto di lavorare con le immagini: prendilo.
Impostazione di un compito di apprendimento.
Dato un file grafico (jpeg, png...). È necessario eseguire alcune manipolazioni e scrivere il risultato in un altro file. Per semplificare, consideriamo tre attività: - ottenere un'immagine negativa - ottenere una versione in bianco e nero dell'immagine (reimpostare il colore) - modificare la saturazione del verde nell'immagine. Si noti che in modo simile possiamo, aggiungendo nuovi metodi, implementare altre attività: - aumentare la nitidezza o la sfocatura - modificare le dimensioni - ruotare in senso orario/antiorario. - e altre possibilità di Photoshop :) in generale, implementiamo qualsiasi algoritmo sull'immagine, purché abbiamo abbastanza immaginazione e conoscenza di matan (ad esempio, riconosciamo il numero di possibili gatti nella foto).
Una piccola teoria secca.
Stiamo considerando le immagini raster (ci sono anche vettoriali e altre). Cioè, quando il file, oltre all'intestazione stessa con le informazioni sul servizio, memorizza una matrice rettangolare di punti. Simile allo schermo di un moderno televisore HD, che ha una risoluzione di 1920x1080 pixel e ogni pixel è rappresentato come i valori di tre componenti di colore: R(ed), G(reen), B(lue) = Red, Green e Blu. Questi colori sono indipendenti e questo modello è tratto dalla biologia della percezione del colore. Negli occhi abbiamo coni e bastoncelli. Coni di tre varietà (reagiscono al corrispondente dei tre intervalli di lunghezza d'onda), i bastoncini “elaborano” la luminosità del colore (l'ampiezza dell'onda luminosa). Nel modello RGB, i bastoncelli sono responsabili del valore della componente (0 - assenza, 255 - la luce più brillante) e i coni - rispettivamente, in quale R / G / B posizionare l'intensità corrispondente. Ad esempio: Mancanza di luce - i bastoncelli/coni non reagiscono e RGB = (0,0,0). Luce bianca brillante: tutti i coni reagiscono in modo uniforme, i bastoncelli impazziscono e RGB = (255.255.255). Il topo grigio correva attraverso: tutti i coni hanno reagito in modo uniforme, i bastoncelli hanno reagito mediamente e RGB = (127.127.127). Arancione scuro: gli stick R e G reagiscono, gli stick rispondono a malapena, RGB=(30, 30, 0) ...
Iniziamo a praticare.
Ho scritto per un esempio di lavoro con i byte, quindi il codice non è lucidato secondo tutte le regole ed è tutt'altro che ottimale: non controlliamo i parametri di input, non eseguiamo il controllo completo degli errori, ecc. È stato scritto direttamente, senza refactoring. L'obiettivo principale è lavorare con byte-bit. Scriviamo, per analogia con i task JavaRush, un'utility della console che, quando richiamata sulla riga di comando con gli argomenti appropriati, modifica l'immagine. Immagine sorgente: Gattino
chiamando con i parametri -n gattino.jpg nuovo gattino.jpg creerà un'immagine: negativo
chiamando con i parametri -b gattino.jpg nuovo gattino.jpg creerà un'immagine: gattino bianco e nero
chiamando con i parametri -gr gattino.jpg nuovo gattino.jpg creerà un'immagine : crepuscolo
In realtà, è così .
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); } } } }
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION