JavaRush /Java Blog /Random-JA /World of Bytes 1. 画像の操作。
Joysi
レベル 41

World of Bytes 1. 画像の操作。

Random-JA グループに公開済み
以下のための特別な この前に、乾いた例を使って説明しました。彼らは画像を扱うよう求めました - それはわかります。
学習課題の設定。
グラフィック ファイル (jpeg、png...) を指定します。これに対していくつかの操作を行い、結果を別のファイルに書き込む必要があります。単純化するために、次の 3 つのタスクを考えてみましょう: - ネガ画像を取得します - 画像の白黒バージョンを取得します (色をリセットします) - 画像内の緑の彩度を変更します。同様の方法で、新しいメソッドを追加することで、次のタスクを実装できることに注意してください。 - シャープネスまたはブラーを増加する - 寸法を変更する - 時計回り/反時計回りに回転する。- および Photoshop のその他の可能性:) 一般に、十分な想像力とマタンの知識がある限り、画像に任意のアルゴリズムを実装します (たとえば、写真内に存在する可能性のある猫の数を認識します)。
ちょっと辛口な理論。
ラスター画像を検討しています(ベクター画像などもあります)。つまり、ファイルには、サービス情報を含むヘッダー自体に加えて、点の長方形マトリックスが格納されます。最新の HD TV の画面と同様、解像度は 1920x1080 ピクセルで、各ピクセルは 3 つの色成分の値として表されます: R(ed)、G(reen)、B(lue) = 赤、緑そしてブルー。これらの色は独立しており、このモデルは色知覚の生物学に基づいています。目には錐体と桿体があります。3 種類の錐体 (3 つの波長範囲の対応する 1 つに反応)、桿体は色の明るさ (光波の振幅) を「処理」します。RGB モデルでは、桿体はコンポーネントの値 (0 - 不在、255 - 最も明るい光)、および錐体 - をそれぞれ担当し、R / G / B のどの値に対応する強度を配置します。例: 光不足 - 桿体/錐体は反応せず、RGB = (0,0,0)。明るい白色光 - すべての錐体は均等に反応し、杆体はおかしくなり、RGB = (255,255,255)。灰色のマウスが走り抜けました。すべての錐体は均等に反応し、杆体は平均的に反応し、RGB = (127,127,127) でした。濃いオレンジ色 - R スティックと G スティックは反応しますが、スティックはほとんど反応しません、RGB=(30, 30, 0) ...
練習を始めましょう。
バイトを扱う例として書いたので、コードはすべてのルールに従って洗練されておらず、最適とは程遠いものです。入力パラメータのチェックや完全なエラー チェックなどは行いません。リファクタリングせずに直接書かれました。主な焦点はバイトビットの処理です。JavaRush タスクと同様に、適切な引数を指定してコマンドラインで呼び出すとイメージを変更するコンソール ユーティリティを作成してみましょう。 ソース画像: キティ
パラメータ -n kitten.jpg newkitten.jpg を指定して呼び出すと画像が作成されます: ネガティブ
パラメータ -b kitten.jpg newkitten.jpg を指定して呼び出す 黒と白の子猫
と画像が作成されます: パラメータ -gr kitten.jpg newkitten.jpg を指定して呼び出すと画像が作成されます: トワイライト
実はそれだけなんです
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); } } } }
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION