(O+P)ut

アウトプット



(O+P)ut

エンジニアのアウトプット

【Java】画像ファイルの画素を用いた部分抽出

スポンサーリンク

はじめに

画像ファイルの各画素を抜き出し、その情報と一致する箇所を部分抽出する処理を実施する流れの記載しました。Javaで利用しているパッケージは以下となります。

参考(import文)
  • java.awt.image.BufferedImage
  • java.io.*
  • javax.imageio.ImageIO

該当画像の画素情報を取得する

File f = new File("C:\\Users\\XXXX\\Downloads\\googlelogo.png");
BufferedImage read=ImageIO.read(f);
int w = read.getWidth();
int h = read.getHeight();

今回は以下のファイルを入力情報としました。
f:id:mtiit:20190816132741p:plain

横幅と高さを出力すると

System.out.println(w+" "+h);

以下のようになります。

960 465

ここからはこれらの画素情報をread.getRGBを用いて取得します。

単純に以下のように出力すると

for(int y=0;y<h;y++){
 for(int x=0;x<w;x++){
  System.out.println(read.getRGB(x, y));
 }
}

以下のように数値として出力されます。

-11959589
-11501877
-6833941
-1705217
-655363
-786433
-655361
-393730

これらをテキストファイルに吐き出して中身を確認すると

$ cat googlelogo.txt | wc
 446400  446400 2123508

ちなみにこの446400は先ほどの960x465の値です。

画素情報を分析する

画素の出現頻度を以下ワンライナーで取得します。

$ cat google.txt | sort | uniq -c | sort -n
.....
    401 -65537
    543 -131587
    548 -257
    580 -3
   2638 -802548
   3421 -65794
   5280 -12221716
   5784 -12797100
   6841 -2346697
 387244 -1

ちなみに最も多い値である「-1」は白色を表します。逆に黒色は「-16777216」あたりで表現されます。

先ほどの画像ファイルに対して該当の画素ファイルで絞りをかけて切り出してみます。

画素値による場合分け

入力情報と同じ大きさの出力画像用ファイルwriteを用意し

BufferedImage write = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

画素値で場合分けし合致した箇所を黒、合致しない箇所を「白」とし、

if(read.getRGB(x, y)==-1){
 write.setRGB(x,y,-16777216);
}
else{
 write.setRGB(x,y,-1);
}

最後に画像ファイルとして出力させます。

File f2 = new File("googlelogo_output.png");
ImageIO.write(write, "png", f2);


例えばこれらの実行結果は以下となります。
f:id:mtiit:20190816135213p:plain

つづいて上位であった「-2346697」での結果は以下です。
Gのロゴマークにおける赤色の一部分が抜き出せました。
f:id:mtiit:20190816135831p:plain

今回は絶対値の一致という厳しい条件で抜き出したので縁取りが甘いですが、以下記事で実施したようなR、G、Bのそれぞれの値を抜き出してクラスタリングを行えばもう少し綺麗に行えそうです。

画像データあるあるですが、原画像を標本化/量子化する際の濃淡の発生が縁部分を切り抜けなかった原因です。

終わりに

画像処理であればOpenCV等を用いてMatlabなどの専用言語でいじることが多いとは思いますが、Javaは企業のパソコンにもインストールがされていたりと使える場面が多いです。
Javaで画像処理をするケースがどの程度あるのかは分かりませんが、同様のことに興味がある方の参考になれば幸いです。