FC2カウンター FPGAの部屋 Vivado HLS

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

FPGAの部屋

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

Vivado HLS 2016.4 における assert() 文の効果3

Vivado HLS 2016.4 における assert() 文の効果2”の続き。

前回も assert() 文を使用して、演算に使用する変数の変域を指定することにより、任意精度固定小数点型の飽和演算は必要ないとVivado HLS に認識してもらい、しかもビット長も制限されることでリソース使用量の低減を図ってきた。しかし、ループカウンタのカウント数の制限によってリソース使用量が低減はされたが、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

次に、assert() 文の変域の書き方は C や C++ の if() 文の中の様に C や C++ の結合規則によって記述するということを hiyuh さんに教えてもらった。それで書き直しても、任意精度固定小数点型の通常の演算では assert() 文が効いていなかった。

もう一度、hiyuh さんに、assert() 文を入れる規則を教えてもらった。それを引用する。

assertの挿入箇所が適切ではありません.assertに与えられた条件式はその挿入箇所で評価されますので,被演算対象に対しては値が確定した演算前,代入対象については値が確定した代入後,可及的速やかに適用する必要があります.


ということで、下のソースコードで確かめてみたが、やはりリソース使用量には変化が無かった。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    temp = in0;
    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);

    //assert(limit <= 10);
    for (int i=0; i<limit; i++){
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
        temp = temp * (ap_xfix_def)2.0;
        assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    }

    assert(temp > (ap_xfix_def)(-10.0) && temp < (ap_xfix_def)10.0);
    assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    *out = temp * in1;

    return(0);
}



次に、アンシャープ・マスキング・フィルタでもう一度、検証してみよう。ソースコードを示す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// ap_fixedバージョン 2015/10/04
//

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ap_int.h>
#include <ap_fixed.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <iostream>

#include "unsharp_mask_axis.h"

using namespace std;

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
//

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88, AP_RND, AP_SAT> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1;
    y_fixed_td y;
    /*ap_ufixed<8, 8> xy[3][3];    int result=0;    ap_ufixed<8, 8, AP_RND, AP_SAT> z;    x1y1_fixed_td x1y1;    y_fixed_td y;*/

    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -xy[0][0]    -xy[0][1]        -xy[0][2]
            -xy[1][0]    +x1y1*xy[1][1]    -xy[1][2]
            -xy[2][0]    -xy[2][1]        -xy[2][2];
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = (k_fixed * y)/(y_fixed_td)9;
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));

        y = y+(y_fixed_td)0.5// 四捨五入
        assert(y > (y_fixed_td)(-10) && y < (y_fixed_td)(10));
        if (y < 0)
            z = 0;
        else if (y > 255)
            z = 255;
        else
            z = y;

        result += z.to_int()<<i; // i=0 : blue, i=8 : green, i=16 : red
    }
    return(result);
}


ヘッダファイルを示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_ufixed<K_BITLEN, K_BITLEN-NUM_ADC_K> k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION> y_fixed_td;

#define K 2.5 // 鮮鋭化の強さ

#endif


最初に assert() をコメントアウトして合成を行った。(なお、assert() 文の変域は正しくない。結果を見るためにわざと厳しい値にしてある)
assert_17_170214.png

合成後の結果を示す。
assert_18_170214.png

Analysis 結果を示す。
assert_19_170214.png

37 ステートだった。

次に assert() のコメントを外して合成を行った。
assert_20_170214.png

合成後の結果を示す。
assert_21_170214.png

Latency が 146 クロックから 131 クロックに 15 クロック減った。DSP48E, FF, LUT もすべて減っている。

Analysis 結果を示す。
assert_22_170214.png

32ステートだった。assert() 文を入れないときは、37ステートだったので、5ステート減っている。

これで、assert() 文で変数の変域を指定することにより、リソース使用量を減らせることが分かった。

最後に実際に使用予定の変数の変域を入れてみよう。
assert_23_170214.png

合成後の結果を示す。
assert_24_170214.png

やはり、assert() 文が無いのに比べてリソース使用量が減っている。

Analysis 結果を示す。
assert_25_170214.png

36ステートで、assert() 文が無いのに比べて 1 ステート減少した。
  1. 2017年02月14日 05:14 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果2

Vivado HLS 2016.4 における assert() 文の効果”の続き。

前回は、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無いという結論になったが、hiyuh さんに再度教えてもらって、もう一度やってみた。

前回の引数の変域の指定方法が間違っていた。hiyuh さんに教えてもらった C /C++ の結合則に従うということだった。それに、値をキャストするのを忘れていた。更に ap_ufixed もやってみようということでソースコードを書き換えた。
新しい ap_fixed_test.cpp を示す。
assert_7_170213.png

ap_fixed_test.cpp のソースコードを示す。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

typedef ap_fixed<16,8, AP_RND, AP_SAT> ap_xfix_def;
//typedef ap_ufixed<16,8, AP_RND, AP_SAT> ap_xfix_def;

int ap_fixed_test(ap_xfix_def in0, ap_xfix_def in1, int limit,
        ap_xfix_def *out){

    ap_xfix_def temp;

    //assert(in0 > (ap_xfix_def)(-1.0) && in0 < (ap_xfix_def)1.0);
    //assert(in1 > (ap_xfix_def)(-2.0) && in1 < (ap_xfix_def)2.0);
    //assert(*out > (ap_xfix_def)(-50.0) && *out < (ap_xfix_def)50.0);
    //assert(in0 < (ap_xfix_def)1.0);
    //assert(in1 < (ap_xfix_def)2.0);
    //assert(*out < (ap_xfix_def)50.0);

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_xfix_def)2.0;

    *out = temp * in1;

    return(0);
}


最初にもう一度、このソースコードのまま合成を行った。
assert_8_170213.png

次に、最初の 3 行の assert() 文を活かしてみよう。これは、符号あり小数の場合だ。
assert_9_170213.png

これを合成した。
assert_10_170213.png

レポートを見ると、assert() 文を活かして無い時と変わらない。

次に、ap_ufixed にして、符号なし小数の場合をやってみた。assert() 文はすべてコメントアウトしてある。
assert_11_170213.png

これを合成した。
assert_12_170213.png

符号あり少数の場合よりも、レイテンシもリソース使用量も少ない。符号なし小数で良いのであれば、大分お得ということができると思う。

次に、下の 3 つの assert() 文を活かした。
assert_13_170213.png

合成を行った。
assert_14_170213.png

assert() 文を入れたときと、入れないときでは変化が無かった。

最後に変数の temp に asset() 文を試しに入れてみた。
assert_15_170213.png

合成を行った。
assert_16_170213.png

temp 変数に assert() 文で変域を指定すると合成されなくなるようだ。
  1. 2017年02月13日 04:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2016.4 における assert() 文の効果

Vivado HLS 2016.4 で変域を指定することができる assert() 文の効果を確かめてみた。

まずは、assert() は、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2016.4) 2016 年 11 月 30 日”の 344 ページの”アサート”に書かれている。最初の1文を引用する。

C の assert マクロは、 範囲情報をアサートするのに使用される場合、 合成でサポートされます。 たとえば、 変数 とループ境界の上限を指定でき ます。


そこで、任意精度固定小数点型を使う際の問題点の変数の変域が飽和演算が必要ない状態で、飽和演算回路を入れないようにできるかを探ってみた。
任意精度型固定小数点型を使用したアンシャープマスキング・フィルタの例については下のリンクを参照のこと。
Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)
Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)
Vivado HLS によるアンシャープマスクキング・フィルタの作製9(C++ の任意精度固定小数点型3)

ap_fixed_test というVivado HLS 2016.4 のプロジェクトを生成した。
assert_1_170212.png

ap_fixed_test.cpp を貼っておく。

// ap_fixed_test.c
// 2017/02/12 by marsee

#include <assert.h>
#include <ap_fixed.h>

int ap_fixed_test(ap_fixed<16,8, AP_RND, AP_SAT> in0, ap_fixed<16,8, AP_RND, AP_SAT> in1, int limit,
        ap_fixed<16,8, AP_RND, AP_SAT> *out){

    ap_fixed<16,8, AP_RND, AP_SAT> temp;

    /*assert(-1 <= in0 <= 1);    assert(-2 <= in1 <= 2);    assert(-10 <= temp <= 10);    assert(-100 <= *out <= 100); */

    temp = in0;
    //assert(limit <= 10);
    for (int i=0; i<limit; i++)
#pragma HLS LOOP_TRIPCOUNT min=1 max=10 avg=2
        temp = temp * (ap_fixed<16,8, AP_RND, AP_SAT>)2.0;

    *out = temp * in1;

    return(0);
}


まずはC コードの合成を行った。結果を示す。
assert_2_170212.png

Latency のmin は 4、max は 13 だった。これは、LOOP_TRIPCOUNT に設定した値が元になっている。LOOP_TRIPCOUNTのカウントにその他のレイテンシを加えたものが Latency として示されている。だが、LOOP_TRIPCOUNT は合成には影響しない。
そこで、合成に変数の変域を反映させるのが assert() だ。
まずは、引数と変数の変域を指定する assert() のコメントを外した。
assert_3_170212.png

これで合成してみよう。
assert_4_170212.png

前回と同じだ。この assert() は効かないようだ。

次に、今コメントを外した部分をコメントにして、LOOP_TRIPCOUNT の max と同じ値を assert() で指定した文のコメントを外す。
assert_5_170212.png

合成結果を示す。
assert_6_170212.png

FF は 137 個が 110 個に、LUT が 243 個が 189 個に減った。

この結果から、assert() はfor ループのカウント用変数の変域を与えられるが、通常の変数の変域を指定できるわけでは無い様だ。

Vivado HLS 2016.4 における assert() 文の効果2”に続く。
  1. 2017年02月12日 07:16 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

FPGAマガジンNo.16 のVivado HLS AXI4マスタ編のソースコード

FPGAマガジンNo.16 のVivado HLS AXI4マスタ編のソースコードをGithubの marsee101/FPGAmagagine16_Vivado_HLS_AXI4M に置いておきましたので、ご利用ください。
ソースコードの説明はFPGAマガジン No.16 をご覧ください。

具体的には、FPGAマガジン No.16 の

高位合成ツールVivado HLS 特設記事

第1章 【画像フィルタをハードウェア化!】無料のVivado HL WebPACK Editionで高位合成にチャレンジしよう(AXI4マスタ編)
アルゴリズム通りに記述したフィルタCプログラムをハードウェア化してみよう P.78

第2章 【ステップアップで高速化!】
無料のVivado HL WebPACK Editionで高位合成にチャレンジしよう(AXI4マスタ編)
ライン・バッファ/バースト転送/最適化指示子を駆使した高速化テクニック P.94

の記事中のソースコードと画像です。
  1. 2017年02月06日 21:56 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

FASTXコーナー検出による物体の形状検出4(FASTXコーナー検出の点だけを表示)

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

前回は、FASTX コーナー検出の点だけを抽出するVivado HLS のプロジェクトを作成した。今回は、そのVivado HLS のIP をVivado のプロジェクトに入れて、カメラ画像からリアルタイムにFASTX コーナー検出の点を表示する。

まずは、V_ZYBO_CAMDS_FASTXt_164 をコピー&ペーストして、名前をV_ZYBO_CAMDS_FASTXt2_164 に変更した。
fastx_31_170204.png

V_ZYBO_CAMDS_FASTXt2_164 のfastx フォルダの内容を前回のVivado HLS のIP に置き換えた。
fastx_32_170204.png

V_ZYBO_CAMDS_FASTXt2_164 のVivado プロジェクトを起動し、ブロックデザインを開くと、Report IP Status が表示されるので、それをクリックした。
fastx_33_170204.png

下のウインドウにUP Status が表示される。Upgrade Selected ボタンをクリックする。
fastx_34_170204.png

Generate Output Products ダイアログが表示された。Generate ボタンをクリックした。
fastx_35_170204.png

Generate Output Products が成功した。
fastx_36_170204.png

IP Status のRerun をクリックしておこう。
fastx_37_170204.png

Generate Bitstream をクリックして、論理合成、インプリメント、ビットストリームの生成を行った。
fastx_38_170204.png

ビットストリームの生成が成功した。レポートを示す。
fastx_39_170204.png

ハードウェアをエクスポートして、SDK を立ち上げた。
今までのプロジェクトとプラットフォームを削除した。
fastx_40_170204.png

アプリケーション・プロジェクトを再生成した。
fash_on_serial プロジェクトを作成して、起動した。
fastx_41_170204.png

threshold = 5, 10, 20, 40, 60 の結果を示す。
fastx_42_170204.png

まずは原画像から。
fastx_43_170204.jpg

threshold = 5
fastx_44_170204.jpg

threshold = 10
fastx_45_170204.jpg

threshold = 20
fastx_46_170204.jpg

threshold = 40
fastx_47_170204.jpg

threshold = 60
fastx_48_170204.jpg
  1. 2017年02月04日 21:03 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

FASTXコーナー検出による物体の形状検出3(FASTXプロジェクトの修正)

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

前回は、FASTX コーナー検出のVivado HLS 2016.4 プロジェクトをやってみた。今回は、前回のFASTX コーナー検出は元の写真が入っているので、コーナー検出された結果から物体を検索することは難しいので、コーナー検出された位置のみを表示するようにしてみた。

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

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

元画像
fastx_22_170203.jpg

元画像からこのようなFASTX コーナー検出の画像が生成できた。(theshold = 60)
fastx_23_170203.jpg

theshold = 20
fastx_30_170203.jpg

次にC コードの合成を行った。
fastx_24_170203.png

前回よりも今回のほうがリソース使用量が増えていた。

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

500587で、前回とC/RTL協調シミュレーションの終了クロック時間は同じだった。

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

1行分拡大した。
fastx_27_170203.png

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

前回との違いは特にない様だ。

最後のIP へのエクスポートを行った
Vivado RTL Synthesis にチェックを入れてOK ボタンをクリックした。

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

fastx_2.cpp を貼っておく。

// fastx_2.cpp
// 2016/04/02 by marsee
// 2016/04/09 : FAST Corners Detection
// 2017/02/03 : 元の写真を入れないで、コーナー検出の点だけ表示した

#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::CvtColor<HLS_GRAY2BGR>(dmask, img_3);
    hls::Mat2AXIvideo(img_3, OUTPUT_STREAM);
}



なお、OpenCV の画像とハードウェア化関数の画像は全く違うので、テストベンチの fastx_tb.cpp ではエラーを表示するprintf() をコメントアウトしてある。
  1. 2017年02月03日 05:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

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