FC2カウンター FPGAの部屋 Vivado HLS を使用した車の白線検出10(ラプラシアンフィルタ1)
fc2ブログ

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

FPGAの部屋

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

Vivado HLS を使用した車の白線検出10(ラプラシアンフィルタ1)

ZYBO 上のOpenCV で白線検出3(Canny フィルタのみの場合)”でZYBO のLinux 上でソフトウェアによる白線検出のめどはついた。
しかし、これは、ソフトウェアのみによる白線検出で、ハードウェアにオフロードにしていないのは寂しい。”Vivado HLS を使用した車の白線検出9(Canny フィルタ3)”で road_1.jpg については白線検出を行うことができたが、road_2.jpg についてはどうスレッショルドを変更しても白線検出を行うことができなかった。これは、ハードウェアによる白線検出の精度が低いという感じがした。
そこで、もう一度、Canny フィルタのアルゴリズムを”Canny Edge Detection -アルゴリズム-”で勉強した。”Canny Edge Detection -アルゴリズム-”によると、

Canny Edge Detectionのアルゴリズムは次の手順。
STEP1:ガウシアンフィルタで平滑化
STEP2:エッジ強度と勾配方向(4方向に量子化)を計算
STEP3:細線化処理(Non-maximum Suppression)
STEP4:ヒステリシス閾処理(Hysteresis Threshold)


エッジ強度と細線化処理を行っているが、これをラプラシアンフィルタに置き換えたらどうか?と考えてみた。ラプラシアンフィルタ処理後のエッジはすでに細線化されているような感じだし、行けるかもしれない?ということで実際にやってみることにした。
ソースファイルの lap_filter_cpp の一部を示す。なお、これは、”ka367/Lane-Detecting-Using-Hough-Transform”のtop.cpp を元に大幅に修正を加えている。なお、 hls::Filter2D()のコードは”hls::Filter2D and cv::Filter2D gives different results”を参考にさせて頂いた。

void lap_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols, int threshold_low, int threshold_high) {
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=threshold_high
#pragma HLS INTERFACE s_axilite port=threshold_low
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output
#pragma HLS INTERFACE axis port=input

#pragma HLS INTERFACE ap_stable port=rows
#pragma HLS INTERFACE ap_stable port=cols

    RGB_IMAGE src(rows, cols);
    RGBSINGLE_IMAGE src_bw(rows, cols);
    RGBSINGLE_IMAGE src_blur(rows, cols);
    RGBSINGLE_IMAGE lap_fil(rows, cols);
    RGB_IMAGE lap_fil_color(rows, cols);
    RGB_IMAGE lap_edges(rows, cols);
  
//#pragma HLS dataflow
    // AXI to RGB_IMAGE stream
    hls::AXIvideo2Mat( input, src );

  // Grayscaling
    hls::CvtColor<HLS_RGB2GRAY>( src, src_bw );

    // Gaussian Blur Noise Reduction
    hls::GaussianBlur<5,5>( src_bw, src_blur );
    //hls::GaussianBlur<3,3>( src_bw, src_blur);

    // Calculate laplacian filter
    const int lap_weight[3][3] = {{-1, -1, -1},{-18, -1},{-1, -1, -1}};
    hls::Window<33int> kernel;
    hls::Point_<int> anchor;

    for (int i=0; i<3; i++){
        for (int j=0; j<3; j++){
            kernel.val[i][j] = lap_weight[i][j];
        }
    }
    anchor.x = -1;
    anchor.y = -1;
    hls::Filter2D(src_blur, lap_fil, kernel, anchor);

    // gray to color
    hls::CvtColor<HLS_GRAY2BGR>( lap_fil, lap_fil_color );

    // Perform hysteresis thresholding for edge tracing
    hysteresis( lap_fil_color, lap_edges, threshold_low, threshold_high );

    hls::Mat2AXIvideo(lap_edges, output );
}


次にテストベンチのLane-Detecting_tb.cpp を示す。

// Lane-Detecting_tb.cpp
// 2016/05/22 by marsee
// OpenCV 2 の Mat を使用したバージョン
// Vivado HLSでは Canny フィルタのみハードウェア化した。OpenCV で処理したCannyフィルタとHough変換を行って比較する。

#include <iostream>
#include "hls_opencv.h"
#include "lap_filter.h"

using namespace cv;

void lap_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols, int threshold_low, int threshold_high);
void opencv_lap_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size);

int main (int argc, char** argv) {
    //const int threshold_low = 50;
    //const int threshold_high = 200;
    const int threshold_low = 40;
    const int threshold_high = 50;
    const int sobel_size = 3;

    // OpenCV で 画像を読み込む
    Mat src = imread(INPUT_IMAGE);
    AXI_STREAM src_axi, dst_axi;

    // Mat フォーマットから AXI4 Stream へ変換
    cvMat2AXIvideo(src, src_axi);

    // image_filter() 関数をコール
    lap_filter(src_axi, dst_axi, src.rows, src.cols, threshold_low, threshold_high);

    // AXI4 Stream から Mat フォーマットへ変換
    // dst は宣言時にサイズとカラー・フォーマットを定義する必要がある
    Mat dst(src.rows, src.cols, CV_8UC3);
    AXIvideo2cvMat(dst_axi, dst);
    imshow("Vivado HLS lap_filter", dst);

    // opencv_image_filter() をコール
    Mat dst_cv(src.rows, src.cols, CV_8UC3);
    opencv_lap_filter(src, dst_cv, 200300, sobel_size);
    imshow("OpenCV Canny filter", dst_cv);

    // Vivado HLS の Canny filter の Hough変換
    // detect lines
    vector<Vec2f> lines;
    Mat gray_dst;
    cvtColor(dst, gray_dst, CV_BGR2GRAY);
    HoughLines(gray_dst, lines, 1, CV_PI/18012000);

    // 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( dst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    imwrite(OUTPUT_IMAGE, dst);

    // OpenCV の Canny filter の Hough変換
    // detect lines
    Mat cdst_cv;
    cvtColor(dst_cv, cdst_cv, CV_GRAY2BGR);

    HoughLines(dst_cv, lines, 1, CV_PI/18015000);

    // 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_cv, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
    imwrite(OUTPUT_IMAGE_GOLDEN, cdst_cv);

    printf("Test with 0 errors.\n");

    imshow("Detect lines of Vivado HLS lap_filter", dst);
    imshow("Detect lines of OpenCV", cdst_cv);

    waitKey();

    return 0;
}

void opencv_lap_filter(Mat& src, Mat& dst, int threshold_low, int threshold_high, int sobel_size){
    Canny(src, dst, (double)threshold_low, (double)threshold_high, sobel_size);
}


Vivado HLS 2016.1 のプロジェクトの Lane-Detecting_cf_2 を示す。
Lane-Detecting_90_160601.png

これで、test_1080p.bmp と road_1.jpg, road_2.jpg, road_3.jpg, road_4.jpg の白線検出を行った。

最初は、test_1080.bmp から白線検出結果を示す。
Lane-Detecting_85_160531.jpg

次に、road_1.jpg の白線検出結果を示す。
Lane-Detecting_86_160531.jpg

road_2.jpg の白線検出結果を示す。
Lane-Detecting_87_160531.jpg

road_3.jpg の白線検出結果を示す。
Lane-Detecting_88_160531.jpg

road_4.jpg の白線検出結果を示す。
Lane-Detecting_89_160601.jpg

思いがけなく良好な結果と言えるのではないだろうか?HLSビデオライブラリを使用したハードウェアの方は、余計な線を検出しているが、それは家の屋根の端のエッジを検出しているようだ。これは、画像の下半分をHoughLine変換することで、取り除くことができると思う。

  1. 2016年06月01日 04:23 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/3481-2f76afba
この記事にトラックバックする(FC2ブログユーザー)