画像処理検討
SRAMに2値化した画像データを保存後、60バイトのセンサー
データを生成する方法を検討します。
2010年の大会に利用したプログラムは、時間が掛かりましたが
必要なセンサーデータを生成することが出来ました。
時間がかかる原因は、画像データ保存後、2値化していたことと
ラインごとの8ビットデータ生成が、冗長な処理をしていたこと。
これらを改善し、ソースコードの長さがどの程度になるか、やって
みました。
60ライン分のセンサーデータが必要なので、for文を利用
して処理し結果を格納します。
for ( j = 0 ; j < 60 ; j++ ) {
/* reverse save */
*(sdat+59-j) = res ;
}
1ライン=80ビットを8ビットに変換します。
8ビットにしたいので、8ブロックに分割して、ブロックの
代表値を求めます。代表値は1ブロック=10ビットの総和
とします。
/* clear */
for ( i = 0 ; i < 8 ; i++ ) { *(lsum+i) = 0 ; }
/* block summuation */
for ( i = 0 ; i < 10 ; i++ ) {
index = j * 80 + i ;
*(lsum+0) += *(gdat+index) ;
*(lsum+1) += *(gdat+index+10) ;
*(lsum+2) += *(gdat+index+20) ;
*(lsum+3) += *(gdat+index+30) ;
*(lsum+4) += *(gdat+index+40) ;
*(lsum+5) += *(gdat+index+50) ;
*(lsum+6) += *(gdat+index+60) ;
*(lsum+7) += *(gdat+index+70) ;
}
各ブロックの総和の合計値から、平均値を求めます。
index = 0 ;
for ( i = 0 ; i < 8 ; i++ ) {
index += *(lsum+i) ;
}
index >>= 3 ;
各ブロックの代表値を1か0にします。
これは、平均値以上で1にします。
for ( i = 0 ; i < 8 ; i++ ) {
res = 0 ;
if ( *(lsum+i) >= index ) { res = 1 ; }
*(lsum+i) = res ;
}
8ビットデータを生成できたので、16進に変換します。
res = 0 ;
for ( i = 0 ; i < 8 ; i++ ) {
res = (res << 1) + *(lsum+i) ;
}
全体をまとめると、次のようになります。
for ( j = 0 ; j < 60 ; j++ ) {
/* clear */
for ( i = 0 ; i < 8 ; i++ ) { lsum[i] = 0 ; }
/* block summuation */
for ( i = 0 ; i < 10 ; i++ ) {
index = j * 80 + i ;
*(lsum+0) += *(gdat+index) ;
*(lsum+1) += *(gdat+index+10) ;
*(lsum+2) += *(gdat+index+20) ;
*(lsum+3) += *(gdat+index+30) ;
*(lsum+4) += *(gdat+index+40) ;
*(lsum+5) += *(gdat+index+50) ;
*(lsum+6) += *(gdat+index+60) ;
*(lsum+7) += *(gdat+index+70) ;
}
/* average */
index = 0 ;
for ( i = 0 ; i < 8 ; i++ ) {
index += *(lsum+i) ;
}
index >>= 3 ;
/* convert */
for ( i = 0 ; i < 8 ; i++ ) {
res = 0 ;
if ( *(lsum+i) >= index ) { res = 1 ; }
*(lsum+i) = res ;
}
/* concatenate */
res = 0 ;
for ( i = 0 ; i < 8 ; i++ ) {
res = (res << 1) + *(lsum+i) ;
}
/* reverse save */
*(sdat+59-j) = res ;
}
50行程度なので、充分高速に動作すると考えられます。
WindowsのDOS窓で動く、LSICを利用したところ、ファイル
から画像データを入力、処理で、2秒もかかりません。
マイコンのプログラムでも、1秒もかからないでしょう。
センサーデータ判定
実際にカメラで撮影したコースから、どのようなセンサーデータ
が生成させるか、テストします。
カメラの画像データから作成したセンサーデータは、以下です。
(2値化した画像データに続けて、センサーデータを逆順表示)
11111111111111111111111111111111111111111111111111111110000000000000000000000000
11111111111111111111111111111111111111111111111111111111000000000000000000000000
01111111111111111111111111111110111111111111111111111111000000000000000000000000
00000000000000000001111000000000000000111111111111111111000000000000000000000000
00000000000000000000000000000000000000111111111111111111000000000000000000000000
00000000000000000000000000000000000000111111111111111111000000000000000000000000
00000000000000000000000000000000000000111111111111111111100000000000000000000000
00000000000000000000000000000000000000111111111111111111100000000000000000000000
00000000000000000000000000000000000001111111111111111111100000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111110000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111101101000000000000000000000
00000000000000000000000000000000000011111111111111111100000000000000000000000000
00000000000000000000000000000000000011111111111111111100000000000000000000000000
00000000000000000000000000000000000011111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
0 0x1C 00011100
1 0x1C 00011100
2 0x1C 00011100
3 0x1C 00011100
4 0x1C 00011100
5 0x1C 00011100
6 0x1C 00011100
7 0x1C 00011100
8 0x1C 00011100
9 0x1C 00011100
10 0x1C 00011100
11 0x1C 00011100
12 0x1C 00011100
13 0x1C 00011100
14 0x1C 00011100
15 0x1C 00011100
16 0x1C 00011100
17 0x1C 00011100
18 0x1C 00011100
19 0x1C 00011100
20 0x1C 00011100
21 0x1C 00011100
22 0x1C 00011100
23 0x1C 00011100
24 0x1C 00011100
25 0x1C 00011100
26 0x1C 00011100
27 0x1C 00011100
28 0x1C 00011100
29 0x1C 00011100
30 0x1C 00011100
31 0x1C 00011100
32 0x1C 00011100
33 0x1C 00011100
34 0x1C 00011100
35 0x1C 00011100
36 0x1C 00011100
37 0x1C 00011100
38 0x1C 00011100
39 0x1C 00011100
40 0x1C 00011100
41 0x1C 00011100
42 0x1C 00011100
43 0x1C 00011100
44 0x1C 00011100
45 0x1C 00011100
46 0x1C 00011100
47 0x1C 00011100
48 0x1C 00011100
49 0x1C 00011100
50 0x1C 00011100
51 0x1C 00011100
52 0x1C 00011100
53 0x1C 00011100
54 0x1C 00011100
55 0x1C 00011100
56 0x3C 00111100
57 0xFC 11111100
58 0xF8 11111000
59 0xF8 11111000
センサーデータは、番号が若い方が手前にあります。
この場合は、56ライン〜59ラインに左クランクが
見えます。
密着タイプのセンサーが出力するデータと似た内容に
なることがわかります。
カメラを利用して、センサーデータに変換すると、現在の
位置から先にある、コースの状態を把握できます。
左右のクランク、左右のレーンチェンジに相当するセンサー
データを見つけ出し、ライン番号と関連させて、舵角を調整
すれば、アンダーステアで最短コースを移動するように制御
します。
2値化処理
カメラから1ピクセルのデータは8ビットで転送されます。
このピクセルデータを、転送と同時に2値化します。
2値化には閾値が必要なので、次のように求めます。
- カメラで、コースを撮影
- 29ラインの80ピクセル取得
- 0、79ピクセルの輝度の相加平均を黒とする
- 39、40ピクセルの輝度の相加平均を白とする
- 30ラインの80ピクセル取得
- 0、79ピクセルの輝度の相加平均を黒とする
- 39、40ピクセルの輝度の相加平均を白とする
- 2ラインの黒の相加平均を求める
- 2ラインの白の相加平均を求める
- 白と黒の相加平均を、閾値とする
走行前のスタートトリガー待ち状態中に、閾値を求めます。
2秒程度で閾値を求められるので、競技進行を妨げないでしょう。
走行中は、次のシーケンスで2値化して保存します。
- ピクセルデータ取得
- 閾値と比較し、1か0を設定
- 8ビットにまとめて、配列に保存
このシーケンスの採用で、80バイトx60ラインのデータは
80ビットx60ラインまで圧縮されます。データは、600
バイトのデータになるので、H8のSRAMに格納できます。
600バイトのデータを、センサーデータにすると
60バイトになります。
一時変数を用意しても、800バイト程度なので内蔵
SRAMが2048バイト程度のマイコンでも動作できます。
2つのシーケンスを画像処理に適用して、センサーデータ
が得られるかをテストしてみました。結果は、以下です。
11111111111111111111111111111111111111111111111111111110000000000000000000000000
11111111111111111111111111111111111111111111111111111111000000000000000000000000
01111111111111111111111111111111111111111111111111111111000000000000000000000000
00000000000000000001111000000000000000111111111111111111000000000000000000000000
00000000000000000000000000000000000000111111111111111111000000000000000000000000
00000000000000000000000000000000000000111111111111111111100000000000000000000000
00000000000000000000000000000000000000111111111111111111100000000000000000000000
00000000000000000000000000000000000001111111111111111111100000000000000000000000
00000000000000000000000000000000000001111111111111111111100000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000001111111111111111111110000000000000000000000
00000000000000000000000000000000000011111111111111111111110000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111110000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111111000000000000000000000
00000000000000000000000000000000000011111111111111111111110100000000000000000000
00000000000000000000000000000000000011111111111111111111011100000000000000000000
00000000000000000000000000000000000111111111111111111110100000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000000111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111110000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000001111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111000000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000011111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111100000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000000111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
00000000000000000000000000000001111111111111111111111111110000000000000000000000
0 0x1C 00011100 CENTER
1 0x1C 00011100 CENTER
2 0x1C 00011100 CENTER
3 0x1C 00011100 CENTER
4 0x1C 00011100 CENTER
5 0x1C 00011100 CENTER
6 0x1C 00011100 CENTER
7 0x1C 00011100 CENTER
8 0x1C 00011100 CENTER
9 0x1C 00011100 CENTER
10 0x1C 00011100 CENTER
11 0x1C 00011100 CENTER
12 0x1C 00011100 CENTER
13 0x1C 00011100 CENTER
14 0x1C 00011100 CENTER
15 0x1C 00011100 CENTER
16 0x1C 00011100 CENTER
17 0x1C 00011100 CENTER
18 0x1C 00011100 CENTER
19 0x1C 00011100 CENTER
20 0x1C 00011100 CENTER
21 0x1C 00011100 CENTER
22 0x1C 00011100 CENTER
23 0x1C 00011100 CENTER
24 0x1C 00011100 CENTER
25 0x1C 00011100 CENTER
26 0x1C 00011100 CENTER
27 0x1C 00011100 CENTER
28 0x1C 00011100 CENTER
29 0x1C 00011100 CENTER
30 0x1C 00011100 CENTER
31 0x1C 00011100 CENTER
32 0x1C 00011100 CENTER
33 0x1C 00011100 CENTER
34 0x1C 00011100 CENTER
35 0x1C 00011100 CENTER
36 0x1C 00011100 CENTER
37 0x1C 00011100 CENTER
38 0x1C 00011100 CENTER
39 0x1C 00011100 CENTER
40 0x1C 00011100 CENTER
41 0x1C 00011100 CENTER
42 0x1C 00011100 CENTER
43 0x1C 00011100 CENTER
44 0x1C 00011100 CENTER
45 0x1C 00011100 CENTER
46 0x1C 00011100 CENTER
47 0x1C 00011100 CENTER
48 0x1C 00011100 CENTER
49 0x1C 00011100 CENTER
50 0x1C 00011100 CENTER
51 0x1C 00011100 CENTER
52 0x1C 00011100 CENTER
53 0x1C 00011100 CENTER
54 0x1C 00011100 CENTER
55 0x1C 00011100 CENTER
56 0x3C 00111100 CENTER
57 0xFC 11111100 CRANK_LEFT
58 0xF8 11111000 CRANK_LEFT
59 0xF8 11111000 CRANK_LEFT
上のデータを得るためのソースコードは、以下です。
#include <stdio.h>
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
#define OFF 0
#define ON OFF+1
#define ALL_BLACK 0x00
#define ALL_WHITE 0xff
#define SINGLE_LEFT 0xf0
#define SINGLE_RIGHT 0x0f
#define CENTER 0x18
#define CENTER1 0x3c
#define CENTER2 0x38
#define CENTER3 0x1c
#define LEFT1 0x10
#define LEFT2 0x30
#define LEFT3 0x60
#define LEFT4 0xc0
#define RIGHT1 0x08
#define RIGHT2 0x0c
#define RIGHT3 0x06
#define RIGHT4 0x03
#define SIDE_EDGE 0x81
#define SIDE_EDGE1 0xc1
#define SIDE_EDGE2 0x83
#define SIDE_EDGE3 0xc3
#define CRANK_LEFT 0xf8
#define CRANK_LEFT1 0xfc
#define CRANK_RIGHT 0x1f
#define CRANK_RIGHT1 0x3f
void binary_display(UBYTE x)
{
int i ;
for ( i = 7 ; i > -1 ; i-- ) {
putchar('0'+((x >> i) & 1));
}
putchar(' ');
}
#define SDAT_SIZE 60
char tmp[330];
UBYTE sdat[SDAT_SIZE] ;
UBYTE gdat[4800] ;
UBYTE gdatx[600] ;
UBYTE lsum[8] ;
UBYTE a2v(UBYTE x)
{
UBYTE result;
result = 0;
if ('0' <= x && x <= '9') { result = x - '0'; }
if ('A' <= x && x <= 'F') { result = x - 'A' + 10; }
if ('a' <= x && x <= 'f') { result = x - 'a' + 10; }
return result;
}
#define LINE_SIZE 321
#define THRESHOLD 128
void put_pattern(UBYTE x)
{
switch ( x ) {
case ALL_BLACK : printf("ALL_BLACK"); break ;
case ALL_WHITE : printf("ALL_WHITE"); break ;
case SINGLE_LEFT : printf("SINGLE_LEFT"); break ;
case SINGLE_RIGHT : printf("SINGLE_RIGHT"); break ;
case CENTER : printf("CENTER"); break ;
case CENTER1 : printf("CENTER"); break ;
case CENTER2 : printf("CENTER"); break ;
case CENTER3 : printf("CENTER"); break ;
case LEFT1 : printf("LEFT1"); break ;
case LEFT2 : printf("LEFT2"); break ;
case LEFT3 : printf("LEFT3"); break ;
case LEFT4 : printf("LEFT4"); break ;
case RIGHT1 : printf("RIGHT1"); break ;
case RIGHT2 : printf("RIGHT2"); break ;
case RIGHT3 : printf("RIGHT3"); break ;
case RIGHT4 : printf("RIGHT4"); break ;
case SIDE_EDGE : printf("SIDE_EDGE"); break ;
case SIDE_EDGE1 : printf("SIDE_EDGE"); break ;
case SIDE_EDGE2 : printf("SIDE_EDGE"); break ;
case SIDE_EDGE3 : printf("SIDE_EDGE"); break ;
case CRANK_LEFT : printf("CRANK_LEFT"); break ;
case CRANK_LEFT1 : printf("CRANK_LEFT"); break ;
case CRANK_RIGHT : printf("CRANK_RIGHT"); break ;
case CRANK_RIGHT1 : printf("CRANK_RIGHT"); break ;
default : printf("ILLEAGAL"); break ;
}
putchar('\n');
}
UBYTE is_middle(UWORD x)
{
if ( x == 2359 ) { return ON ; }
if ( x == 2360 ) { return ON ; }
if ( x == 2439 ) { return ON ; }
if ( x == 2440 ) { return ON ; }
return OFF ;
}
UBYTE is_edge(UWORD x)
{
if ( x == 2320 ) { return ON ; }
if ( x == 2399 ) { return ON ; }
if ( x == 2400 ) { return ON ; }
if ( x == 2479 ) { return ON ; }
return OFF ;
}
void main(void)
{
int i,j ;
FILE *infile ;
int res ;
int index ;
UWORD resx ;
UWORD resy ;
UWORD thvalue ;
/* file */
infile = fopen("mgtst.txt","r");
if ( infile == NULL ) { fprintf( stderr , "Open Error !"); }
/* get file context */
index = 0 ;
resx = 0 ;
resy = 0 ;
while ( !feof( infile ) ) {
/* get 1 line data */
fgets( tmp , LINE_SIZE , infile );
/* separate and store */
for ( i = 0 ; i < 80 ; i++ ) {
/* convert */
j = (i << 2) ;
res = a2v( *(tmp+j+0) ) ;
res = res * 10 + a2v( *(tmp+j+1) ) ;
res = res * 10 + a2v( *(tmp+j+2) ) ;
/* store */
*(gdat+index) = res ;
/* judge */
if ( is_middle(index) ) { resx += res ; }
if ( is_edge(index) ) { resy += res ; }
if ( index == 4799 ) {
resx >>= 2 ;
resy >>= 2 ;
thvalue = ((resx+resy) >> 1) ;
}
/* increment */
index++ ;
}
}
fclose( infile );
/* convert binary */
index = 0 ;
resx = 0 ;
for ( i = 0 ; i < 4800 ; i++ ) {
/* judge */
j = 0 ;
if ( *(gdat+i) > thvalue ) { j = 1 ; }
/* show */
putchar('0' + j ) ;
if ( (i % 80) == 79 ) putchar('\n') ;
/* store */
resx += j ;
if ( (i % 10) == 9 ) {
*(gdatx+index) = resx ;
resx = 0 ;
index++ ;
}
}
/* local */
for ( j = 0 ; j < 60 ; j++ ) {
/* block summuation */
index = (j << 3) ;
res = 0 ;
for ( i = 0 ; i < 8 ; i++ ) { res += *(gdatx+index+i) ; }
/* average */
res >>= 3 ;
/* convert */
for ( i = 0 ; i < 8 ; i++ ) {
resx = 0 ;
if ( *(gdatx+index+i) >= res ) { resx = 1 ; }
*(gdatx+index+i) = resx ;
}
/* concatenate */
resx = 0 ;
for ( i = 0 ; i < 8 ; i++ ) {
resx = (resx << 1) + *(gdatx+index+i) ;
}
/* reverse save */
*(sdat+59-j) = resx ;
}
/* show */
for ( i = 0 ; i < SDAT_SIZE ; i++ ) {
printf("%2d ",i);
printf("0x%02X ",*(sdat+i));
binary_display( *(sdat+i) );
put_pattern( *(sdat+i) );
}
}
CUIのコードで、実質100行程度になります。
目次
前
次