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

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

FPGAの部屋

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

Vivado HLS 2019.2 で xfOpenCV のAXI4-Stream 版 medianblur をやってみる3

Vivado HLS 2019.2 で xfOpenCV のAXI4-Stream 版 medianblur をやってみる2”の続き。

前回は、カラー画像出力と白黒画像出力の C シミュレーションを行って、成功した。今回は、カラー画像出力と白黒画像出力それぞれにおいて、C コードの合成、C/RTL 協調シミュレーション、Export RTL を行う。

まずは前回の続きで、C コードの合成を行った。左側が白黒画像出力、右側がカラー画像出力だ。
xfOpenCV_101_200312.pngxfOpenCV_106_200312.png

2 つ共、Latency は同じ max 値で 2094021 クロックだった。最大解像度は 1920 x 1080 = 2073600 ピクセルなので、 2094021 クロック / 2073600 ピクセル ≒ 1.010 クロック / ピクセルだった。性能は問題ない。
リソース使用量は当然ながらカラー画像出力の方が多い。BRAM_18K の使用量も白黒画像出力が 3 個、カラー画像出力が 9 個だった。

C/RTL 協調シミュレーションを行った。結果を示す。上がが白黒画像出力、下がカラー画像出力だ。
xfOpenCV_102_200312.png
xfOpenCV_107_200312.png

どちらも Latency は 366956 クロックだった。使用画像は 800 x 450 ピクセルなので、合計 360000 ピクセル、よって 366956 クロック / 2073600 ピクセル ≒ 1.019 クロック / ピクセルだった。

C/RTL 協調シミュレーションの全体波形を示す。上がが白黒画像出力、下がカラー画像出力だ。
xfOpenCV_103_200312.png
xfOpenCV_108_200312.png

ほとんど同じだが、TDATA が 8 ビットと 32 ビットの違いがある。

C/RTL 協調シミュレーションの波形を拡大してみよう。上がが白黒画像出力、下がカラー画像出力だ。
xfOpenCV_104_200312.png
xfOpenCV_109_200312.png

こちらも同じだ。

最後に、Export RTL を示す。左側が白黒画像出力、右側がカラー画像出力だ。
xfOpenCV_105_200312.pngxfOpenCV_110_200312.png

この結果がそっくり同じということはどういうことだろうか?
C コードの合成の結果は違っていたのに?何かバグっているとしか思えない。
  1. 2020年03月13日 03:59 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する4

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する3”の続き。

前回は、HLS Video Library の resize を使用して、800 x 600 ピクセルの画像を 60 x 45 ピクセル、100 x 75 ピクセル、200 x 150 ピクセルに縮小できるかどうか?を C シミュレーションですべてできることを確認した。今回は、60 x 45 ピクセル、200 x 150 ピクセルに縮小した時の C コードの合成、 C/RTL 協調シミュレーション、 Export RTL を行った。

800 x 600 ピクセルの画像を 60 x 45 ピクセルに縮小した場合
C コードの合成を行った。
HLS_Video_Library_32_200306.png

Latency は 503450 クロックだった。これは、 503450 クロック / 480000 ピクセル数 ≒ 1.05 クロック / ピクセルだ。
リソース使用量もそこそこだ。

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

Latency は 498437 クロックで、合成レポートよりも小さくなっている。

C/RTL 協調シミュレーションの全体波形を示す。
HLS_Video_Library_34_200307.png

outs_TVALID が櫛形になっているのが分かる。

もう少し拡大してみた。
HLS_Video_Library_35_200307.png

outs_TVALID の櫛形の部分が細かいデータ転送が集まっていることが分かる。この塊が画像の 1 行に相当する。

outs_TVALID のデータ転送部分を拡大してみた。
HLS_Video_Library_36_200307.png

やはり、outs_TVALID が櫛形になっているのが分かる。これは、60 / 800 ピクセルで 1 / 13.3333 であるはずだ。

Export RTL の結果を示す。
HLS_Video_Library_37_200307.png

CP achieved post-implementation が 4.085 ns で問題ない。

800 x 600 ピクセルの画像を 200 x 150 ピクセルに縮小した場合
C コードの合成を行った。左が200 x 150 ピクセルに縮小した場合のレポートで、右が 60 x 45 ピクセルに縮小した場合のレポートだ。
HLS_Video_Library_38_200307.pngHLS_Video_Library_32_200306.png

200 x 150 ピクセルに縮小した場合の方が FF と LUT の使用量が僅かに増えている。
Latency は同じだった。

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

Latency は 502637 クロックで、 60 x 45 ピクセルのときよりも多い。

C/RTL 協調シミュレーションの波形を示す。
HLS_Video_Library_40_200307.png

1 / 13.33333 から 1 / 4 の縮小率になったので、 outs_TVALID の櫛形の間隔が狭い。

拡大してみよう。
HLS_Video_Library_41_200307.png

やはり、outs_TVALID の櫛形の部分が細かいデータ転送が集まっていることが分かる。

outs_TVALID のデータ転送部分を拡大してみた。
HLS_Video_Library_42_200307.png

データ転送は 4 クロックに 1 回であることが分かる。

Export RTL を行った。
HLS_Video_Library_43_200307.png

Export RTL の結果は、 60 x 45 ピクセルに縮小した場合と全く同じだ。。。興味深い。

800 x 600 ピクセルの画像を 200 x 150 ピクセルに縮小した場合で、C コードの合成結果を HLS Video Library と xfOpenCV とで比較してみよう。左が HLS Video Library で、右が xfOpenCV での結果だ。
HLS_Video_Library_38_200307.pngxfOpenCV_73_200302.png

Latency は HLS Video Library が 503450 クロックで、 xfOpenCV が 487696 クロックだった。
リソース使用量の差を表にする。
HLS_Video_Library_44_200307.png

xfOpenCV の方が BRAM_18K を除くと HLS Video Library よりもリソース使用量は少ない。

xfOpenCV と HLS Video Library は適材適所で良いかもしれない。
  1. 2020年03月07日 05:14 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する3

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する2”の続き。

前回は、カラー画像の resize をカラー画像から白黒画像への resize に変更した。今回は、いろいろな縮小率で画像が縮小できるか?を C シミュレーションで検証する。

800 x 600 ピクセルの画像を 60 x 45 ピクセルの画像に変換する設定を行った時の C シミュレーションの結果を示す。
HLS_Video_Library_18_200306.png

resize_gray/solution1/csim/build ディレクトリの内容を示す。
問題なく画像が縮小できているようだ。
HLS_Video_Library_19_200306.png

test_straight0.bmp を示す。これが、HLS Video Library で縮小した画像だ。
HLS_Video_Library_20_200306.png

test_straight0_cv.bmp を示す。こっちは OpenCV で縮小した画像だ。
HLS_Video_Library_21_200306.png

同じに見える。

次に、800 x 600 ピクセルの画像を 100 x 75 ピクセルの画像に変換する設定を行った場合の C シミュレーションを行った。
HLS_Video_Library_22_200306.png

C シミュレーションは問題なく終了した。
resize_gray/solution1/csim/build ディレクトリの内容を示す。
問題なく画像が縮小できているようだ。
HLS_Video_Library_23_200306.png

test_straight0.bmp を示す。これが、HLS Video Library で縮小した画像だ。
HLS_Video_Library_24_200306.png

800 x 600 ピクセルの画像を 200 x 150 ピクセルの画像に変換する設定を行った場合の C シミュレーションを行った。
HLS_Video_Library_25_200306.png

C シミュレーションは問題なく終了した。
resize_gray/solution1/csim/build ディレクトリの内容を示す。
問題なく画像が縮小できているようだ。
HLS_Video_Library_26_200306.png

test_straight0.bmp を示す。これが、HLS Video Library で縮小した画像だ。
HLS_Video_Library_27_200306.png

最後に、800 x 600 ピクセルの画像を 40 x 30 ピクセルの画像に変換する設定を行った場合の C シミュレーションを行った。
HLS_Video_Library_28_200306.png

C シミュレーションは問題なく終了した。
resize_gray/solution1/csim/build ディレクトリの内容を示す。
問題なく画像が縮小できているようだ。流石に小さい。
HLS_Video_Library_29_200306.png

test_straight0.bmp を示す。これが、HLS Video Library で縮小した画像だ。
HLS_Video_Library_30_200306.png

あまりにも小さいので、拡大した。
HLS_Video_Library_31_200306.png

基本的な要素は保たれているようだ。白線も見える。

このように、HLS Video Library の resize は xfOpenCV の resize よりも画像を縮小する範囲が広いが、bilinear interpolation のみとなっている。
800 x 600 ピクセルの画像を 60 x 45 ピクセルの画像に変換するという私の要件では、HLS Video Library の resize が一択となる。
  1. 2020年03月06日 05:20 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する2

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する1”の続きと言うか修正版。

前回、カラーの画像をカラーで縮小する HLS Video Library の resize のソースコードを貼ったが、”Vivado HLS 2019.2 で xfOpenCV を使用する6(resize 1)”でも、カラーの画像を白黒画像に縮小する resize だったので、今回は、同様に、カラーの画像を白黒画像に縮小する resize のソースコードを貼る。
以前書いたブログの”Vivado HLS で画像のサイズを縮小して白黒変換(resize_gray)”のソースコードそのものなのだが、いろいろな解像度でうまく行くか?を確かめるために、多少変更した。

resize_gray.h を示す。

// resize.h
// 2020/03/04 by marsee

#ifndef __RESIZE_GRAY_H__
#define __RESIZE_GRAY_H__

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

#define ORG_HEIGHT   600
#define ORG_WIDTH    800

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef hls::Mat<ORG_HEIGHT, ORG_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<ORG_HEIGHT, ORG_WIDTH, HLS_8UC1> GRAY_IMAGE;

#define RESIZE_HEIGHT 45
#define RESIZE_WIDTH 60

#endif


resize_gray.cpp を示す。

// resize_gray.cpp
// 2017/08/31 by marsee
// 2020/03/04 : Changed source code.
//

#include "resize_gray.h"

int resize_gray(AXI_STREAM& ins, AXI_STREAM& outs){
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE axis register both port=ins
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=return

    RGB_IMAGE org_img(ORG_HEIGHT, ORG_WIDTH);
    GRAY_IMAGE org_img_g(ORG_HEIGHT, ORG_WIDTH);
    GRAY_IMAGE resize_img_g(RESIZE_HEIGHT, RESIZE_WIDTH);
    RGB_IMAGE resize_img(RESIZE_HEIGHT, RESIZE_WIDTH);

    hls::AXIvideo2Mat(ins, org_img);
    hls::CvtColor<HLS_BGR2GRAY>(org_img, org_img_g);
    hls::Resize(org_img_g, resize_img_g);
    hls::CvtColor<HLS_GRAY2BGR>(resize_img_g, resize_img);
    hls::Mat2AXIvideo(resize_img, outs);

    return(0);
}


resize_gray_tb.cpp を示す。

// resize_gray_tb.cpp
// 2017/08/31 by marsee
// 2020/03/04 : Changed source code.
//

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

using namespace cv;

#define INPUT_IMAGE        "straight0.bmp"
#define OUTPUT_IMAGE    "test_straight0.bmp"
#define OUTPUT_IMAGE_CV    "test_straight0_cv.bmp"

void resize_gray(AXI_STREAM& ins, AXI_STREAM& outs);
void opencv_resize_gray(Mat& src, Mat& dst);

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);

    // resize_gray() 関数をコール
    resize_gray(src_axi, dst_axi);

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

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

    // opencv_resize_gray() をコール
    Mat dst_cv(RESIZE_HEIGHT, RESIZE_WIDTH, CV_8UC3);
    opencv_resize_gray(src, dst_cv);
    imwrite(OUTPUT_IMAGE_CV, dst_cv);

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

            // bgr のどれかが間違っていたらエラー
            if (std::pow(dst_bgr[0]-dst_cv_bgr[0], 2.0) > 1 || std::pow(dst_bgr[1]-dst_cv_bgr[1], 2.0) > 1
                    || std::pow(dst_bgr[2]-dst_cv_bgr[2], 2.0) > 1){
                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_resize_gray(Mat& src, Mat& dst){
    Mat gray(src.rows, src.cols, CV_8UC1);
    Mat img0g(RESIZE_HEIGHT, RESIZE_WIDTH, CV_8UC1);

    cvtColor(src, gray, CV_BGR2GRAY);
    resize(gray, img0g, img0g.size(), 0, 0, INTER_LINEAR);
    cvtColor(img0g, dst, CV_GRAY2BGR);
}


Vivado HLS 2019.2 の resize_gray プロジェクトを示す。
HLS_Video_Library_17_200305.png
  1. 2020年03月05日 04:59 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で C シミュレーションが通らずに C コードの合成で ERROR: [HLS 200-101] 'add_files': が出る場合の対処

新しく VIvado HLS 2019.2 のプロジェクトを作って C シミュレーションや C コードの合成を行ったのだが、ソースコードは間違っていないはずなのにどうしてもエラーになってしまう。環境を捨ててしまって、実際のエラーを貼れないのが残念だ。

その時の C コードの合成のエラーは、”ERROR: [HLS 200-101] 'add_files': Too many positional arguments specified.”というエラーだった。
このエラーをググってみると、”AR# 71759 HLS ベースのビデオ IP を使用すると、「ERROR: [HLS 200-101] 'add_files': Too many positional arguments specified.」”というエラー メッセージが表示される”がヒットした。
アンサー・レコードによると、

このエラーは、プロジェクト パスに予期しない文字 (空白、英語以外の標準文字、バックスラッシュなど) があると発生することがあります。
プロジェクト パス名を変更して予期しない文字を使用しないようにすると、この問題を解決できます。

とのことだった。
ディレクトリパスには日本語使ってない。
後は、ファイル名しか無いが、日本語が入っていない。全く英語とアンダースコア以外使ってないように見える。
resize_gray.cpp, resize_grey.h, resize_gray_tb.cpp の 3 つのファイルだ。なお、これは正常のファイルだが、ダメなファイルも同様に見えていた。
HLS_Video_Library_16_200305.png

ファイルを消して、もう一度新規作成で作り直したところ、 C シミュレーションや C コードの合成が成功した。何か不正な文字コードが入ってしまったようだ。
  1. 2020年03月05日 04:39 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2019.2 の HLS Video Library を使用して resize() を実装する1

Vivado HLS 2019.2 で xfOpenCV を使用する8(resize 3)”で xfOpenCV を使用して、Vivado HLS 2019.2 で画像のサイズ変換を実装した。今回は、HLS Video Library を使用して、Vivado HLS 2019.2 で画像のサイズ変換を実装する。

Vivado HLS で画像のサイズを縮小して白黒変換(resize_gray)”を参考にするが、白黒変換は無しで、画像サイズを変換してカラーのままとする。

Vivado HLS 2019.2 で resize プロジェクトを生成した。
HLS_Video_Library_15_200304.png

resize.h を貼っておく。

// resize.h
// 2020/03/04 by marsee

#ifndef __resize_gray_H__
#define __resize_gray_H__

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

#define ORG_HEIGHT   600
#define ORG_WIDTH    800

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef hls::Mat<ORG_HEIGHT, ORG_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<ORG_HEIGHT, ORG_WIDTH, HLS_8UC1> GRAY_IMAGE;

#define RESIZE_HEIGHT 45
#define RESIZE_WIDTH 60

#endif


resize.cpp を貼っておく。

// resize.cpp
// 2020/03/04 by marsee

#include "resize.h"

int resize(AXI_STREAM& ins, AXI_STREAM& outs){
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE axis register both port=ins
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=return

    RGB_IMAGE org_img(ORG_HEIGHT, ORG_WIDTH);
    RGB_IMAGE resize_img(RESIZE_HEIGHT, RESIZE_WIDTH);

    hls::AXIvideo2Mat(ins, org_img);

    hls::Resize(org_img, resize_img);

    hls::Mat2AXIvideo(resize_img, outs);

    return(0);
}


resize_tb.cpp を貼っておく。

// resize_tb.cpp
// 2020/03/04 by marsee

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

using namespace cv;

#define INPUT_IMAGE        "straight0.bmp"
#define OUTPUT_IMAGE    "test_straight0.bmp"
#define OUTPUT_IMAGE_CV    "test_straight0_cv.bmp"

void resize(AXI_STREAM& ins, AXI_STREAM& outs);
void opencv_resize(Mat& src, Mat& dst);

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);

    // resize() 関数をコール
    resize(src_axi, dst_axi);

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

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

    // opencv_resize_gray() をコール
    Mat dst_cv(RESIZE_HEIGHT, RESIZE_WIDTH, CV_8UC3);
    opencv_resize(src, dst_cv);
    imwrite(OUTPUT_IMAGE_CV, dst_cv);

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

            // bgr のどれかが間違っていたらエラー
            if (std::pow(dst_bgr[0]-dst_cv_bgr[0], 2.0) > 1 || std::pow(dst_bgr[1]-dst_cv_bgr[1], 2.0) > 1
                    || std::pow(dst_bgr[2]-dst_cv_bgr[2], 2.0) > 1){
                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_resize(Mat& src, Mat& dst){
    Mat img0(RESIZE_HEIGHT, RESIZE_WIDTH, CV_8UC3);

    resize(src, img0, img0.size(), 0, 0, INTER_LINEAR);

    img0.copyTo(dst);
}


  1. 2020年03月04日 04:45 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2019.2 で普通に C ソースコードを書いて Sobel フィルタを実装する2

Vivado HLS 2019.2 で普通に C ソースコードを書いて Sobel フィルタを実装する1”の続き。

前回は、ivado HLS 2019.2 で普通に C ソースコードを書いて Sobel フィルタを実装するためのソースコードとテストベンチを貼った。今回は、C シミュレーション、 C コードの合成、 C/RTL 協調シミュレーション、 Export RTL を行う。

C シミュレーションを行った。結果を示す。
sobel_filter_axis3_2_200227.png

sobel_filter_axis3/solution/csim/build ディレクトリを示す。
sobel_filter_axis3_3_200227.png

Sobel フィルタ処理結果の sobel.jpg を示す。綺麗なエッジが検出できている。
sobel_filter_axis3_4_200227.jpg

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

Latency は 480016 クロックで、総ピクセル数よりも 16 クロック多いだけである。リソース使用量も少ない。

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

Latency は 480041 クロックだった。優秀だ。

C/RTL 協調シミュレーションの波形を示す。
sobel_filter_axis3_7_200227.png

outs_TVALID も ins_TREADY もほとんど 1 にアサートされたままなので、スループットが高い。

最後に Export RTL を行った。結果を示す。
sobel_filter_axis3_8_200227.png

リソース使用量も少なく、 CP achieved post-implementation が 4.152 ns で大丈夫そうだ。
  1. 2020年02月28日 04:46 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0
»