拙作マンホールマップの隠し(?)機能でも使っている手法の1つを紹介します。
マンホールマップで特定のマンホール画像を表示すると、このような画面になります(PC版の場合):
http://manholemap.juge.me/page.jsp?id=1125001 の例
http://manholemap.juge.me/page.jsp?id=157009 の例
注目していただきたいのは地図部分ではなくマンホール画像部分です。画像が色の付いた枠(上は青枠、下は赤枠)で囲われていることにお気づきでしょうか?
これ、実は画像全体の色味を表しています。つまり上の画像は「全体的に青っぽい」、下の画像は「全体的に赤っぽい」ことを自動判断して表示しているのです。なんとなく合ってます(よね)。実際のアプリケーションでは赤、青、緑、黄、紫、そしてマジェンタの6種類のいずれかと判断しています。
これをどうやって実現しているか、というのが今回のネタです。
マンホールマップは Java で開発していて、特にこの部分は Java の拡張クラスである ImageIO (javax.imageio.ImageIO)を使っています。具体的にはこのようなコードです:
この例では画像バイナリのバイト配列( byte[] img )を引数として受け取る GetImageColor() 関数を定義しています。その中でまず ImageIO.read を使って、画像の BufferedImage を取り出します。
正しく取り出すことができたら、画像の幅と高さをピクセル単位で取得し、2重の for ループ内で1ピクセルずつ BufferedImage.getRGB 関数を実行し、RGB 値を取り出す、という処理を実行しています。これで1ピクセル毎の RGB 値を取り出すことができます。
あとはこの結果から、赤、青、緑、黄、紫、そしてマジェンタのどの色が多く使われているか、、、を調べるわけですが、そのあたりの細かなアルゴリズムは秘密(というか面倒なので省略)、ということで(苦笑)。
ちなみに白と黒が含まれていない理由は「マンホールの色が黒(または白)」というのは「普通過ぎてつまらないから、黒と白を除いて近い色を探す」という工夫をしているからでした。
この方法を応用することで、色んな画像の色情報(RGB値)を1ピクセル毎に取り出して判断することができるようになります。
マンホールマップで特定のマンホール画像を表示すると、このような画面になります(PC版の場合):
http://manholemap.juge.me/page.jsp?id=1125001 の例
http://manholemap.juge.me/page.jsp?id=157009 の例
注目していただきたいのは地図部分ではなくマンホール画像部分です。画像が色の付いた枠(上は青枠、下は赤枠)で囲われていることにお気づきでしょうか?
これ、実は画像全体の色味を表しています。つまり上の画像は「全体的に青っぽい」、下の画像は「全体的に赤っぽい」ことを自動判断して表示しているのです。なんとなく合ってます(よね)。実際のアプリケーションでは赤、青、緑、黄、紫、そしてマジェンタの6種類のいずれかと判断しています。
これをどうやって実現しているか、というのが今回のネタです。
マンホールマップは Java で開発していて、特にこの部分は Java の拡張クラスである ImageIO (javax.imageio.ImageIO)を使っています。具体的にはこのようなコードです:
: public String GetImageColor( byte[] img ){ String r = null; : if( img != null ){ BufferedImage image = null; try{ InputStream is = new ByteArrayInputStream( img ); image = ImageIO.read( is ); }catch( IOException e ){ } if( image != null ){ //. 画像の大きさをチェック int w = image.getWidth(); int h = image.getHeight(); //. 1ピクセルずつ色を取り出す for( int x = 0; x < w; x ++ ){ for( int y = 0; y < h; y ++ ){ //. 特定ピクセルの RGB 情報を取り出す int rgb = image.getRGB( x, y ); : } } }else{ } } return r; } :
この例では画像バイナリのバイト配列( byte[] img )を引数として受け取る GetImageColor() 関数を定義しています。その中でまず ImageIO.read を使って、画像の BufferedImage を取り出します。
正しく取り出すことができたら、画像の幅と高さをピクセル単位で取得し、2重の for ループ内で1ピクセルずつ BufferedImage.getRGB 関数を実行し、RGB 値を取り出す、という処理を実行しています。これで1ピクセル毎の RGB 値を取り出すことができます。
あとはこの結果から、赤、青、緑、黄、紫、そしてマジェンタのどの色が多く使われているか、、、を調べるわけですが、そのあたりの細かなアルゴリズムは秘密(というか面倒なので省略)、ということで(苦笑)。
ちなみに白と黒が含まれていない理由は「マンホールの色が黒(または白)」というのは「普通過ぎてつまらないから、黒と白を除いて近い色を探す」という工夫をしているからでした。
この方法を応用することで、色んな画像の色情報(RGB値)を1ピクセル毎に取り出して判断することができるようになります。