金子邦彦研究室プログラミングOctave の活用画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める

画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める

画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める 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」 のようにしている.

    元画像の例

    [image]
  2. RGB 画像を濃淡画像に変換

    mono = rgb2gray( rgb );
    

    濃淡画像の例

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

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

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

    2 値画像の例

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

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

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

    2 値画像の例

    [image]
  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;
    

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

    [image]
  7. 長方形の座標値を四角形の形で描画

    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 ) );
    

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

    [image]

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

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

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

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

# 画像ファイル名(入力)を 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 キーを押す.

    [image]