はじめに
画像ファイルの各画素を抜き出し、その情報と一致する箇所を部分抽出する処理を実施する流れの記載しました。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();
今回は以下のファイルを入力情報としました。
横幅と高さを出力すると
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);
例えばこれらの実行結果は以下となります。
つづいて上位であった「-2346697」での結果は以下です。
Gのロゴマークにおける赤色の一部分が抜き出せました。
今回は絶対値の一致という厳しい条件で抜き出したので縁取りが甘いですが、以下記事で実施したようなR、G、Bのそれぞれの値を抜き出してクラスタリングを行えばもう少し綺麗に行えそうです。
画像データあるあるですが、原画像を標本化/量子化する際の濃淡の発生が縁部分を切り抜けなかった原因です。
終わりに
画像処理であればOpenCV等を用いてMatlabなどの専用言語でいじることが多いとは思いますが、Javaは企業のパソコンにもインストールがされていたりと使える場面が多いです。
Javaで画像処理をするケースがどの程度あるのかは分かりませんが、同様のことに興味がある方の参考になれば幸いです。