Convolution

平滑化、ノイズ除去、輪郭強調など、画像処理アプリケーションの様々な場面で使われる Convolution (畳み込み) 処理です。

 主な仕様

  • 入力: 512 x 512 pixel グレースケール 画像
  • 出力: 512 x 512 pixel グレースケール 画像
  • FPGA サイクル数: 2pixel/cycle (unroll_factor=2の場合)
  • FPGA ゲート数: (unroll_factor=2の場合)
    • LUT:4642
    • FF:8847
    • DSP: 70
    • BRAM: 7

ソースコード

#include <Halide.h>
#include <Element.h>

using namespace Halide;
using namespace Halide::Element;
   
class Convolution : public Halide::Generator<Convolution> {
    Var x{"x"}, y{"y"};

    GeneratorParam<int32_t> width{"width", 512};
    GeneratorParam<int32_t> height{"height", 512};
    GeneratorParam<int32_t> unroll_factor{"unroll_factor", 2};
    ImageParam in{UInt(8), 2, "in"};
    ImageParam kernel{Int(16), 2, "kernel"};
    Param<int32_t> kernel_size{"kernel_size", 3, 1, 5};
       
public:
    Func build() {
        Func bounded = BoundaryConditions::repeat_edge(in, 0, width.value(), 0, height.value());

        Expr kh = div_round_to_zero(kernel_size, 2);
        RDom r(0, kernel_size, 0, kernel_size);

        Expr dx = r.x - kh;
        Expr dy = r.y - kh;

        Func k;
        k(x, y) = kernel(x, y);
        
        constexpr uint32_t frac_bits = 10;
        using Fixed16 = Fixed<int16_t, frac_bits>;
        Fixed16 pv = to_fixed<int16_t, frac_bits>(bounded(x+dx, y+dy));
        Fixed16 kv{k(r.x, r.y)};

        Func out("out");
        out(x, y) = from_fixed<uint8_t>(sum_unroll(r, pv * kv));

        schedule(in, {width, height});
        schedule(kernel, {5, 5});
        schedule(k, {5, 5});
        schedule(out, {width, height}).unroll(x, unroll_factor);
      
        return out;
    }
};

HALIDE_REGISTER_GENERATOR(Convolution, "convolution")

 

解説

Convolutionは、注目画素とその近傍の画素に対して同じサイズのカーネルと呼ばれる重み行列を掛けあわせ、それらの和をとって新しい値とする処理です。

カーネルは、処理の目的によって様々な種類があります。代表的なものだけでも、

  • 平滑化フィルタ
  • 先鋭化フィルタ
  • エッジ強調フィルタ

などがあり、同じアルゴリズムの畳込み処理であっても、異なる値のカーネルを使用するだけで、多様な処理結果を得ることができます。

このコードの大きな特徴として、DSLコンパイル時に性能と消費リソースの調整が任意に可能な点が挙げられます。コンパイル時パラメータunroll_factorには、画像X方向に連続したピクセルをいくつ同時に処理するかを指定することができます。デフォルトでは2が設定されており、これは2ピクセルを同時に処理するようなデザインへと変換されます。

GeneratorParam<int32_t> unroll_factor{"unroll_factor", 2};

入力画像は8ビット符号なし整数、カーネルは16ビットの固定少数点数を指定しています。

ImageParam in{UInt(8), 2, "in"};
ImageParam kernel{Int(16), 2, "kernel"};

カーネルサイズは3×3、5×5の選択式で、実行時パラメータkernel_sizeとして与えます。

Param<int32_t> kernel_size{"kernel_size", 3, 1, 5};

畳み込み処理は以下のように、sum_unroll関数を用いて記述されています。これは、与えられた式を指定した範囲内で畳み込むという組み込み関数です。

Func out("out");
out(x, y) = from_fixed<uint8_t>(sum_unroll(r, pv * kv));

FPGA上に浮動小数点数演算を実装すると、多くのリソースを消費するため、畳み込み処理には固定少数点数演算を使用しています。 pv, kv は以下のようにFixed16として定義されています。

Fixed16 pv = to_fixed<int16_t, frac_bits>(bounded(x+dx, y+dy));
Fixed16 kv{k(r.x, r.y)};

Fixed16 型は、テンプレート型Fixed<int16_t, 10>の型エイリアスになっており、Fixedクラスには任意精度の固定小数点数演算が演算子オーバーロードを使用して定義されています。HalideはC++のEDSLなので、テンプレートを使用して使用したい型を切り替えるだけで、精度や演算方法を自由に切り替え、素早くFPGAへと実装することが可能になります。

全てのソースコードにアクセスするためには、Githubを、テスト用Linuxイメージの使用法はこちらを参照して下さい。 IPコア形式での提供は近日中の対応を予定しています。

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

レビュー

レビューはまだありません。

“Convolution” の口コミを投稿します

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Available Downloads:

ログインするとダウンロードとカスタマイズなどのお問合せができます。