FC2カウンター FPGAの部屋 2017年08月03日

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

白線追従走行用畳み込みニューラルネットワークの製作3(トレーニング、ラベル・ファイルの作成)

白線追従走行用畳み込みニューラルネットワークの製作2(画像縮小、切り出し)”の続き。

前回は、800 x 600 ピクセルの元画像を 60 x 45 に縮小してから、白黒変換し、56 x 10 ピクセルの白線の画像を切り出した。今回は、本格的に56 x 10 ピクセルの白線の画像を切り出すとともに、MNISTデータセットと同じフォーマットでトレーニング・ファイルとラベル・ファイルを生成しよう。
なお、ソフトを作成する際に参考にしたサイトは、”OpenCV入門 2.画像の簡単操作”だ。このサイトには、Matからピクセル値を取り出す方法が書いてある。

まずは、straight_dataset_bmp.cpp を変更した。ここに貼っておく。なお、3つ続けて、同じコードを使用して、みっともないことをお詫びしておく。
buf[0] = htonl(0x803); の htonl() だが、uint32_t を fwrite() するとリトルエンディアンでファイルに書き込まれてしまう。つまり、0x00000803 だと 03 08 00 00 と書き込まれてしまう。これではまずいので、ビックエンディアンに変更した。リトルエンディアンをビックエンディアンに変更する関数が htonl() である。

// straight_dataset_bmp.cpp
// 2017/07/24 by marsee
//

#include <iostream>
#include "hls_opencv.h"
#include "straight_dataset_bmp.h"
#include <arpa/inet.h>

int main(){
    char straight_fn[256] = "straight";
    char left_turn_fn[256] = "left_turn";
    char right_turn_fn[256] = "right_turn";
    char bmp_file[256];
    FILE *ftin, *ftln;
    char train_image_name[256] = "train_straight_run_image";
    char train_label_name[256] = "train_straight_run_label";
    uint32_t buf[5];
    uint8_t bufchar[100];


    if ((ftin = fopen(train_image_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_image_name);
        exit(1);
    }
    if ((ftln = fopen(train_label_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_label_name);
        exit(1);
    }

    // Writed header
    buf[0] = htonl(0x803); // magic number
    buf[1] = htonl(750); // number of image (750)
    buf[2] = htonl(10); // number of rows (10)
    buf[3] = htonl(56); // number of columns (56)
    fwrite(buf, sizeof(uint32_t), 4, ftin);

    buf[0] = htonl(0x801); // magic number
    buf[1] = htonl(750); // number of image (750)
    fwrite(buf, sizeof(uint32_t), 2, ftln);

    // refereed to http://opencv.jp/cookbook/opencv_img.html
    // straight
    for(int i=0; i<STRAIGHT_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s%d.bmp", straight_fn, i);
        cv::Mat straight_img = cv::imread(bmp_file,1);
        if(straight_img.empty())
            return(-1);
        cv::Mat reduct_img(straight_img.rows*0.075, straight_img.cols*0.075, straight_img.type());
        cv::resize(straight_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        sprintf(bmp_file, "%s_RED%d.bmp", straight_fn, i);
        cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", straight_fn, i, y, x);
                cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x1;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // left turn
    for(int i=0; i<LEFT_TRUN_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s%d.bmp", left_turn_fn, i);
        cv::Mat left_trun_img = cv::imread(bmp_file,1);
        if(left_trun_img.empty())
            return(-1);
        cv::Mat reduct_img(left_trun_img.rows*0.075, left_trun_img.cols*0.075, left_trun_img.type());
        cv::resize(left_trun_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        sprintf(bmp_file, "%s_RED%d.bmp", left_turn_fn, i);
        cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", left_turn_fn, i, y, x);
                cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x0;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    // right turn
    for(int i=0; i<STRAIGHT_NUM_OF_IMAGE; i++){
        sprintf(bmp_file, "%s%d.bmp", right_turn_fn, i);
        cv::Mat right_trun_img = cv::imread(bmp_file,1);
        if(right_trun_img.empty())
            return(-1);
        cv::Mat reduct_img(right_trun_img.rows*0.075, right_trun_img.cols*0.075, right_trun_img.type());
        cv::resize(right_trun_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
        cv::Mat gray_img;
        cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

        sprintf(bmp_file, "%s_RED%d.bmp", right_turn_fn, i);
        cv::imwrite(bmp_file, gray_img);

        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
                cv::Rect rect_center(x, 30+y, 5610);
                cv::Mat img_rect(gray_img, rect_center);
                sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", right_turn_fn, i, y, x);
                cv::imwrite(bmp_file, img_rect);

                for(int iy=0; iy<img_rect.rows; iy++){
                    for(int ix=0; ix<img_rect.cols; ix++){
                        bufchar[ix] = img_rect.at<uchar>(iy, ix);
                    }
                    fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
                }
                bufchar[0] = 0x2;
                fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
            }
        }
    }

    fclose(ftin);
    fclose(ftln);

    return(0);
}


次に、straight_dataset_bmp.h を貼っておく。これはバグをフィックスした。

// straight_dataset_bmp.h
// 2017/07/24 by marsee
//

#ifndef __STRAIGHT_DATASET_BMP_H__
#define __STRAIGHT_DATASET_BMP_H__

#include "hls_video.h"

#define BMP_HEIGHT    600
#define BMP_WIDTH    800

#define REDUCTION_RATIO    0.075    // 1/13.3333... 60x45

#define DATASET_HEIGHT    10
#define DATASET_WIDTH    56

#define STRAIGHT_BMP_FILE_NAME        straight
#define LEFT_TRUN_BMP_FILE_NAME        left_turn
#define RIGHT_TRUN_BMP_FILE_NAME    right_turn
#define STRAIGHT_NUM_OF_IMAGE        10
#define LEFT_TRUN_NUM_OF_IMAGE        10
#define RIGHT_TRUNNUM_OF_IMAGE        10

typedef hls::Scalar<3unsigned char> RGB_PIXEL;
typedef hls::Mat<BMP_HEIGHT, BMP_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<BMP_HEIGHT, BMP_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


straight_dataset_bmp のVivado HLS プロジェクトを示す。
wlt_cnn_11_170803.png

C シミュレーションを行った。
wlt_cnn_12_170803.png

Straight_dataset_bmp/solution1/csim/build ディレクトリの内容を示す。ここにC シミュレーションの結果のファイルがある。
wlt_cnn_13_170803.png

wlt_cnn_19_170803.png

ピンクの四角枠で示した train_straight_run_image がトレーニング・ファイルで 56 x 10 ピクセルの 750 枚分の白線の画像が入っている。411KB だ。MNISTデータのフォーマットについては、”MNIST手書き数字のデータフォーマット”を参照のこと。
train_straight_run_label がラベル・ファイルだ。左旋回が 0 、直進が 1 、右旋回が 2 のラベルが入っている。1KB だ。

train_straight_run_label の内容を示す。
wlt_cnn_18_170803.png

train_straight_run_image の最初の部分を示す。
wlt_cnn_17_170803.png

ヘッダの次の値が 0x61, 0x5F なのに注目してほしい。
この値は、left_turn_RED_rect0_00.bmp ファイルの最初の行の最初の列からの2つのピクセル値のはずだ。
GIMP2 で見てみよう。スポイトを使用して、最初の行の最初の列(0, 0)の値を抜き出してみよう。
wlt_cnn_14_170803.png

(0, 0)のピクセル値は0x61 だった。
wlt_cnn_15_170803.png

(0, 1)のピクセル値は0x5F だった。
wlt_cnn_16_170803.png

これは、 train_straight_run_image の最初の 2 つのピクセル値と一致している。
これでトレーニング・ファイルとラベル・ファイルは大丈夫の様だが、一応、トレーニング・ファイルの値を読み込んで画像を復元するアプリケーションソフトを作成してみよう。
  1. 2017年08月03日 04:52 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0