拙作マンホールマップの隠し(?)機能でも使っている手法の1つを紹介します。

マンホールマップで特定のマンホール画像を表示すると、このような画面になります(PC版の場合):

http://manholemap.juge.me/page.jsp?id=1125001 の例
2018030401


http://manholemap.juge.me/page.jsp?id=157009 の例
2018030402


注目していただきたいのは地図部分ではなくマンホール画像部分です。画像が色の付いた枠(上は青枠、下は赤枠)で囲われていることにお気づきでしょうか?

これ、実は画像全体の色味を表しています。つまり上の画像は「全体的に青っぽい」、下の画像は「全体的に赤っぽい」ことを自動判断して表示しているのです。なんとなく合ってます(よね)。実際のアプリケーションでは赤、青、緑、黄、紫、そしてマジェンタの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ピクセル毎に取り出して判断することができるようになります。