目次

画像処理検討

 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値化には閾値が必要なので、次のように求めます。
  1. カメラで、コースを撮影
  2. 29ラインの80ピクセル取得
  3. 0、79ピクセルの輝度の相加平均を黒とする
  4. 39、40ピクセルの輝度の相加平均を白とする
  5. 30ラインの80ピクセル取得
  6. 0、79ピクセルの輝度の相加平均を黒とする
  7. 39、40ピクセルの輝度の相加平均を白とする
  8. 2ラインの黒の相加平均を求める
  9. 2ラインの白の相加平均を求める
  10. 白と黒の相加平均を、閾値とする
 走行前のスタートトリガー待ち状態中に、閾値を求めます。  2秒程度で閾値を求められるので、競技進行を妨げないでしょう。  走行中は、次のシーケンスで2値化して保存します。
  1. ピクセルデータ取得
  2. 閾値と比較し、1か0を設定
  3. 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行程度になります。
目次

inserted by FC2 system