−83−
Turbo‑Cによる画像処理プログラムについて
吉村 卓
OnProgrammingof lmageProcessing inTurbo‑C
TakashiYosHIMuRA
(昭和63年10月17日受理)
コピー(gcopy)
フーリエ変換により画像を空間領域から周波数領 域に変換してスペクトルを求め,周波数領域でフィ ルタ操作を行なってから逆変換により元空間に復元 する。アルゴリズムとして基数2の周波数間引方式 を用い, 1次元FFTの繰り返しにより2次元データ
の変換処理を行なう。1. はしがき
さきに,BASIC語と機械語を用いてパソコン用画 像処理プログラムを作成した。プログラミングにお いて,機械語を用いたのは,BASICだけでは処理速 度が遅く実用にならないからである。初期設定やプ ログラム全体の流れをコントロールする部分など,
繰り返し計算を伴わない部分をBASICで,メニュー で選ばれた個々の処理や繰り返し部分を機械語でプ ログラミングすることにより,処理時間の短縮化が
図られた・
ところで,機械語によるプログラミングはソフト ウエア作成作業の面からは非能率的であり,一方,
BASIC語は構造化プログラミングには不向きである。
そこで,今回はc言語によるプログラミングに切換
えたわけである。cには,構造化プログラミングを行う上で必要な 流れ制御構造として, ifelse構文はもちろんのこと,
判定先行型ループにwhile文,判定後行型ループに do・ ・ ・while構文,回数判定型ループにfol文と豊 富な構文が用意されている。殊に, Cにはブロック
(複文)なる概念があるので,ifelse、whileの制御 構造をスマートに書くことができる。BASICやFO−
RTRANはブロックという概念をもたないために構 造化プログラミングに向かないのである。
3. データ構浩
3. 1 メモリモデル
メモリ ・モデルとしてスモール・モデルを用いる。
Turbo‑Cではスモール・モデルの場合,プログラム・
サイズ,データ・サイズともにその上限は64KBで
ある。1枚の画面を表現するのに128*128画素(un‑
signedchar型2次元配列imageに格納)とし,
各画素は1バイト (256段階)の濃度値をもつもの
とする。3. 2 ラム・ディスクの使用
1画面128*128画素でも,フーリエ変換を行なう には, フーリエ変換像の実部ならびに虚部を格納す るために, 2個のfloat型2次元配列realとimagを
用意せねばならないから, 2バンク128KBのメモリ領域が必要となり,スモール・モデルでは主メモ リだけでは収容しきれない。そのため,アルゴリズ ムとしてX方向ならびにY方向の1次元FFTの繰り 返し法を採用する。すなわち2次元配列データをデ ィスクに格納しておき,処理の対象となる1行ある いは1列分のデータをその都度ディスクから読み込 んできて変換処理を施し再びディスクに戻してやる
という方法によるわけである。
しかしこの方法では, 1画面の変換処理に128*
2回,ディスクとのデータの出し入れを必要とし,
フロッピーディスクを用いていたのでは,入出力の
2. 機能概要今回は,NECのPC‑9801VXを用いて, フーリエ 変換とフィルタリングのアルゴリズムを用意するこ とを主目的としているが,それに先だち最小限,つ ぎの機能を準備する必要があるであろう。
(1) 画像データの保存(save)と再生(load)
(2) 濃度ヒストグラム(histgram)
(3) 濃度パターン表示(dot̲pattern) とハード
平成元年2月
−84−
吉村 卓
ための時間がかかりすぎて実用にならない。そのた めに増設RAMボードをラム・ディスクとして用いる。
(2) グラフィック・インターフェイス
PC‑9800でグラフィック処理を行うにはソフトウ エア割り込みによりROM内ルーチンを利用するこ とができる。すなわち,グラフLIOのコマンドを実 行するには,パラメータ・ リストの先頭アドレスの セグメント値をレジスタdsに,オフセット値をレジ スタbxに与えてintnを行う。そのめにはTurbo‑C の関数のfar型システム・コールint86×を用いればよ い。以下のような関数を用意する。
ginit グラフィックLIOの初期化 Screenグラフィック画面モード設定
cls 画面クリア
pset 指定位置に点を打つ line 指定点を直線で結ぶ
getpalete
指定位置の点のパレット番号取得 これらの関数ではつぎの関数を用いている。
setb バイト・データの設定 setw ワード・データの設定 lio
glioの割り込み
4. プログラミングの手法4. 1 プロセス制御
親プロセスとしてのメニュー・プログラムで選択 された個々の処理を子プロセスとして実行し,処理
終了後は再び親プロセスとしてのメニュー・プログラムに制御を戻してやる。そのために,Turbo‑C に標準関数として用意されているspawn関数を用い
る。
4. 2 各種ライブラリ・ルーチン
Turbo‑CのVerl . 5ではIBM版にテキスト
画面処理関数とグラフィック処理関数が用意されて いるが,PC版には末だこれらの関数が提供されて
いないので,テキスト画面制御やグラフィック処理を実行するためにはそれに必要な関数を自作しなけ
ればならない。(1) CRTインターフェイス
Turbo‑Cの標準関数には,CRTの任意の位置に カーソルを移動させる等の関数が用意されていない。
ところで,Turbo‑CはMS‑DOSの上で走っている。
カーソル・アドレッシングのようなハードウエアに
依存する部分はOSの機能を直接コールすることで
実現する。すなわち, エスケープ・コード0×1bではじまる文
字列を送出することによりCRT画面の各種制御を行
う。最小限つぎのような関数を用意する。
console画面最下行の使用モード設定 clstxt テキスト画面のクリア locate カーソル位置の指定
clreol カーソル位置から行末までの消去
setb(adr。dat) intadr。dat;
{
movedata(DSEG,&dat,GSEG。adr,1);
)
setw(adr,dat) intadr。dat;
{
movedata(DSEG,&dat,GSEG,adr,2);
)
lio(intno)
int intno;
(
inregs.x・bx=0;
segregs.ds=GSEG;
int86x(intno,&inregs,&outregs,&segregs);
)
図2
j52シy
lO
OOOくy
OO●9●9︒︐●9
O0jjjjlj
●99999
図yOjOOOOp
oow9999
xシrL++;++;くxbOOjOOjelll9119t00x〃ノ%・9〃ノ%H a00;¥yy9xx9
c・りnW〃l〃1グ4〃Ir︑グー・Oy︽Ur彦irrrrrr ︑1︐くufaaaaaa
xxntot.nh.n.nh.ndグーencccccc
●10℃r・1+しOr0tf︾十︾0℃on︽工ruuuuuu
v.l〃1.1ppppppp・﹄(3) プリンタ・インターフェイス
グラフィック画面をプリンタにハード・コピーす
るプログラムgcopyを作成するためにプリンタ・イ
ンターフェイスが必要である。プリンタへの出力法としてはプリンタの出力ポートO×40に直接データを 書き出す方法をとる。つぎの2つの関数を用意する。
dlputc l文字出力 dlputs文字列の出力
(4) MS‑DOSインターフェイス
画像を空間領域から周波数領域にフーリエ変換し てパワー・スペクトルを求め,逆変換するにあたり
秋田高専研究紀要第24号
−85−
Turbo‑Cによる画像処理プログラムについて
read/write関数はデータ・セグメント内のバッファ との間でしかリード/ライトできない。そこで,セ グメント外のバッファとの間で直接リード/ライト を行う関数dread/dwriteを準備する。
MS‑DOSのシステム・コールをする。すなわち,
レジスタahにファンクション・コードを入れ, さら
に必要なパラメータをレジスタcx,dxなどに入れて
ソフトウエア割り込みのint21hを行なう。これによ りファンクション・コードで定められた機能が実行 される。 far型intO×21を実行する関数として,Tu‑rbo‑Cではintdosxが用意されている。
4. 3 ファイル処理
原画像データは2次元配列imageに,また,フーリ エ変換像の実部,虚部はそれぞれ2次元配列real, imagに格納されている。save,loadではデータimage
の読み出し書き込みはシーケンシャル・ファイルとして連続的に行えるので,ストリーム入出力関数の ブロック・ リード/ライトfread/fwriteを用いる。
staticdlputc(c)
Charc;(
while ((inport(0x42)&4)
;
outportb(Ox40,c);
outportb(Ox46,14);
outportb(0x46,15);
}
!=4)
staticdlputs(str)
char*str;{
while (*str!=0) {
dlputc(*str++);
)
)
図3
周波数領域でフィルタ操作を行う際,パワー・スペ クトルを3次元立体表示すると都合よい。そのよう なとき,グラフィック画面上の原画像を一時ラム・
ディスクに退避させておき,逆変換後,原画像とフ
ーリエ変換像を並べて表示したい。そのとき,一時 退避させておいた原画像をディスクからグラフィッ ク画面に再現しなければならない。そこで,グラフ ィック画面全体の保存と読み込みを行うプログラム
gsaveとgloadを作成する。
グラフィックVRAMのデータは0×a800,0×b000, 0×b800を先頭とするメモリにそれぞれ32000バイト
(640*400ドット)ずつ格納されている。このデ ータをディスクにセーブするのにTurbo‑Cのセグ メント間データ転送関数movedataを用いたのでは
時間がかかりすぎる。また,スモール・モデルでの
void loaddata()
{
FILE*f;
char fname[30];
●●夕●︑︑日夕●●ケ●︽ynB夕︑B〃︑日夕の一〃︾︽↑0−︽↑▲
︑〆一︑︒●@ヶ〃日︑●夕
︒〃︒︒〆︑ノW1︽14e︑ノ←し︐f︑mereE eam亘旨乙 tna9二丁△
aneyScePxmW9 0勺1paope
勺1.1Wn︑j9.9︒︐︽工Sの1の土a︑﹄1〃%〃Ilmfグー〃InW・1〃ItfくetくextfpepdS otnnOgaO
S・la︽1二e勺11︽rc二xrc
cpSfWff}
図5
●●毎
j e1
mlaljJnlOfR−0︐W二4WD室く6SRjj+%一JorⅦOEOdくT8aF400TL十二︑RpraTW︒︐二.;cAIjpaj ;SE雨;;0
1.︐RSnOOO;4JC︐¥004
4r6w一Yt846 .tORab*︐
図ae9o9AexOrDmeNrO8d
paemマーcこくa︲nmaBくr︐dfan−tpdp
PXpn会xO9;a9つ﹄Ino︒︐dDt︽Uenan︾0f︽n4−1▲eC8二〃I・16.1pWare;
PLFO〃k;xdtmJd争工Ⅶ雲︽工1夕0a・1deu〃td︒t〃4ニクIrfnbffntpv参I
︑﹄g十︾〃1・1◇1〃Irde夕・lrn夕IrxOS eSa・1perf.;0
Vnhrf0.1aucp・1︑jf︑jc
S
glI
また, フーリエ変換のプログラムでも,行方向処 理の場合は連続してデータを読み出し書き込みでき るが,列方向処理の場合は飛びとびにデータを読み
書きしなければならな・い・そのため, ファイル現在 位置の移動関数lseekを用いる必要がある。そして,ラム・ディスクとの間のデータの読み書きには低水 準ファイル入出力関数のread/writeを用いることに する。
4.4 callbyreference
関数間のデータ授受の方法としてCの最も一般的
な引数渡しの方法はcallbyvalueである。callby
平成元年2月
一髄一
吉村 卓
次元座標P'(u,v)に変換しなければならない。
このように,戻り値が二つ以上ある場合はデータ 授受の方法としてcallbyreferenceの手法を用い,
実引数のアドレスを仮引数に渡す。呼ばれた関数で はポインタを介して呼び出し側の関数とデータをや りとりする。
voidfft2(int flag)
(
int i,j;
float rx,ry;
/*FFT/ inverseFFT*/
if ((fr=open(frname,O̲RDWR I O̲BINARY))==‑1) ( printf(''Can't openreal file'、);exit();
)
if ((fi=open(finame,O̲RDWR I O̲BINARY))==‑1) { printf('0Can't open imaginaryfile'');exit();
)
for (i=O;i<size;i++) ( for (j=0;j<size;j++) (
lseek(fr,(long)(i*size+j)*4,0);
read(fr,&rx,4);x[j]=rx;
lseek(fi,(long)(i*size+j)*4,0);
read(fi,&ry,4);y[j]=ry;
)
FFT1(flag);
for (j=0;j<size;j++) (
rx=x[j];lseek(fr,(long)(i*size+j)*4,0);
write(fr,&rX,4);
ry=y[j];lseek(fi,(long)(i*size+j)*4,0);
write(fi,&ry,4);
)
)
for (i=O;i<size;i++) ( for (j=O;j〈size;j++) {
lseek(fr,(long)(j*size+i)*4,0);
read(fr,&rx,4);X[j]=rX;
lseek(fi,(long)(j*size+i)*4,0);
read(fi,&ry,4);y[j]=ry;
)
FFT1(flag);
for (j=O;j〈size;j十十) {
rx=x[j];lseek(fr,(long)(j*size+i)*4,0);
Write(fr,&rX,4);
ry=y[j];lseek(fi,(long)(j*size+i)*4,0);
Write(fi,&ry,4);
)
}
close(fr);close(fi);
)
図6
︐●9
0︐JO0zy︒︒q*00
0.︐O ee40111一一●一●●ウbbT72Yuu︲01︒︲ノKOOOD二MT* dd︒−MCoy OYC一Dq ︲︐5︲一Y一* yx二OYノXj q*2.︐T+z DOOOXq ee︲4.DK一 11064一*2 bb・二2YxD uuOT二二q+0050MY*1 dd雲DCKJD 1一一zく
りDXX;q/x0;M−2qeYC2D
lK一D−eb︐X+2l
uXノーノ
bOKTDTudoくOOeDノDdtl−2一く
SGDN︽︽UYenu二二二sOOXxyrcdK**up〃I︑︺
ee
llbbuu oo
ddDp勺0一命〃︼●●pyyzzee9.6・9l1yj﹄.︐
bbyzzjuu︲z;z;0 00x&﹄&﹄︲ ddx︐1︐21
99︐yyyyO122yyyyc
xx︑﹄y&&&&︐1今y︐︐︐p2eeOOxlx2y.l・lc2xxxxybbx&x&xp
uutxD&D︽鞍ワーOon︐1︑クーgxdd・11zzzzxくy︐Z︐Z︐ey1︐2︐1︑︐yyyyy
●Q■冬1︐y︐yylxl−Dク︾p9
xxxxx句1W〃lx〃Ixx
aenグー︑〃lxro1aeaefLdbkSkSe
unrnrndOeueu.l
①●■△dhphplovIIZ1,
Z2,
図7
参考文献
吉村卓パソコン用画像処理プログラム
秋田高専研究紀要第21号 1986年
町田東一,小島紀男パソコンBASIC数値 計算Ⅱ東海大学出版会1985年
安居院猛,中島正之,長尾智春TURBO
pascal画像処理の実際工学社1988年
河西朝雄TURBOC初級プログラミング 技術評論社1988年1
valueでは実引数の値を仮引数に渡すため,引数を 用いて呼び出し側に値を返すことができず,関数名 を介して戻り値が一つだけ返される。
ところで, フーリエ変換の結果パワー・スペクト
ルを立体表示するのに, 3次元図形上の点P(x,y,z)
を透視変換してグラフィック・ディスプレイ上の22
3
4
秋田高専研究紀要第24号