2015年3月1日日曜日

javaで画像処理する方法

画像処理は計算に時間かかるから普通はCとかでするんだけど、javaであえて書いてみる!
対象は「人によって青&黒または白&金に見える」って話題になったこのドレスの画像で

画像の仕組み

画像とは大量の点からできている
画像の情報を見るとき、下のかけ算をよくみると思うけどコレがこの画像を表示するための点の数

上記画像は、横方向に288個、縦方向に437個。つまり、125856個の点で構成されているってこと

この点を「ピクセル」といい、色の情報を持ってる
一般的にはピクセルは4Byteで表されてるんだけど、振り分けはこんな感じ
ビット00000000000000000000000000000000
意味
透過率
透過率はまぁいいとして、 それぞれ赤、青、緑を色深度を0x00〜0xFF(16進表記)で表してる
色深度は数値が低いほど暗い。例として、下記に示す※透過はFFとしておく
色の情報表示される色表示される色
0xFFFF0000赤(純粋)   
0xFF000100青(めっちゃ暗い)   
0xFFFF00FFマゼンダ(赤と緑を混ぜた色)   
こんな感じで、すべての色を赤青緑でつくってることになる

実装

javaには最初から画像処理するためのクラスがあるので、ダウンロードとかいらない。インポートさえすれば使える 一例に、画像を少し暗くする
/** ImageTest.java  画像を少し暗くする処理 */
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
 
public class ImageTest {
     
    final static String INPUT_IMAGE = "image.jpg";// 読み込み画像(このjavaファイルと同じフォルダに入れとく)
    final static String OUTPUT_IMAGE = "reslt.jpg";// 出力する画像(このjavaファイルと同じフォルダに出力される)
     
    public static void main(String[] args) throws IOException {
         
        // 画像読み込み
        File in_file = new File(INPUT_IMAGE);
        BufferedImage read = ImageIO.read(in_file);
         
        // 情報取得 w, hは縦、横のピクセル数。writeは画像の1ピクセルごとにアクセスできるようにしてる
        int w = read.getWidth(),h=read.getHeight();
        BufferedImage write =
        new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
         
        // 格ピクセルに処理していく
        for(int y=0; y < h; y++) {
            for(int x = 0; x < w; x++) {
                // 色抽出
                int color = read.getRGB(x, y); // 座標の色を取得
                int red   = (color & 0xff0000) >> 16; // 赤抽出
                int green = (color & 0x00ff00) >> 8;  // 緑抽出
                int blue  = (color & 0x0000ff) >> 0;  // 青抽出
                 
                // 色の情報変換
                red   = red / 2;   // 赤色の色深度を半分にする
                green = green / 2; // 緑色の色深度を半分にする
                blue  = blue / 2;  // 青色の色深度を半分にする
   
                // 出力用にフォーマット
                red  =(red << 16)  & 0xff0000;
                green=(green << 8) & 0x00ff00;
                blue =(blue << 0)  & 0x0000ff;
                color = 0xff000000 | red | green | blue;
                write.setRGB(x, y, color); // 情報変換した色をもとの座標に戻す
            }
        }
         
        // 画像の出力
        File out_file = new File(OUTPUT_IMAGE);
        ImageIO.write(write, "jpg", out_file);
    }
}
結果はこんな感じ
ポイントは色ついてるとこ(32~34行目)。それぞれの色を半分にすることで、暗くできる

応用

ポイント部分を変えることで、いろんなことができる
赤のみ抽出
// 色の情報変換
red   = red; // 赤はそのまま
green = 0;   // 緑は0にする
blue  = 0;   // 青は0にする
青のみ抽出
// 色の情報変換
red   = 0;   // 赤は0にする
green = 0;   // 緑は0にする
blue  = blue;// 青はそのまま
緑のみ抽出
// 色の情報変換
red   = 0;     // 赤は0にする
green = green; // 緑はそのまま
blue  = 0;     // 青は0にする
ビット反転
// 色の情報変換
red   = ~red;   // ビット反転
green = ~green; // ビット反転
blue  = ~blue;  // ビット反転


出力結果
赤抽出青抽出緑抽出ビット反転
ビット反転すると写真のネガみたいになる
不思議なことにビット反転すると白&金になるんだよねw
他にもモザイクをかけたり、色のヒストグラムとったりなどいろいろできるけど、今回はこれまでで

0 件のコメント:

コメントを投稿