2次元の図形要素を2値画像データとして描画

2次元の図形要素を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

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

function A = intersect_X ( px, vx, val )
# 点 (px,py) を通過するベクトル(xv,vy) が x = val と交わる交点について.
# px + A * vx = val となるような A を求める
  if ( abs( vx ) < 0.0001 )
    A = NaN;
  else
    A = (val - px) / vx;
  endif
endfunction

function A = intersect_Y ( py, vy, val )
# 点 (px,py) を通過するベクトル(xv,vy) が y = val と交わる交点について.
# py + A * vy = val となるような A を求める
  if ( abs( vy ) < 0.0001 )
    A = NaN;
  else
    A = (val - py) / vy ;
  endif
endfunction

function AA = intersect_rectangle ( px, py, vx, vy, width, height )
# 点 (px,py) を通過するベクトル(xv,vy) がなす軌跡 (px,py) + A * (xv,vy) と
# 左上 (1,1), 右下 (width, height) である長方形と交点(2つ)について,その交点における A の値を求める
  # 4 本の直線との交点
  a1 = intersect_X( px, vx, 1 );
  a2 = intersect_X( px, vx, width );
  a3 = intersect_Y( py, vy, 1 );
  a4 = intersect_Y( py, vy, height );
  A = [a1 a2 a3 a4];

  # a1, a2, a3, a4 の中で正であり、最小のもの
  e1 = min( A( find( A > 0 ) ) );

  # a1, a2, a3, a4 の中で負であり、最大のもの
  e2 = max( A( find( A < 0 ) ) );
 
  AA = [e1 e2];
endfunction

function mask = draw_linesegment ( x1, y1, x2, y2, width, height )
# 2端点を指定しての線分の描画
# 左上 (1,1), 右下 (width, height) である画像に,線分 (x1, y1) - (x2, y2) を描く
  mask = poly2mask([x1 x2 x1], [y1 y2 y1], height, width);
endfunction

function mask = draw_linesegment_vectorform ( px, py, vx, vy, width, height )
# 左上 (1,1), 右下 (width, height) である画像に,(px, py) を通過し,方向が (vx, vy) であるような線分を書く
  AA = intersect_rectangle( px, py, vx, vy, width, height );
  mask = draw_linesegment( px + (vx * AA(1)), py + (vy * AA(1)), px + (vx * AA(2)), py + (vy * AA(2)), width, height );
endfunction

function mask = draw_vector ( px, py, vx, vy, width, height )
# 左上 (1,1), 右下 (width, height) である画像に,線分 (x1, y1) - (x2, y2) を描く
  # (px, py) + (vx, vy) が画像からはみ出るか?
  AA = intersect_rectangle( px, py, vx, vy, width, height );
  if ( AA(1) > 1 )
    # はみ出ない
    mask = draw_linesegment( px, py, px + vx, py + vy, width, height );
  else
    mask = draw_linesegment( px, py, px + ( vx * AA(1) ), py + ( vy * AA(1) ), width, height );
  endif
endfunction

px = 140;
py = 250;
vx = 8;
vy = -12;

width = 512;
height = 512;

# 線分
mask = draw_linesegment_vectorform(px, py, vx, vy, width, height);
imshow( mask );
w = input("please press Enter to proceed");

# ベクトル
mask2 = draw_vector( px, py, vx, vy, width, height );
imshow( mask2 );
w = input("please press Enter to proceed");

実行方法と実行結果の例

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

使用方法の説明

ここでのプログラムは,2値画像データ(2 次元の配列)に,2次元の図形要素を描画するもの.gnuplot と混同しないように.

ブレゼンハム(Bresenham)のアルゴリズム

ブレゼンハム(Bresenham)のアルゴリズムとは,整数演算で,ビットマップ上に線分を描画するアルゴリズム.

(x1, y1), (x2, y2) 間の線分を書く. x1, y1, x2, y2 は整数とする場合で、 Octave のプログラムは次の通り

x1 = 95;
y1 = 80;
x2 = 100;
y2 = 100;

dx = x2 - x1;
dy = y2 - y1;

if ( abs(dx) > abs(dy) )
    i = x1;
    j = y1;
    di = sign(dx); 
    c = floor( dx / 2 );
    while( ( i * di ) <= ( x2 * di ) )    
        printf("%d %d\n", i, j)
        i = i + di;
        c = c + dy;
        if ( abs(c) > abs(dx) )
            j = j + sign(dy);
            c = c - ( sign(dx) * sign(dy) * dx );
        endif
    endwhile

else
    i = x1;
    j = y1;
    dj = sign(dy); 
    c = floor( dy / 2 );
    while( ( j * dj ) <= ( y2 * dj ) )    
        printf("%d %d\n", i, j)
        j = j + dj;
        c = c + dx;
        if ( abs(c) > abs(dy) )
            i = i + sign(dx);
            c = c - ( sign(dx) * sign(dy) * dy );
        endif
    endwhile

endif