目次

ファームウエアへの展開

 マイクロコンピュータあるいはFPGAを利用した、Machine Visionの
 画像処理を説明した書籍やホームページがないかと探してみました。

 OpenCVを利用したパーソナルコンピュータ上のアプリケーションの
 解説は、星の数ほどありましたが、マイクロコンピュータやFPGAで
 どう実現するかを記述したものは、皆無でした。

 ないなら、自分で簡単な例を用意して、それを処理して
 テストしてしまえばよいと考えを改めました。

 HSPで簡単な画像処理を記述しました。
 これらをマイクロコンピュータで実現する場合には
 以下のハードルを越えなければなりません。


 画像処理は、元画像をSRAMから取り出し、加工後、再度SRAM
 に保存すると考えると、次のブロック図の操作になります。



 ブロック図から、画像メモリへのアクセスと加工ができると
 画像処理ができることがわかります。

 カメラから画像メモリへの転送は、個々のデバイスで異なる
 ので、画像メモリへのアクセスと加工に限定して説明します。


画像メモリアクセス

 マイクロコンピュータの中に、潤沢なメモリ容量があれば  単純に配列への入出力で対応できます。  マイクロコンピュータにSRAMを外付けする場合にはGPIO(General Purpose Inputs and Outputs)があれば、次の回路で対応します。  ここでは、H8/3664Fを想定していますが、14ビットの入出力が  あれば実現可能です。  上の回路で、以下の4つの関数を定義すれば、メモリアクセス  はおしまいです。  SRAMアドレス設定 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; void set_sram_address(UWORD x) { UBYTE dummy ; /* set address */ sram_address = x ; /* set upper address */ PDAT5 = (UBYTE)(sram_address / 256) ; TRGH = OFF ; dummy = 0 ; TRGH = ON ; /* set lower address */ PDAT5 = (UBYTE)(sram_address % 256) ; TRGL = OFF ; dummy = 0 ; TRGL = ON ; }  アドレスインクリメント void inc_sram_address(void) { UBYTE dummy ; /* address increment */ sram_address++ ; /* increment */ TRGCLK = OFF ; dummy = 0 ; TRGCLK = ON ; }  1バイトデータリード UBYTE get_sram_data(void) { UBYTE result ; /* change input */ PDDR5 = 0x00 ; /* enable CE */ SRAM_CS = OFF ; /* enable OE */ SRAM_OE = OFF ; /* get data */ result = PDAT5 ; /* disable OE */ SRAM_OE = ON ; /* disable CE */ SRAM_CS = ON ; /* change output */ PDDR5 = 0xff ; /* address increment */ inc_sram_address(); return result ; }  1バイトデータライト void put_sram_data(UBYTE x) { UBYTE dummy ; /* impress data */ PDAT5 = x ; /* enable CE */ SRAM_CS = OFF ; /* enable WE */ SRAM_WE = OFF ; /* dummy */ dummy = 0 ; /* disable WE */ SRAM_WE = ON ; /* disable CE */ SRAM_CS = ON ; }

モノクロ変換

 R、G、Bに区切って、画像メモリに保存されている場合は  単純に計算で求めてしまえばよいのですが、YUVのような  フォーマットの場合は、YUVからRGBに変換してしまえば  カラー→モノクロ変換できます。 --------------------------------------------- UBYTE tmp_r[XLAST] ; UBYTE tmp_g[XLAST] ; UBYTE tmp_b[XLAST] ; UBYTE tmp ; UWORD i_r,i_g,i_b,j ; UWORD x,y ; UWORD idx ; i_r = src_red_adr ; i_g = src_green_adr ; i_b = src_blue_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* get red 1 line data */ set_sram_address(i_r+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp_r+x) = get_sram_data(); } /* get green 1 line data */ set_sram_address(i_g+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp_g+x) = get_sram_data(); } /* get blue 1 line data */ set_sram_address(i_b+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp_b+x) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x++ ) { /* calculate */ tmp = *(tmp_r+x) * 77 + *(tmp_g+x) * 151 + *(tmp_b+x) * 28 ; tmp /= 256 ; /* store */ put_sram_data( (UBYTE)tmp ); } } ---------------------------------------------

2倍に拡大

 2倍に拡大するには、元画像のラインを2回保存し  ピクセルも2回繰り返します。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; UWORD idy ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; idy = (idx << 1) ; /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 2 line data */ set_sram_address(j+idy); for ( x = 0 ; x < XLAST ; x += 2 ) { put_sram_data( *(tmp+x) ); /* store left pixel */ put_sram_data( *(tmp+x) ); /* store right pixel */ } for ( x = 0 ; x < XLAST ; x += 2 ) { put_sram_data( *(tmp+x) ); /* store left pixel */ put_sram_data( *(tmp+x) ); /* store right pixel */ } } ---------------------------------------------

1/2に縮小

 1/2に縮小するには、元画像のラインを1飛びに取り出し  さらに、ピクセルも1飛びにして階調値を保存します。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* judge */ if ( (y % 2) == 1 ) continue ; /* if ( (y % 2) == 0 ) continue ; */ /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x += 2 ) { put_sram_data( *(tmp+x) ); } } ---------------------------------------------

間引き処理

 間引きは、元画像のラインを1飛びに取り出して  目的のアドレスに保存すれば、実現できます。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* judge */ if ( (y % 2) == 1 ) continue ; /* if ( (y % 2) == 0 ) continue ; */ /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x++ ) { put_sram_data( *(tmp+x) ); } } ---------------------------------------------

横スクロール

 横スクロールは、元画像のX方向の座標にシフト量を  加えて剰余を求めて、新しい座標値とします。  この座標値を使い、階調値を保存します。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; UWORD xx ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x++ ) { xx = (x + shift) / XLAST ; put_sram_data( *(tmp+xx) ); } } ---------------------------------------------

縦スクロール

 縦スクロールは、元画像のY方向の座標にシフト量を  加えて剰余を求めて、新しいライン位置とします。  このライン位置を使い、階調値を保存します。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; UWORD yy ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 1 line data */ yy = j + ((y+shift) % YLAST) * XLAST ; set_sram_address(yy); for ( x = 0 ; x < XLAST ; x++ ) { put_sram_data( *(tmp+x) ); } } ---------------------------------------------

90°回転

under construction

特定色抽出

under construction

エッジ抽出

 エッジ抽出は、Laplacianフィルタを適用して実現します。  Laplacianフィルタは、8点の情報を必要とするので  ラインバッファを3つ用意して対応します。 --------------------------------------------- UBYTE gtmp[3*XLAST] ; UWORD tmp ; UWORD i,j ; UWORD x,y ; UWORD idx ; UWORD x00,x01,x02 ; UWORD x10,x11,x12 ; UWORD x20,x21,x22 ; j = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* get line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(gtmp+x) = *(gtmp+x+XLAST); *(gtmp+x+XLAST) = *(gtmp+x+2*XLAST); *(gtmp+x+2*XLAST) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x++ ) { /* store */ put_sram_data( (UBYTE)(*(gtmp+x+2*XLAST)) ); } set_sram_address(j+idx); if ( 1 < y && y < YLAST-1) { for ( x = 0 ; x < XLAST ; x++ ) { /* judge */ if ( 0 < x && x < XLAST-1 ) { /* calculate index */ x01 = x ; x00 = x01-1 ; x02 = x01+1 ; x11 = x+XLAST ; x10 = x11-1 ; x12 = x11+1 ; x21 = x+XLAST*2 ; x20 = x21-1 ; x21 = x21+1 ; /* calculate */ tmp = *(gtmp+x00) + *(gtmp+x01) + *(gtmp+x02) ; tmp += *(gtmp+x10) + *(gtmp+x11) + *(gtmp+x12) ; tmp += *(gtmp+x20) + *(gtmp+x21) + *(gtmp+x22) ; tmp -= (*(gtmp+x11) * 9) ; put_sram_data( (UBYTE)tmp ); } } } } ---------------------------------------------

左右反転

 左右反転は、元画像のX方向の座標を小さい方と  大きい方を交換すれば実現できます。 --------------------------------------------- UBYTE tmp[XLAST] ; UWORD i,j ; UWORD x,y ; UWORD idx ; i = src_adr ; j = dst_adr ; for ( y = 0 ; y < YLAST ; y++ ) { idx = y*XLAST ; /* get 1 line data */ set_sram_address(i+idx); for ( x = 0 ; x < XLAST ; x++ ) { *(tmp+x) = get_sram_data(); } /* set 1 line data */ set_sram_address(j+idx); for ( x = 0 ; x < XLAST ; x++ ) { put_sram_data( *(tmp+XLAST-1-x) ); } } ---------------------------------------------

目次

inserted by FC2 system