FC2カウンター FPGAの部屋 ZYBO

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

FPGAの部屋

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

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム6(アプリの変更と30fpsへ)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム5(ILAコアの削除)”の続き。

前回は、Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システムから 2 つの ILA コアを削除した。今回は、アプリケーションソフトを整備した後で、15 fps のカメラのフレームレートを 30 fps に変更する。

まずは、DMA_Read_addr IP の動作モードのDMA_WRITE_MODE はDMA_Write IP の書き込んでいる画像フレームの1つ前の画像フレームからDMA Read しているモードでこれは正常に動作している。問題は、FREE_RUM_MODE で、これは、3 つの画像フレームからフリーランで読んでるモードなのだが、15 fps でカメラがWrite していて、60 fps でビットマップ・ディスプレイ・コントローラがRead するので、画像フレームバッファが 3 つあると現在、過去が入り混じって画像がぶれてしまう。よって、FREE_RUM_MODE の場合は、画像フレームを 1 つにする必要があるようだ。そのように変更したところ、画像がぶれることは無くなった。
DMA_Read_IP_85_170320.png

cam_disp_hls.c を貼っておく。

/* * cam_disp_hls.c * *  Created on: 2016/08/21 *      Author: Masaaki */


#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xdma_read_addr.h"
#include "xdma_write.h"
#include "sleep.h"

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

#define FRAME_BUFFER_ADDRESS 0x10000000

#define DMA_WRITE_MODE
//#define FREE_RUN_MODE

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XDma_read_addr  dmar, *dmarp;
    XDma_write      dmaw, *dmawp;

    dmarp = &dmar;
    dmawp = &dmaw;

    // Initialization of DMA Read
    if (XDma_read_addr_Initialize(dmarp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Read open error\n");
        exit(-1);
    }

    // Initialization of DMA Write
    if (XDma_write_Initialize(dmawp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Write open error\n");
        exit(-1);
    }

    // frame buffer settings
#ifdef DMA_WRITE_MODE
    XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS);
    XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);

    XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
#else // FREE_RUN_MODE
    XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS);
    XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS);
    XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS);

    XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS);
#endif

    // DMA_read_addr mode set
#ifdef DMA_WRITE_MODE
    XDma_read_addr_Set_mode_V(&dmar, 0); // DMA_WRITE_MODE
#else // FREE_RUN_MODE
    XDma_read_addr_Set_mode_V(&dmar, 1); // FREE_RUN_MODE
#endif

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cont_axis_0
    volatile unsigned int *mt9d111_axiL;
    volatile unsigned int *cam_iic_axiL;
    volatile unsigned int *bmdc_axiL;

    mt9d111_axiL = (volatile unsigned int *)XPAR_MT9D111_INF_AXIS_0_BASEADDR;
    cam_iic_axiL = (volatile unsigned int *)XPAR_AXI_IIC_0_BASEADDR;
    bmdc_axiL = (volatile unsigned int *)XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR;

    // bitmap_disp_cont_axis_0 is started
    bmdc_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // DMA Start
    XDma_read_addr_DisableAutoRestart(&dmar);
    while(!XDma_read_addr_IsIdle(&dmar)) ;
    XDma_read_addr_Start(&dmar);
    XDma_read_addr_EnableAutoRestart(&dmar);

    XDma_write_DisableAutoRestart(&dmaw);
    while(!XDma_write_IsIdle(&dmaw)) ;
    XDma_write_Start(&dmaw);
    XDma_write_EnableAutoRestart(&dmaw);

    // mt9d111_inf_axis_0 is started
    mt9d111_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(cam_iic_axiL);

    cam_i2c_write(cam_iic_axiL, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(cam_iic_axiL, 0xba, 0x970x20);     // RGB Mode, RGB565

    mt9d111_axiL[1] = 0// One_shot_mode is disabled

    return(0);
}


これで、FREE_RUM_MODE も問題が無くなったので、次は、カメラのフレームレートを 15 fps から 30 fps に向上させることにした。
やり方は、”MT9D111のフレームレートを 15 fps から 30 fps にした”に書いておいた。
早い話が、カメラに供給するクロックを 36 MHz から倍の 72 MHz に変更するということだ。それに合わせて制約も変更する。
具体的には、PS からのクロックの FCLK_CLK2 の周波数設定を 36 MHz から 72 MHz に変更した。
DMA_Read_IP_86_170320.png

もう一度、論理合成、インプリメント、ビットストリームの生成を行い、ハードウェアをエクスポートして、SDKを立ち上げた。
これで、画像のフレームレートが 15 fps から 30 fps に向上した。

このDMAWrite IPとDMA_Read_addr IP の組は使えそうだ。AXI VDMAの説明書を読まなくても簡単に使えるところが良いと思う。
願わくば、DMA_Read_addr IP を使うときのツールのバグが直ってほしいと思う。
  1. 2017年03月24日 05:17 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム5(ILAコアの削除)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム4(ILAコアの挿入2)”の続き。

前回、Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システムが動作した。しかし、ブロックデザイン上で挿入したILA コアとネットリストの信号を観察するため入れたILA コアが残ってしまっている。それを削除した。

まずは、ブロックデザイン上で挿入したILA コアを削除しよう。

Debug にマーキングされた配線を複数選択して、右クリックし、右クリックメニューからClear Debug を選択する。
DMA_Read_IP_76_170320.png

ILA コアの system_ila が削除された。
DMA_Read_IP_77_170320.png

これで、ブロックデザイン上で挿入したILA コアが削除された。
次に、ネットリストの信号を観察するため入れたILA コアを削除する。

論理合成を行って、成功後に表示されるSynthesis Completed ダイアログで Open Synthesized Design を選択した。
DMA_Read_IP_78_170320.png

Synthesized Design が表示された。Tools -> Set Up Debug... を選択した。
DMA_Read_IP_79_170320.png

Set Up Debug ダイアログが表示された。Next ボタンをクリックした。
DMA_Read_IP_80_170320.png

Existing Debug Nets で、Disconnect all net and remove debug cores を選択した。
DMA_Read_IP_81_170320.png

Set Up Debug Summary が表示された。Finish ボタンクリックした。
DMA_Read_IP_82_170320.png

ネットリストの信号を観察するため入れたILA コアが削除された。
DMA_Read_IP_83_170320.png

確か、制約ファイルの ILA コア関連の制約は削除されたが、1つ ILA コアの制約が残っていたので、手動で削除した。

インプリメント、ビットストリームの生成を行った。結果を示す。
DMA_Read_IP_84_170320.png

ILA コアが入る前と同等のリソース使用量になった。

ハードウェアをエクスポートして、SDK を立ち上げて、カメラ画像をディスプレイに表示してみたところ正常に表示された。
DMA_Read_IP_87_170320.jpg
  1. 2017年03月23日 04:58 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム4(ILAコアの挿入2)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム3(ILAコアの挿入)”の続き。

DMA_Read_addr_0 の m_axi_in_r と outs は波形が出ていて動作しているようだった。よって今回は、AXI4-Stream 版のビットマップ・ディスプレイ・コントローラの内部信号をVivado Analyzer で確認してみよう。

Flow Navigator -> Synthesis -> Open Synthesized Design をクリックして、Synthesized Design を開く。

Tools -> Set Up Debug... を選択する。
DMA_Read_IP_56_170320.png

Set Up Debug ダイアログが開いた。
DMA_Read_IP_57_170320.png

Nets to Debug でFind Nets to Add... をクリックする。
DMA_Read_IP_58_170320.png

Find Nets で、h_count を検索してみた。
DMA_Read_IP_59_170320.png

Add Nets to Debug で信号を選択する。
DMA_Read_IP_60_170320.png

観察する信号を示す。
DMA_Read_IP_61_170320.png

次は、ILA Core Options を設定する。
DMA_Read_IP_62_170320.png

Set Up Debug Summary が表示された。
DMA_Read_IP_63_170320.png

Debug 画面が表示された。
DMA_Read_IP_64_170320.png

cam_disp_axis.xdc の制約ファイルに挿入したu_ila_0 の制約が追加された。
DMA_Read_IP_65_170320.png

インプリメント、ビットストリームの生成を行った。結果を示す。
DMA_Read_IP_66_170320.png

SDK でXilinx Tools -> Program FPGA を選択して、ビットストリームをZynq にダウンロードした。
SDK で、Hello_World を起動して、PL にクロックを供給した。
Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択した。
Hardware Manager が起動した。
Dashboard Optionsを開いて、hw_ila_2, hw_ila_3 のすべてにチェックを入れた。
DMA_Read_IP_67_170320.png

hw_ila_1 のトリガをかけた。AXI4 バス。
DMA_Read_IP_68_170320.png

hw_ila_2 のトリガをかけた。ビットマップ・ディスプレイ・コントローラのclk_disp ドメイン。
DMA_Read_IP_69_170320.png

hw_ila_3 のトリガをかけた。ビットマップ・ディスプレイ・コントローラの clk_axi ドメイン。
DMA_Read_IP_70_170320.png

SDK で cam_disp_hls.elf をRun した。
hw_ila_3 の波形を示す。diap_mode_ena が 1 にならない。しかも init_done_d1 が上がったときに、u_ila_1_war_data_count_1[7:0] が 00 ではなかった。となると、ビットマップ・ディスプレイ・コントローラを活かすのが遅いことが考えられる。
DMA_Read_IP_71_170320.png

cam_disp_hls.c のアプリケーションソフトで、DMA_read_addr の起動の後で、ビットマップ・ディスプレイ・コントローラを活かしていたのだが、これでは、ビットマップ・ディスプレイ・コントローラを活かすのが遅い。ビットマップ・ディスプレイ・コントローラを生かす記述(ピンクの四角)を DMA_read_addr の起動(青の四角)の前に持ってきた。
DMA_Read_IP_72_170320.png

これでうまくDMA Read の波形が出力された。
DMA_Read_IP_73_170320.png

画像も表示された。
DMA_Read_IP_87_170320.jpg

DMA Read とDMA Write が両方表示されている波形を示す。
DMA_Read_IP_74_170320.png
DMA_Read_IP_75_170320.png
  1. 2017年03月21日 04:08 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム3(ILAコアの挿入)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム2(SDK)”の続き。

前にやったのは半年くらい前だが、DMA Read IPが動作しないということで止まっていた。しかし、”「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション3”で論理合成しても機能シミュレーションが問題なくなったということで、もう一度やってみようと思う。

cam_disp_axis_162 プロジェクトはVivado 2016.2 なので、”Vivado 2016.2 からVivado 2016.4 へアップグレード”を参照して、Vivado 2016.4 のcam_disp_axis プロジェクトを作成した。
DMA_Read_IP_34_170319.png
当然、Target language はVHDL にしてある。

論理合成、インプリメント、ビットストリームの生成を行ったところ、成功した。
リソース使用量は以前と変化が無い。今回のProject Summary はキャプチャするのを忘れてしまったので、以前のVivado 2016.2 のときのProject Summary を貼っておく。
cam_disp_axis_6_160821.png

ハードウェアをエクスポートして、SDKを立ち上げた。
cam_disp_hls プロジェクトを作成し、cam_disp_hls.c をコピー&ペーストした。
ビットストリームをZYBO にダウンロードして、cam_disp_hls.elf を起動したが、動作しなかった。
DMA_Read_IP_35_170319.png

Vivado 2016.4 になって変わったVivado Analyzer を試してみようということで、ブロックデザインでDMA_Read_addr_0 のm_axi_in_r と outs とDMA_Write_0 の m_axi_out_r を選択して、右クリックし右クリックメニューからDebug を選択した。
DMA_Read_IP_36_170319.png

選択したラインにデバックマークが付き、上に Run Connection Automation が出るので、クリックした。
DMA_Read_IP_37_170319.png

Run Connection Automation が表示された。OK ボタンをクリックした。
DMA_Read_IP_38_170319.png

system_ila が挿入された。ILA コアがブロックデザイン上に挿入されるようになった。
DMA_Read_IP_39_170319.png

論理合成、インプリメント、ビットストリームの生成を行った。結果を示す。
DMA_Read_IP_40_170319.png
全体的にリソース使用量が増えている。これはILA コアを入れたので、当然と言えば当然だ。

Vivado Analyzer はPL の回路にクロックが来ないと起動できない。ソフトウェアを起動しないと回路にクロックが供給されないので、Vivado Analyzer は起動しない。
と言う訳で、ZYBO にビットストリームをダウンロードしてから、cam_disp_hls.elf を起動した。
DMA_Read_IP_41_170319.png

その後で、Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択した。
DMA_Read_IP_42_170319.png

Hardware Manager が立ち上がった。
DMA_Read_IP_43_170319.png

Status ペインで Run trigger immediate for this ILA core をクリックすると、すぐに波形がキャプチャされる。
DMA_Read_IP_44_170319.png

Vivado 2016.4 では、AXI バスはステータスを表示してくれるようだ。トランザクションが全く見えなかった。
DMA_Read_IP_47_170319.png

よくわからなかったので、DMA_Write_0 の ins も追加した。
DMA_Read_IP_48_170319.png

論理合成、インプリメント、ビットストリームの生成を行った。成功した。
Project Summary を示す。
DMA_Read_IP_49_170319.png

Hardware Manager で net_slot_3_axis_tvalid = R (DMA_Write_0 の ins)でトリガをかけて Run trigger for this ILA core をクリックした。
DMA_Read_IP_50_170319.png

DMA_Write_0 の ins と m_axi_out_r は波形が出力されていることが分かった。
DMA_Read_IP_51_170319.png

次に、net_slot_0_axi_arvalid = R (DMA_Read_addr_0 の m_axi_in_r)でトリガをかけたが掛からなかった。
DMA_Read_IP_52_170319.png

これは、電源ON の少し間だけのみ DMA_Read_addr_0 の m_axi_in_r と outs が動作しているかもしれない。ということで、Hello_World プロジェクトを作成し、これを起動して、PL へクロックを供給してから cam_disp_hls.elf を起動することにした。

Hello_World プロジェクトを作成した。起動した。
DMA_Read_IP_53_170319.png

Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択し、Hardware Manager を起動する。
net_slot_0_axi_arvalid = R (DMA_Read_addr_0 の m_axi_in_r)でトリガをかけた。
DMA_Read_IP_54_170319.png

これで、SDK で、cam_disp_hls.elf を起動した。すると、トリガがかかってDMA_Read_addr_0 のm_axi_in_r と outs の波形が表示された。
DMA_Read_IP_55_170319.png

これを見るときちんとDMA_Read_addr_0 の m_axi_in_r はAXI4 Master Read ができていて、AXI4-Stream の outs にもきちんと出力できているように見える。しかし、途中で tready が 1 から 0 になってしまっている。これは、AXI4-Stream 版のビットマップ・ディスプレイ・コントローラのピクセル用FIFO がフルになってしまっているからだと思われる。
AXI4-Stream 版のビットマップ・ディスプレイ・コントローラがおかしい可能性が出てきた。
  1. 2017年03月20日 07:16 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出3(Canny フィルタのみの場合)

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)”の続き。

今回は前回のコードはそのままに、10行目の”#define HIST”をコメントアウトして、equalizeHist() を使用しないで、Canny フィルタのみで白線検出を行うことにする。なお、Canny フィルタのスレッショルドは、試行錯誤して、最適化したつもりだ。

最初に、test_1080p.bmp からやってみた。
Lane-Detecting_75_160529.png

白線検出の経過時間は 0.221 sec 程度だった。前回よりも 0.057 sec 速かった。
白線検出結果を示す。
Lane-Detecting_76_160529.jpg

白線検出ができてる。なお、source ウインドウは今回はカラーで取り込んでいる。

次に road_1.jpg の結果を示す。
Lane-Detecting_77_160529.png

白線検出の経過時間は 0.416 sec 程度だった。前回は、source ウインドウは白黒だが、0.638 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_78_160529.jpg

次に road_2.jpg の結果を示す。
Lane-Detecting_79_160529.png

白線検出の経過時間は 0.414 sec 程度だった。前回は、source ウインドウは白黒だが、1.290 sec 程度だった。大幅に速くなっている。これだったら使えそうだ。1秒回に 2 回は判定できる。
白線検出結果を示す。
Lane-Detecting_80_160529.jpg

次に road_3.jpg の結果を示す。
Lane-Detecting_81_160529.png

白線検出の経過時間は 0.394 sec 程度だった。前回は、source ウインドウは白黒だが、1.300 sec 程度だった。こちらも大幅に速くなっている。
白線検出結果を示す。
Lane-Detecting_82_160529.jpg

最後に、road_4.jpg の結果を示す。
Lane-Detecting_83_160529.png

白線検出の経過時間は 0.320 sec 程度だった。前回は、source ウインドウは白黒だが、0.604 sec 程度だった。
白線検出結果を示す。
Lane-Detecting_84_160529.jpg

全体に白線検出の速度は上がっている。equalizeHist() を外したおかげもあるが、HoughLines() で検出する直線の数が経過時間に影響するようだ。
  1. 2016年05月29日 05:31 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出2(equalizeHist() を使用した場合2)

”ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)”の続き。

前回は、equalizeHist() を使用し、Canny フィルタを掛けて、HoughLine 変換で道路の白線検出を行った。しかし、画像を読み込む時点で白黒画像に変換していた。ハードウェアでは、カメラで撮影した画像を白黒変換して、Canny フィルタを掛ける予定なので、白黒画像変換の部分の経過時間も測る必要がある。それでC++ ソースコードを修正した。更に、白黒画像変換+Canny フィルタの経過時間を測定した。

Hough_example.cpp を下に示す。

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1]);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    Mat src_g;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

    cvtColor(src, src_g, CV_BGR2GRAY);
#ifdef HIST
    Mat eqst;
    equalizeHist(src_g, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    //Canny(src_g, dst, 50, 200, 3); // Normal
    Canny(src_g, dst, 2003003); // Normal2
#endif

    //gettimeofday(&end_time, NULL);
    
    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


./Hough_example test_1080p.bmp コマンドを実行した。
Lane-Detecting_72_160527.png

白線検出の経過時間は 0.278 sec 程度だった。前回は 0.273 sec だったので、約 5 ms 程度、白黒変換にかかることが分かった。

白線検出結果を示す。結果は前回と同じだが、source ウインドウがカラーなのが分かる。
Lane-Detecting_73_160527.jpg

次に、白黒画像変換+Canny フィルタの経過時間を測定する。
現在の”gettimeofday(&end_time, NULL);”の行をコメントアウトして、現在コメントになっている同様の行のコメントを外した。もう一度コンパイルして、やってみた。

すると、白黒画像変換+Canny フィルタの経過時間は、57 ms くらいのようだ。
Lane-Detecting_74_160527.png
  1. 2016年05月27日 04:07 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBO 上のOpenCV で白線検出1(equalizeHist() を使用した場合)

Vivado HLS を使用した車の白線検出9(Canny フィルタ3)”で、大体Vivado HLS による C シミュレーションでは白線検出が出来てきたと思うので、本命のZYBO のOpenCV 環境でまずはソフトウェアで、どのくらいの速度で白線検出をできるかどうかをテストしてみた。

ZYBO のUbuntu 14.04 LTS 上のOpenCV 2.4.10 で白線検出のテストを行った。
白線検出用のアプリケーションの HoughLine_example.cpp を示す。最初は、equalizeHist() を行う設定でやってみた。
Lane-Detecting_71_160526.png

// Line Detection by Hough Line Transform
// http://opencvexamples.blogspot.com/2013/10/line-detection-by-hough-line-transform.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <sys/time.h>

#define HIST

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat src;
    
    if (argc >= 1){
        src = imread(argv[1], 0);
    } else {
        printf("Usage : HoughLine_example <read_file_name>\n");
        exit(1);
    }

    Mat dst, cdst;
    struct timeval start_time, end_time;

    gettimeofday(&start_time, NULL);

#ifdef HIST
    Mat eqst;
    equalizeHist(src, eqst);
    Canny(eqst, dst, 1502503); // for equalizeHist
#else
    Canny(src, dst, 502003); // Normal
    //Canny(src, dst, 200, 300, 3); // Normal2
#endif

    cvtColor(dst, cdst, CV_GRAY2BGR);

    vector<Vec2f> lines;
    // detect lines
    HoughLines(dst, lines, 1, CV_PI/18015000);

    gettimeofday(&end_time, NULL);
    
    // draw lines
    for( size_t i = 0; i < lines.size(); i++ )
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    
    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %ld.%06ld sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }

#ifdef HIST
    imshow("equalizeHist", eqst);
#endif
    imshow("Canny", dst);
    imshow("source", src);
    imshow("detected lines", cdst);

    waitKey();
    waitKey();
    waitKey();
    waitKey();
    waitKey();
    
    return 0;
}


このアプリケーションを使用して、最初に test_1080p.bmp の白線検出をやってみた。
Lane-Detecting_61_160526.png

白線検出の経過時間は0.273 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_62_160526.jpg

良さそうだ。

次に、自分で撮影した4つの写真の白線検出結果を見た。

まずは、 road_1.jpg の白線検出を行った。
Lane-Detecting_63_160526.png

白線検出の経過時間は0.638 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_64_160526.jpg

良さそうではあるが、電線の影を検出している。

次に、road_2.jpg の白線検出を行った。
Lane-Detecting_65_160526.png

白線検出の経過時間は1.290 sec 位だった。下に白線検出の結果を示す。
Lane-Detecting_66_160526.jpg

road_1.jpg の方が逆光で、road_2.jpg の方が順光だからか?道路のちょっとした凸凹までエッジとして検出されているので、Hough変換で相当な量の直線を検出したようだ。

road_3.jpg の白線検出を行った。road_3.jpg は road_2.jpg の反対のレーンから撮影した写真なので、road_2.jpg の結果と同じような傾向になるはずだ。
Lane-Detecting_67_160526.png 

白線検出の経過時間は 1.300 sec 程度だった。下に白線検出結果を示す。
Lane-Detecting_68_160526.jpg

やはり、 road_2.jpg と同様の結果になった。

最後に、road_4.jpg の白線検出を行った。同様に、road_4.jpg は road_1.jpg と同様の写真である。
Lane-Detecting_69_160526.png

白線検出の経過時間は、0.604 程度だった。下に白線検出結果を示す。
Lane-Detecting_70_160526.jpg

road_2.jpg と road_3.jpg の白線検出が酷い気がする。equalizeHist() を使用すると、現在のパラメータでは、このカメラの順光時のアスファルト舗装の細かい凸凹がよく見えるようになってしまう。

どうやら、Hough 変換の実行時間は検出した本数が多いほど、遅くなっているのでは?と思う。
  1. 2016年05月26日 04:49 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0
»