画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める
画像の中央部分に写っているオブジェクト(背景は黒)を囲む長方形を求める 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 ページの後半に載せています.
- 画像ファイルを変数 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」 のようにしている.
元画像の例
- RGB 画像を濃淡画像に変換
mono = rgb2gray( rgb );
濃淡画像の例
- 濃淡画像を 2 値画像に変換
「- 0.2」を付けているのは,境界の部分をきれいに出すための調整です. 「- 0.2」の 0.2 の値は,何度か 2 値画像を作ってみて調整する必要があるでしょう. つまり,完全に自動ではできず,手動での調整が必要だということです.
bw = im2bw(mono, graythresh( mono ) - 0.2);
2 値画像の例
- 2 値画像での小さな黒の塊の除去や,境界のぎざぎざの調整 (モルフォロジカル演算を利用)
「4」に指定しているのは,半径 4 以下の黒の塊を除去したりなどしたいという意味です. 「4」で良いかどうかは,画像の種類によって変わります. 実際に作ってみて,「4」という値を調整する必要があるでしょう.
bw2 = bwmorph( bwmorph( bw, "dilate", 4 ), "erode", 4 );
2 値画像の例
- (参考) 隣接領域を抽出(画像の中心から出発)
ここに載せている画像(魚眼カメラ画像)では関係ないですが, 出来た2値画像が複数の部分に分かれているとき, 画像の中心から出発し,隣接する画像(白色の画像)をつなげていき,大きな領域を作るという方法により, 主要部分を抜き出すということを行うことがあります.
bw3 = bwselect( bw2, width/2, height/2 );
- 画素が白(値は 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;
長方形の例(座標値の表示)
- 長方形の座標値を四角形の形で描画
- 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 ) );
実行方法と実行結果の例
- (オプション)Cygwin からリモートログインする場合
startx xhost + ssh -X username@ipaddress
- ソースコードをファイルとして保存
- Octave を起動
- Octave の source コマンドを使って実行
cd <ソースコードのファイルを置いたディレクトリ> source "<ソースコードのファイル名>"
- 実行が終わるまで数秒待つ
- 途中で何回か「please press Enter to proceed」と表示されるので,Enter キーを押す.