[kaneko lab.]
  1. 金子邦彦研究室
  2. 画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める

    画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める Octave のプログラム例を示す.

    前準備

    Octave のインストールが済んでいること.

    必見 Web ページ: http://www.csse.uwa.edu.au/~pk/Research/MatlabFns/

    必見 Web ページ: http://www.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/

    * プロンプトを変えたいときは,次のように操作する.

    PS1('> ')
    

    * Octave のインストールによっては,Octave の起動時に毎回次の操作を行う必要があるかもしれない

    pkg load image
    

    処理方法の説明

    画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求めることを行いたいとします.以下に処理方法の例を説明する.

    * プログラムのソースコード全体は,この Web ページの後半に載せています.

    1. 画像ファイルを変数 rgb に読み込み
      [rgb, immap, alpha] = imread("/tmp/DSC_0015.JPG");
      

      * Windows では「imread("t:/DSC_0015.JPG");」のようにしてください.

      * 読み込み結果は「imshow( imresize( rgb, 0.2 ) );」のようなコマンドで簡単に表示できる. ここで「0.2」とあるのは倍率のこと.元の画像が大きいと Octave で表示できないことがあるので,「0.2」 のようにしている.

      元画像の例

    2. RGB 画像を濃淡画像に変換
      mono = rgb2gray( rgb );
      

      濃淡画像の例

    3. 濃淡画像を 2 値画像に変換

      「- 0.2」を付けているのは,境界の部分をきれいに出すための調整です. 「- 0.2」の 0.2 の値は,何度か 2 値画像を作ってみて調整する必要があるでしょう. つまり,完全に自動ではできず,手動での調整が必要だということです.

      bw = im2bw(mono, graythresh( mono ) - 0.2);
      

      2 値画像の例

    4. 2 値画像での小さな黒の塊の除去や,境界のぎざぎざの調整 (モルフォロジカル演算を利用)

      「4」に指定しているのは,半径 4 以下の黒の塊を除去したりなどしたいという意味です. 「4」で良いかどうかは,画像の種類によって変わります. 実際に作ってみて,「4」という値を調整する必要があるでしょう.

      bw2 = bwmorph( bwmorph( bw, "dilate", 4 ), "erode", 4 );
      

      2 値画像の例

    5. (参考) 隣接領域を抽出(画像の中心から出発)

      ここに載せている画像(魚眼カメラ画像)では関係ないですが, 出来た2値画像が複数の部分に分かれているとき, 画像の中心から出発し,隣接する画像(白色の画像)をつなげていき,大きな領域を作るという方法により, 主要部分を抜き出すということを行うことがあります.

      bw3 = bwselect( bw2, width/2, height/2 );
      
    6. 画素が白(値は 1)になっている領域を囲む長方形を求める

      白画素の x, y 座標の最小値と最大値を求めることで, 画素が白(値は 1)になっている領域を囲む長方形が求まったことになる.

      ここでは,Octave なので,for 文を使わない流儀で書いてみます.

      # 右上が (min_x, min_y), 左下が (max_x, max_y)
      height = size(bw3)(1);
      width = size(bw3)(2);
      
      [XX1, YY1] = meshgrid([1:1:width], [1:1:height]);
      max_x = max( max( bw3 .* XX1 ) );
      max_y = max( max( bw3 .* YY1 ) );
      fdisp(stderr, "upper-left point ...");
      
      [XX2, YY2] = meshgrid([width:-1:1], [height:-1:1]);
      min_x = width -  ( max( max( bw3 .* XX2 ) ) ) + 1;
      min_y = height - ( max( max( bw3 .* YY2 ) ) ) + 1;
      

      長方形の例(座標値の表示)

    7. 長方形の座標値を四角形の形で描画
      • poly2mask() 関数: (x,y)座標値の並びを入力とし,多角形(中を白で塗りつぶしたもの)の2値画像を出力する関数
      • bwborder() 関数: 輪郭を得る関数.ここでは,中を白で塗りつぶした2値画像から,長方形の輪郭だけが白い 2値画像を得るために使っています.
      • +: 2つの画像の重ね合わせ
      height = size(mono)(1);
      width = size(mono)(2);
      mask = poly2mask([min_x min_x max_x max_x], [min_y max_y max_y min_y], height, width);
      imshow( 100 * bwborder( imresize( mask, 0.2 ) ) + imresize( mono, 0.2 ) );
      

      長方形の例(画像との重ね合わせ表示)

    プログラムのソースコード

    先ほど示した手順で,「やりたいこと」はできそうです. もし

    • たくさんの画像で同じ手順を繰り返したい

    というようなことがあれば,プログラムをファイルとして作り,何度も実行するのが便利です.まずはソースコードを載せておきます.実行手順は,後で説明している.

    # 画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求めるプログラム
    
    # 画像ファイル名(入力)を in_path に設定して使ってください.
    in_path = "t:/DSC_0015.JPG";
    # A は「bw = im2bw(mono, graythresh( mono ) - A);」で2値化するときにしきい値の調整
    A = 0.1;
    # SIZE は,「bw2 = bwmorph( bwmorph( bw, "dilate", SIZE ), "erode", SIZE ); 」で
    # 小さな黒の塊の除去や,境界のぎざぎざの調整
    SIZE = 4;
    # 表示倍率
    SCALE = 0.2;
    
    
    # in_path で指定した画像ファイルを rgb に読み込み
    fdisp(stderr, "reading image file ...");
    [rgb, immap, alpha] = imread(in_path);
    
    # 画像 rgb を 2値画像 bw に変換
    #   背景部分は「黒」だが,画素値が「0」になっているとは限らない(かすかに薄く何かが写っている)
    fdisp(stderr, "black-white image ...");
    mono = rgb2gray( rgb );
    bw = im2bw(mono, graythresh( mono ) - A);
    
    # dirate と erode により,2 * SIZE 画素より小さな黒の塊の除去や,境界のぎざぎざの調整
    fdisp(stderr, "dilation and erosion ...");
    bw2 = bwmorph( bwmorph( bw, "dilate", SIZE ), "erode", SIZE );
    
    # 隣接領域を抽出.画像の中心から出発
    fdisp(stderr, "connected component ...");
    bw3 = bwselect( bw2, width/2, height/2 );
    
    # 画素が白(値は 1)になっている領域を囲む長方形を求める.
    # 右上が (min_x, min_y), 左下が (max_x, max_y)
    fdisp(stderr, "bottom-right point ...");
    height = size(bw3)(1);
    width = size(bw3)(2);
    [XX1, YY1] = meshgrid([1:1:width], [1:1:height]);
    max_x = max( max( bw3 .* XX1 ) );
    max_y = max( max( bw3 .* YY1 ) );
    fdisp(stderr, "upper-left point ...");
    [XX2, YY2] = meshgrid([width:-1:1], [height:-1:1]);
    min_x = width -  ( max( max( bw3 .* XX2 ) ) ) + 1;
    min_y = height - ( max( max( bw3 .* YY2 ) ) ) + 1;
    
    # 「画素が白(値は 1)になっている領域を囲む長方形」の確認のため,マスク画像を作る
    fdisp(stderr, "mask ...");
    mask = poly2mask([min_x min_x max_x max_x], [min_y max_y max_y min_y], height, width);
    
    # マスク画像と bw3 を重ねて表示する.これは確認のため.
    imshow( or( bwborder( imresize( mask, SCALE ) ), imresize( bw3, SCALE ) ) );
    w = input("please press Enter to proceed");
    
    # マスク画像と bw を重ねて表示する.これは確認のため.
    imshow( 100 * bwborder( imresize( mask, SCALE ) ) + imresize( bw, SCALE ) );
    w = input("please press Enter to proceed");
    
    # 今度は,マスク画像と mono を重ねて表示する.これも確認のため.
    imshow( 100 * bwborder( imresize( mask, SCALE ) ) + imresize( mono, SCALE ) );
    

    実行方法と実行結果の例

    1. (オプション)Cygwin からリモートログインする場合
      startx
      xhost +
      ssh -X username@ipaddress
      
    2. ソースコードをファイルとして保存
    3. Octave を起動
    4. Octave の source コマンドを使って実行
      cd <ソースコードのファイルを置いたディレクトリ>
      source "<ソースコードのファイル名>"
      
    5. 実行が終わるまで数秒待つ
    6. 途中で何回か「please press Enter to proceed」と表示されるので,Enter キーを押す.

    金子邦彦研究室公式Webページへようこそ.サイト内検索は専用ページをご利用ください.

    問い合わせ先: 金子邦彦(かねこ くにひこ) メールアドレス画像

    公開資料はCC BY-NC-SA 4.0で提供しています.自由にご利用いただけますが,著作者表示(BY),非営利(NC),継承(SA)の条件に従ってください.記事の推敲等にAIを利用しています.詳細は別ページをご覧ください.