FC2カウンター FPGAの部屋 FASTXコーナー検出による物体の形状検出2(Vivado HLS 2016.4 プロジェクト)

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

FPGAの部屋

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

FASTXコーナー検出による物体の形状検出2(Vivado HLS 2016.4 プロジェクト)

FASTXコーナー検出による物体の形状検出1(Vivado 2016.4 プロジェクト)”の続き。

前回は、Vivado 2016.1 のカメラ画像から FASTX コーナー検出を行うプロジェクトをVivado 2016.4 に変換して動作を確認した。
今回は、後先違ってしまったが、FASTX コーナー検出を行う fastx.cpp のVivado HLS 2016.4 プロジェクトを示す。
前回やったときはC/RTL協調シミュレーションが出来なかったが、今回はできるだろうか?(前回やったVivado HLS 2016.1 のプロジェクトは、”FASTXコーナー検出IPのカメラ表示システム3(Vivado HLS 2016.1でやってみた1)”を参照のこと)

まずは、fastx プロジェクトを示す。
fastx_11_170202.png

C シミュレーションを行った。相変わらず、エラーがたくさん出ている。
fastx_11_170202.png

C コードの合成を行った。
fastx_13_170202.png

Vivado HLS 2016.1 の使用リソースと比べると、明らかにVivado HLS 2016.4 のほうが使用リソースが少ない。Vivado HLS が進化しているようだ。

C/RTL協調シミュレーションを行った。
fastx_14_170202.png

Vivado HLS 2016.1 では完了しなかったC/RTL協調シミュレーションがVivado HLS 2016.4 では完了した。
500587 クロックだった。1ピクセル1クロックとすると、480000 クロックなので、1ピクセル当たりの平均処理クロック数は、500587 / 480000 ≒ 1.04 クロックだった。

C/RTL協調シミュレーション波形を示す。
まずはAXI4-Stream の全体のシミュレーション波形を示す。
fastx_15_170202.png

1行分拡大してみた。
fastx_16_170202.png

更に、1行の終了部分と次の行の開始部分を拡大した。
fastx_17_170202.png

やはり、1行の処理が終了した後と次の行が始まる前にWait が入る。

最後のIP へのエクスポートを行った。
fastx_18_170202.png

Vivado RTL Synthesis にチェックを入れてOK ボタンをクリックした。

IP へのエクスポートの結果を示す。
fastx_19_170202.png

Timing もメットしている。

fastx.h を貼っておく。

// 2016/04/03 : GRAY_IMAGE を追加

#ifndef __FASTX_H__
#define __FASTX_H__

#include "ap_axi_sdata.h"
#include "hls_video.h"

#define MAX_HEIGHT    600
#define MAX_WIDTH    800

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef hls::Scalar<3unsigned char> RGB_PIXEL;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC1> GRAY_IMAGE;
#endif


fastx.cpp を貼っておく。

// fastx.cpp
// 2016/04/02 by marsee
// 2016/04/09 : FAST Corners Detection

#include "fastx.h"

void fastx_corner_det(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM, int rows, int cols, int threshold) {
#pragma HLS INTERFACE ap_stable port=threshold
#pragma HLS INTERFACE s_axilite port=threshold
#pragma HLS DATAFLOW
#pragma HLS INTERFACE ap_stable port=cols
#pragma HLS INTERFACE ap_stable port=rows
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis port=OUTPUT_STREAM
#pragma HLS INTERFACE axis port=INPUT_STREAM
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows

    RGB_IMAGE img_0(rows, cols);
    RGB_IMAGE img_1(rows, cols);
    RGB_IMAGE img_1_(rows, cols);
#pragma HLS STREAM variable=img_1_.data_stream depth=8192
    // FASTX に最大 7 ラインのレイテンシ、Dilate に最大 3 ラインのレイテンシがあるそうだ
    // 1ラインのピクセル数X10 ラインのFIFO バッファが必要 800x10 < 8192 (2の13乗)
    // http://japan.xilinx.com/support/documentation/application_notes/xapp1167.pdf
    // の 10 ページ参照

    GRAY_IMAGE img_1g(rows, cols);
    GRAY_IMAGE mask(rows, cols);
    GRAY_IMAGE dmask(rows, cols);
    GRAY_IMAGE img_2g(rows, cols);
    RGB_IMAGE img_3(rows, cols);
    RGB_PIXEL color(25500);

    hls::AXIvideo2Mat(INPUT_STREAM, img_0);
    hls::Duplicate(img_0, img_1, img_1_);
    hls::CvtColor<HLS_BGR2GRAY>(img_1, img_1g);
    hls::FASTX(img_1g, mask, threshold, true);
    hls::Dilate(mask, dmask);
    hls::PaintMask(img_1_, dmask, img_3, color);
    hls::Mat2AXIvideo(img_3, OUTPUT_STREAM);
}


fastx_tb.cpp を貼っておく。

// fastx_tb.cpp
// 2016/04/02 by marsee
// OpenCV 2 の Mat を使用したバージョン
// 2016/04/09 : FAST Corners Detection

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

using namespace cv;

#define INPUT_IMAGE     "test.jpg"
#define OUTPUT_IMAGE    "test_result.jpg"
#define OUTPUT_IMAGE_CV "test_result_cv.jpg"

#define THESHOLD_LEVEL    60

void fastx_corner_det(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM, int rows, int cols, int threshold);
void opencv_fastx_corner_det(Mat& src, Mat& dst, int threshold);

int main (int argc, char** argv) {
    // OpenCV で 画像を読み込む
    Mat src = imread(INPUT_IMAGE);
    AXI_STREAM src_axi, dst_axi;

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

    // fastx_corner_det() 関数をコール
    fastx_corner_det(src_axi, dst_axi, src.rows, src.cols, THESHOLD_LEVEL);

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

    // Mat フォーマットからファイルに書き込み
    imwrite(OUTPUT_IMAGE, dst);

    // opencv_fastx_corner_det() をコール
    Mat dst_cv(src.rows, src.cols, CV_8UC3);
    opencv_fastx_corner_det(src, dst_cv, THESHOLD_LEVEL);
    imwrite(OUTPUT_IMAGE_CV, dst_cv);

    // dst と dst_cv が同じ画像かどうか?比較する
    for (int y=0; y<src.rows; y++){
        Vec3b* dst_ptr = dst.ptr<Vec3b>(y);
        Vec3b* dst_cv_ptr = dst_cv.ptr<Vec3b>(y);
        for (int x=0; x<src.cols; x++){
            Vec3b dst_bgr = dst_ptr[x];
            Vec3b dst_cv_bgr = dst_cv_ptr[x];

            // bgr のどれかが間違っていたらエラー
            if (dst_bgr[0] != dst_cv_bgr[0] || dst_bgr[1] != dst_cv_bgr[1] || dst_bgr[2] != dst_cv_bgr[2]){
                printf("x = %d, y = %d,  Error dst=%d,%d,%d dst_cv=%d,%d,%d\n", x, y,
                        dst_bgr[0], dst_bgr[1], dst_bgr[0], dst_cv_bgr[0], dst_cv_bgr[1], dst_cv_bgr[2]);
                //return 1;
            }
        }
    }
    printf("Test with 0 errors.\n");

    return 0;
}

void opencv_fastx_corner_det(Mat& src, Mat& dst, int threshold){
     src.copyTo(dst); // 深いコピー
     std::vector<Mat> layers;
     std::vector<KeyPoint> keypoints;
     split(src, layers);
     FAST(layers[0], keypoints, threshold, true);
     for (int i = 0; i < keypoints.size(); i++) {
         rectangle(dst,
                 Point(keypoints[i].pt.x-1, keypoints[i].pt.y-1),
                 Point(keypoints[i].pt.x+1, keypoints[i].pt.y+1),
                 Scalar(255,0), CV_FILLED);
     }
}

  1. 2017年02月02日 04:52 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3710-8a6d9219
この記事にトラックバックする(FC2ブログユーザー)