blog.n-hassy.info
gaussian.h
#include <ap_int.h> #include <hls_stream.h> #include <ap_axi_sdata.h> using namespace hls; typedef ap_axis<32, 0, 0, 0> AP_AXIS; typedef stream<AP_AXIS> AXI_STREAM; const int height = 512; // 画像の高さ const int width = 512; // 画像の幅 const int d = 3; // フィルタ直径 (奇数のみ) const int r = d/2; // フィルタの半径 const int coeff[d][d] = {{1, 2, 1}, {2, 4, 2}, {1, 2, 1}}; // ガウシアンフィルタの係数 (を shift ビット左シフトしたもの) const int shift = 4; // 係数を何ビット左シフトしたか // 座標 (x, y) が画像の範囲内かどうかを返す inline bool bounds_ok(int y, int x) { return (0 <= y && y < height && 0 <= x && x < width); } // x を右に s ビットシフトする (繰り上げがあれば繰り上げる) inline int bitshift(int x, int s) { int bit = (1<<(s-1)); if (x & bit) { x >>= s; x++; } else { x >>= s; } return x; }
gaussian.cpp
#include "gaussian.h" // メインの関数 void gaussian(AXI_STREAM &in_strm, AXI_STREAM &out_strm) { // 入出力のインターフェースを定義 #pragma HLS INTERFACE s_axilite port=return bundle=CONTROL_BUS #pragma HLS INTERFACE axis port=in_strm #pragma HLS INTERFACE axis port=out_strm // line buffer と window を定義して,パーティションする int linebuf[d-1][width]; int window[d][d]; #pragma HLS ARRAY_PARTITION variable=linebuf complete dim=1 #pragma HLS ARRAY_PARTITION variable=window complete dim=0 AP_AXIS pix; // width * r + r + 1 個入力を読んで,linebuf と window を初期化する buf_x1: for (int px = width - r - 1; px < width; px++) { #pragma HLS PIPELINE II=1 pix = in_strm.read(); linebuf[r-1][px] = pix.data; } buf_y: for (int py = r; py < d - 1; py++) { buf_x2: for (int px = 0; px < width; px++) { #pragma HLS PIPELINE II=1 pix = in_strm.read(); linebuf[py][px] = pix.data; } } win_y: for (int wy = r; wy < d; wy++) { win_x: for (int wx = r; wx < d; wx++) { #pragma HLS PIPELINE II=1 window[wy][wx] = linebuf[wy-1][wx+width-d]; } } // pix の値を使って val を初期化する // これをしなくてもシミュレーションなどは通るが PYNQ で動かしても値が返って来なくなる AP_AXIS val; val.keep = pix.keep; val.strb = pix.strb; val.last = 0; // 最後のビットの時だけ 1 で,その他の時は 0 にする int read_cnt = width * r + r + 1; // 何ビット読んだかを保存 for_y: for (int py = 0; py < height; py++) { for_x: for (int px = 0; px < width; px++) { #pragma HLS PIPELINE II=1 int val_out = 0; // 出力値を計算 // HLS PIPELINE の内側なので,for は全てインライン展開される for (int wy = -r; wy <= r; wy++) { for (int wx = -r; wx <= r; wx++) { if (bounds_ok(py + wy, px + wx)) val_out += window[wy + r][wx + r] * coeff[wy + r][wx + r]; } } // 計算した出力値を val.data に入れて,最後の出力なら val.last を 1 にする val.data = bitshift(val_out, shift); if (py == height-1 && px == width-1) val.last = 1; out_strm << val; int val_in = 0; // 入力が残っていれば読んで,val_in に格納する if (read_cnt < height * width) { pix = in_strm.read(); val_in = pix.data; read_cnt++; } // window を 1 列左にシフトする for (int wy = 0; wy < d; wy++) { for (int wx = 0; wx < d - 1; wx++) { window[wy][wx] = window[wy][wx+1]; } } // linebuf[:][px] を window[:][d-1] に格納し,linebuf[:][px] を 1 行上にシフトする window[0][d-1] = linebuf[0][px]; for (int ry = 1; ry < d-1; ry++) { window[ry][d-1] = linebuf[ry][px]; linebuf[ry - 1][px] = linebuf[ry][px]; } window[d-1][d-1]= val_in; linebuf[d-2][px] = val_in; } } }