JavaRush /Java Blog /Random-ID /World of Bytes 1. Bekerja dengan gambar.
Joysi
Level 41

World of Bytes 1. Bekerja dengan gambar.

Dipublikasikan di grup Random-ID
Spesial untuk Sebelumnya saya jelaskan dengan contoh kering. Mereka meminta untuk bekerja dengan gambar - mengerti.
Menetapkan tugas belajar.
Diberikan file grafik (jpeg, png...). Anda perlu melakukan beberapa manipulasi dengannya dan menulis hasilnya ke file lain. Untuk menyederhanakan, mari kita pertimbangkan tiga tugas: - mendapatkan gambar negatif - mendapatkan versi gambar hitam putih (mengatur ulang warna) - mengubah saturasi warna hijau pada gambar. Perhatikan bahwa dengan cara serupa kita dapat, dengan menambahkan metode baru, menerapkan tugas lain: - meningkatkan ketajaman atau keburaman - mengubah dimensi - memutar searah/berlawanan arah jarum jam. - dan kemungkinan lain dari Photoshop :) secara umum, terapkan algoritma apa pun pada gambar, sejauh kita memiliki cukup imajinasi dan pengetahuan tentang matan (misalnya, kenali jumlah kemungkinan kucing dalam gambar).
Sedikit teori kering.
Kami sedang mempertimbangkan gambar raster (ada juga vektor dan lainnya). Artinya, ketika file, selain header itu sendiri dengan informasi layanan, menyimpan matriks titik persegi panjang. Mirip dengan layar TV HD modern yang memiliki resolusi 1920x1080 piksel dan setiap piksel direpresentasikan sebagai nilai tiga komponen warna: R(ed), G(reen), B(lue) = Merah, Hijau dan Biru. Warna-warna ini bersifat independen dan model ini diambil dari biologi persepsi warna. Pada mata kita terdapat kerucut dan batang. Kerucut dari tiga jenis (bereaksi terhadap salah satu dari tiga rentang panjang gelombang yang sesuai), batang “memproses” kecerahan warna (amplitudo gelombang cahaya). Dalam model RGB, batang bertanggung jawab atas nilai komponen (0 - tidak adanya, 255 - cahaya paling terang), dan kerucut - masing-masing, di R / G / B mana untuk menempatkan intensitas yang sesuai. Misal: Kurang cahaya - batang/kerucut tidak bereaksi dan RGB = (0,0,0). Cahaya putih terang - semua kerucut bereaksi secara merata, batang menjadi gila dan RGB = (255.255.255). Tikus abu-abu berlari melewatinya - semua kerucut bereaksi secara merata, batang bereaksi rata-rata dan RGB = (127.127.127). Oranye tua - Stik R dan G bereaksi, stik hampir tidak merespons, RGB=(30, 30, 0) ...
Mari kita mulai berlatih.
Saya menulis contoh bekerja dengan byte, sehingga kode tidak dipoles sesuai dengan semua aturan dan jauh dari optimal: kami tidak memeriksa parameter input, tidak melakukan pemeriksaan kesalahan penuh, dll. Itu ditulis langsung, tanpa refactoring. Fokus utamanya adalah bekerja dengan byte-bit. Mari kita tulis, dengan analogi dengan tugas JavaRush, sebuah utilitas konsol yang, ketika dipanggil pada baris perintah dengan argumen yang sesuai, akan mengubah gambar. Sumber gambar: kucing
memanggil dengan parameter -n Kitten.jpg newkitten.jpg akan membuat gambar: negatif
memanggil dengan parameter -b Kitten.jpg newkitten.jpg akan membuat gambar: anak kucing hitam dan putih
Memanggil dengan parameter -gr Kitten.jpg newkitten.jpg akan membuat gambar : senja
Sebenarnya itu saja .
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); } } } }
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION