次は、今のガボールフィルタのままだと、右白線、左白線とCPUで設定する必要があるから、CPUで左右を設定してから、ガボール・フィルタ処理結果を取得する必要がある。これはフレームレートが遅くなってしまう。
そこで、左右白線の2フレーム1セットでガボールフィルタ処理を行うことにする。左右は当然異なるフレームバッファにDMAする。その為にVDMAを4フレーム対応にして左右左右のフレームバッファにライトする。
これで左右白線用ガボールフィルタはカメラのフレームレートが15 fps だから、半分の 7.5 fps でデータが取得できる。
このエッジをとりあえずはCPUで探索して、どの位置にいるかを確認することにしよう。
// Gabor_filter_lh_2.h
// 2016/07/24
// 2016/07/25 : 右白線検出用のGabor Filterの重みを追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
//
#ifndef __Gabor_filter_lh_H__
#define __Gabor_filter_lh_H__
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
//#define HORIZONTAL_PIXEL_WIDTH 640 // for Simulation
//#define VERTICAL_PIXEL_WIDTH 480
//#define HORIZONTAL_PIXEL_WIDTH 64
//#define VERTICAL_PIXEL_WIDTH 48
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
#define ARRAY_SIZE 9
#define RIGHT_WEIGHT 1
#define LEFT_WEIGHT 0
#define L_R_WEIGHT 2
const int gabor_weight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用
{
{0,-3,-10,-16,-7,7,10,5,1},
{-3,-15,-27,-11,32,50,29,5,-2},
{-11,-24,-5,73,135,95,16,-17,-10},
{-11,4,85,187,160,14,-72,-52,-14},
{4,51,135,137,-18,-159,-136,-45,-2},
{16,50,59,-39,-179,-185,-73,3,13},
{10,12,-25,-104,-131,-60,15,27,11},
{1,-7,-31,-48,-24,18,29,14,3},
{-1,-5,-9,-4,10,16,10,2,-1}
},
{
{1,5,7,1,-12,-17,-10,-3,0},
{1,11,33,45,21,-16,-27,-15,-4},
{-8,-5,35,107,131,69,-2,-21,-11},
{-17,-47,-51,40,169,187,93,13,-7},
{-8,-54,-134,-147,-18,123,130,58,11},
{9,-6,-82,-185,-187,-65,36,44,17},
{11,24,12,-55,-125,-112,-43,1,7},
{3,14,30,23,-13,-41,-33,-12,-1},
{0,2,9,17,14,1,-6,-5,-2}
}
};
const float gabor_fweight[2][ARRAY_SIZE][ARRAY_SIZE] = { // 左白線検出用+右白線検出用(float)
{
{0.001282,-0.009914,-0.04062,-0.060586,-0.027574,0.026072,0.038427,0.018191,0.003056},
{-0.012155,-0.057448,-0.104645,-0.042953,0.123263,0.197238,0.114451,0.020448,-0.007239},
{-0.042252,-0.093065,-0.018911,0.285374,0.525746,0.372687,0.060734,-0.064748,-0.040465},
{-0.042261,0.015673,0.332798,0.728763,0.625046,0.053591,-0.283076,-0.203293,-0.05608},
{0.017342,0.198305,0.52554,0.535526,-0.069756,-0.622839,-0.531089,-0.177366,-0.006367},
{0.060866,0.19708,0.231032,-0.154219,-0.699885,-0.721808,-0.286707,0.013004,0.049249},
{0.038379,0.04877,-0.098477,-0.404993,-0.510165,-0.233566,0.057894,0.104366,0.041887},
{0.0047,-0.0278,-0.121277,-0.187262,-0.093276,0.070512,0.113857,0.055799,0.009976},
{-0.003798,-0.01885,-0.035607,-0.01709,0.037692,0.064268,0.038606,0.007536,-0.002133}
},
{
{0.005562,0.018882,0.028293,0.004499,-0.044995,-0.064838,-0.039469,-0.009822,0.000815},
{0.002294,0.04108,0.127023,0.175094,0.083025,-0.063755,-0.106402,-0.057798,-0.01406},
{-0.031269,-0.021096,0.135641,0.417286,0.512467,0.269946,-0.008354,-0.082091,-0.041357},
{-0.066348,-0.184919,-0.197802,0.15614,0.65976,0.728616,0.361674,0.052074,-0.027152},
{-0.031146,-0.211178,-0.523777,-0.573856,-0.069756,0.480311,0.506451,0.225223,0.041031},
{0.035552,-0.023892,-0.320104,-0.723563,-0.728735,-0.253689,0.1391,0.170625,0.067723},
{0.04216,0.094939,0.047511,-0.216623,-0.488075,-0.437898,-0.168739,0.003336,0.027009},
{0.012112,0.056596,0.115239,0.090332,-0.05076,-0.158403,-0.127847,-0.046375,-0.004918},
{-0.00168,0.007437,0.036985,0.067021,0.053689,0.004977,-0.02365,-0.018248,-0.005928}
}
};
#endif
// Gabor_fiter_lh_2.cpp
// 2016/07/23 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
// 2016/07/27 : 右白線検出用配列と左白線検出用配列を統合
// 2016/08/29 : 1回目左白線検出、2回目右白線検出のモードを追加
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>
#include "Gabor_filter_lh_2.h"
int conv_rgb2y(int rgb);
int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins,
hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL){
#pragma HLS INTERFACE s_axilite port=RorL
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> gabor;
hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;
int gray_pix, val, i, j, x, y;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int k=0; k<2; k++){
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
mbuf.shift_left(); // mbuf の列を1ビット左シフト
for(i=ARRAY_SIZE-2; i>=0; --i){
mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
}
gray_pix = conv_rgb2y(pix.data);
mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);
// LineBuffer の更新
linebuf.shift_down(x);
linebuf.insert_bottom(gray_pix, x);
// 使用する配列を決定する
int ano;
switch (RorL){
case LEFT_WEIGHT :
ano = LEFT_WEIGHT;
break;
case RIGHT_WEIGHT :
ano = RIGHT_WEIGHT;
break;
case L_R_WEIGHT :
if (k == 0)
ano = LEFT_WEIGHT;
else
ano = RIGHT_WEIGHT;
break;
default :
ano = LEFT_WEIGHT;
break;
}
// Gabor filter の演算
for (j=0, val=0; j<ARRAY_SIZE-1; j++){
for (i=0; i<ARRAY_SIZE-1; i++){
val += gabor_weight[ano][j][i] * mbuf(ARRAY_SIZE-1-j,i);
}
}
val = val/256; // 256倍してあるので、1/256して戻す
if (val<0)
//val = -val; // 絶対値
val = 0; // マイナスの値を0に丸める
else if (val>255)
val = 255;
// Gabor filter・データの書き込み
gabor.data = (val<<16)+(val<<8)+val;
// 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
gabor.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
gabor.user = 1;
else
gabor.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
gabor.last = 1;
else
gabor.last = 0;
outs << gabor; // AXI4-Stream へ出力
}
}
}
return(0);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// Gabor_filter_lh_2_tb.cpp
// 2016/07/24 by marsee
// 2016/07/25 : 右白線検出用のGabor Filterを追加して、右左の白線を指定するRorL 引数を追加
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>
#include "Gabor_filter_lh_2.h"
#include "bmp_header.h"
int Gabor_filter_lh_2(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL);
int conv_rgb2y_soft(int rgb);
int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL);
#define CLOCK_PERIOD 10
#define RIGHT_OR_LEFT L_R_WEIGHT
#define BMP_FILE_NAME "road_1.bmp"
int main()
{
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins;
hls::stream<ap_axis<32,1,1,1> > ins_soft;
hls::stream<ap_axis<32,1,1,1> > outs;
hls::stream<ap_axis<32,1,1,1> > outs_soft;
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> vals;
ap_axis<32,1,1,1> vals_soft;
int m_seq = 1; // M系列の値
int i, k;
int xor_shift;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw, *fbmpwf;
int *rd_bmp, *hw_gabor, *sw_gabor;
int blue, green, red;
ap_uint<2> r_l;
char fhname[100];
char fsname[100];
if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_gabor memory\n");
exit(1);
}
if ((sw_gabor =(int *)malloc(2 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_gabor memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
}
// 2画面分を入力する
for(int k=0; k<2; k++){
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
}
r_l = (ap_uint<2>)RIGHT_OR_LEFT;
Gabor_filter_lh_2(ins, outs, r_l);
Gabor_filter_lh_2_soft(ins_soft, outs_soft, r_l);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(k=0; k<2; k++){
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val;
sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+(j*bmpihr.biWidth)+i] = (int)val_soft;
//printf("k=%d, j=%d, i=%d\n",k,j,i);
if ((double)pow((double)(val&0xff)-(val_soft&0xff),(double)2) > 4){ // 2乗誤差が4よりも大きい
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %08x, SW = %08x\n", i, j, (int)val, (int)val_soft);
//return(1);
}
//if (vals.last)
//cout << "AXI-Stream is end" << endl;
}
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
// ハードウェアのラプラシアンフィルタの結果を temp_gabor0.bmp, temp_gabor1.bmp へ出力する
for(k=0; k<2; k++){
if(k == 0){
if ((fbmpw=fopen("temp_gabor0.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_gabor0.bmp by binary write mode\n");
exit(1);
}
} else {
if ((fbmpw=fopen("temp_gabor1.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_gabor1.bmp by binary write mode\n");
exit(1);
}
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (hw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
}
// ソフトウェアのラプラシアンフィルタの結果を temp_gabor_float0.bmp, temp_gabor_float1.bmp へ出力する
for(k=0; k<2; k++){
if (k == 0){
if ((fbmpwf=fopen("temp_gabor_float0.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_gabor_float0.bmp by binary write mode\n");
exit(1);
}
} else {
if ((fbmpwf=fopen("temp_gabor_float1.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_gabor_float1.bmp by binary write mode\n");
exit(1);
}
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpwf);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpwf);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpwf);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpwf);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpwf);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpwf);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (sw_gabor[bmpihr.biWidth*bmpihr.biHeight*k+((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpwf);
fputc(green, fbmpwf);
fputc(red, fbmpwf);
}
}
fclose(fbmpwf);
}
free(rd_bmp);
free(hw_gabor);
return 0;
}
int Gabor_filter_lh_2_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, ap_uint<2> & RorL){
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> gabor;
hls::LineBuffer<ARRAY_SIZE-1, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
hls::Window<ARRAY_SIZE, ARRAY_SIZE, int> mbuf;
int gray_pix, val, i, j, x, y;
float valf;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int k=0; k<2; k++){
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
mbuf.shift_left(); // mbuf の列を1ビット左シフト
for(i=ARRAY_SIZE-2; i>=0; --i){
mbuf.insert(linebuf(i,x), i+1, ARRAY_SIZE-1);
}
gray_pix = conv_rgb2y_soft(pix.data);
mbuf.insert(gray_pix, 0, ARRAY_SIZE-1);
// LineBuffer の更新
linebuf.shift_down(x);
linebuf.insert_bottom(gray_pix, x);
// 使用する配列を決定する
int ano;
switch (RorL){
case LEFT_WEIGHT :
ano = LEFT_WEIGHT;
break;
case RIGHT_WEIGHT :
ano = RIGHT_WEIGHT;
break;
case L_R_WEIGHT :
if (k == 0)
ano = LEFT_WEIGHT;
else
ano = RIGHT_WEIGHT;
break;
default :
ano = LEFT_WEIGHT;
break;
}
// Gabor filter の演算
for (j=0, valf=0; j<ARRAY_SIZE-1; j++){
for (i=0; i<ARRAY_SIZE-1; i++){
valf += gabor_fweight[ano][j][i] * (float)mbuf(ARRAY_SIZE-1-j,i);
}
}
val = (int)valf;
if (val<0)
//val = -val; // 絶対値
val = 0; // マイナスの値を0に丸める
else if (val>255)
val = 255;
// Gabor filter・データの書き込み
gabor.data = (val<<16)+(val<<8)+val;
// 最初のARRAY_SIZE-1行とその他の行の最初のARRAY_SIZE-1列は無効データなので0とする
if (x<(ARRAY_SIZE-1) || y<(ARRAY_SIZE-1))
gabor.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
gabor.user = 1;
else
gabor.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
gabor.last = 1;
else
gabor.last = 0;
outs << gabor; // AXI4-Stream へ出力
}
}
}
return(0);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | - | - | - | - |