でC/RTLコシミュレーションの波形が表示された。cd c:/Users/Masaaki/Documents/Vivado_HLS/ZYBO/unsharp_mask_14_4/solution1/sim/verilog
current_fileset
open_wave_database unsharp_mask_axis.wdb
open_wave_config unsharp_mask_axis.wcfg
// アンシャープマスキング・フィルタ
// 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の小数点の位置
// 2015/09/27 : 演算の小数部は num_adec_k*2 ビットとする。
//
#define PRECISION 6 // 小数点以下の桁数、精度(1以上)
int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
int y;
int xy[3][3];
int result=0;
int z;
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のいずれかを抽出
}
}
int x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);
y = -(xy[0][0]<<PRECISION) -(xy[0][1]<<PRECISION) -(xy[0][2]<<PRECISION)
-(xy[1][0]<<PRECISION) +x1y1*xy[1][1] -(xy[1][2]<<PRECISION)
-(xy[2][0]<<PRECISION) -(xy[2][1]<<PRECISION) -(xy[2][2]<<PRECISION);
y = ((k * y)/9) >> num_adec_k; // k は num_adc_k だけ左シフトされているので戻す
z = y + (1<<(PRECISION-1)); // 四捨五入 +0.5
z = z >> PRECISION; // 小数点以下切り捨て
if (z<0) // 飽和演算
z = 0;
else if (z>255)
z = 255;
result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
}
return(result);
}
// unsharp_mask_axis.h
// 2015/09/26 by marsee
//#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)
// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "unsharp_mask_axis.h"
int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k);
int unsharp_mask_axis(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE ap_none port=usm_fil_enable
#pragma HLS INTERFACE ap_none port=usm_fil_k
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_none port=return
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> usm;
int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete
int usm_fil_val;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int i=0; i<3; i++){
for (int j=0; j<2; j++){
#pragma HLS UNROLL
pix_mat[i][j] = pix_mat[i][j+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
pix_mat[2][2] = pix.data;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = pix.data;
usm.data = unsharp_masking(pix_mat, (int)usm_fil_k, 2);
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
usm.data = pix.data;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
usm.user = 1;
else
usm.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
usm.last = 1;
else
usm.last = 0;
if (usm_fil_enable)
outs << usm; // AXI4-Stream へ出力
else
outs << pix; // 入力画像をそのまま出力
}
}
return 0;
}
// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k -j -k
// x0y1 x1y1 x2y1 -k 9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k -k -k
//
// k : 鮮鋭化の強さ(固定小数点)
// num_adec_k : Kの小数点の位置
//
int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
float y;
int xy[3][3];
float rgb[3];
int result=0;
float fk = (float)k;
for (int m=0; m<num_adec_k; m++){ // 小数点の位置を正しい位置にする
fk /= 2.0;
}
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 = -(float)xy[0][0] -(float)xy[0][1] -(float)xy[0][2]
-(float)xy[1][0] +(9.0/fk+8.0)*(float)xy[1][1] -(float)xy[1][2]
-(float)xy[2][0] -(float)xy[2][1] -(float)xy[2][2];
y = (fk * y)/9.0;
int z = (int)(y + 0.5); // 四捨五入
if (z<0) // 飽和演算
z = 0;
else if (z>255)
z = 255;
result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
}
return(result);
}
// unsharp_mask_axis_tb.cpp
// 2015/09/26 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>
#include "unsharp_mask_axis.h"
#include "bmp_header.h"
int unsharp_mask_axis(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k);
int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);
#define CLOCK_PERIOD 10
#define K 3.0 // 鮮鋭化の強さ
#define NUM_ADEC_K 2 // Kの小数点の位置
int main()
{
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins;
hls::stream<ap_axis<32,1,1,1> > ins_soft;
hls::stream<ap_axis<32,1,1,1> > outs;
hls::stream<ap_axis<32,1,1,1> > outs_soft;
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> vals;
ap_axis<32,1,1,1> vals_soft;
int m_seq = 1; // M系列の値
int i;
int xor_shift;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
int *rd_bmp, *hw_usmd;
int blue, green, red;
if ((fbmpr = fopen("test.bmp", "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_usmd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_usmd memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
int usm_k = (int)(K * pow(2.0, (double)NUM_ADEC_K));
unsharp_mask_axis(1, usm_k, ins, outs); // k = 2
unsharp_mask_axis_soft(1, usm_k, ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight); // k = 2;
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_usmd[(j*bmpihr.biWidth)+i] = (int)val;
if (val != val_soft){
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
return(1);
}
if (vals.last)
cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
// ハードウェアのラプラシアンフィルタの結果を temp_usm.bmp へ出力する
if ((fbmpw=fopen("temp_usm.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_usm.bmp by binary write mode\n");
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = hw_usmd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (hw_usmd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (hw_usmd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
free(rd_bmp);
free(hw_usmd);
return 0;
}
int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> usm;
int **line_buf;
int pix_mat[3][3];
int usm_fil_val;
int i;
// line_buf の1次元目の配列をアロケートする
if ((line_buf =(int **)malloc(sizeof(int *) * 2)) == NULL){
fprintf(stderr, "Can't allocate line_buf[3][]\n");
exit(1);
}
// メモリをアロケートする
for (i=0; i<2; i++){
if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
exit(1);
}
}
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<height; y++){
for (int x=0; x<width; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int k=0; k<3; k++){
for (int m=0; m<2; m++){
pix_mat[k][m] = pix_mat[k][m+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
pix_mat[2][2] = pix.data;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = pix.data;
usm.data = unsharp_masking_soft(pix_mat, (int)usm_fil_k, 2);
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
usm.data = pix.data;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
usm.user = 1;
else
usm.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
usm.last = 1;
else
usm.last = 0;
if (usm_fil_enable)
outs << usm; // AXI4-Stream へ出力
else
outs << pix; // 入力画像をそのまま出力
}
}
for (i=0; i<2; i++)
free(line_buf[i]);
free(line_buf);
return 0;
}
// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k -j -k
// x0y1 x1y1 x2y1 -k 9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k -k -k
//
// k : 鮮鋭化の強さ(固定小数点)
// num_adec_k : Kの小数点の位置
//
int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k)
{
float y;
int xy[3][3];
float rgb[3];
int result=0;
float fk = (float)k;
for (int m=0; m<num_adec_k; m++){ // 小数点の位置を正しい位置にする
fk /= 2.0;
}
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 = -(float)xy[0][0] -(float)xy[0][1] -(float)xy[0][2]
-(float)xy[1][0] +(9.0/fk+8.0)*(float)xy[1][1] -(float)xy[1][2]
-(float)xy[2][0] -(float)xy[2][1] -(float)xy[2][2];
y = (fk * y)/9.0;
int z = (int)(y + 0.5); // 四捨五入
if (z<0) // 飽和演算
z = 0;
else if (z>255)
z = 255;
result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
}
return(result);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
// 2015/09/15 : RGB-y変換AXI Masterハージョン by marsee
#include "conv_rgb2ym.h"
int conv_rgb2ym(int *rgb, int *y){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=4096 port=rgb offset=slave
#pragma HLS INTERFACE m_axi depth=4096 port=y offset=slave
int r, g, b, y_f;
int rgb_val;
for (int i=0; i<DATA_SIZE; i++){
#pragma HLS PIPELINE II=1
rgb_val = *rgb++;
b = rgb_val & 0xff;
g = (rgb_val>>8) & 0xff;
r = (rgb_val>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
*y++ = y_f >> 8; // 256で割る
}
return(0);
}
// conv_rgb2ym.h
// 2015/09/15 : by marsee
//
#define DATA_SIZE 4096
// conv_rgb2ym_tb.cpp
// 2015/09/15 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "conv_rgb2ym.h"
int conv_rgb2ym(int *rgb, int *y);
int conv_rgb2ym_soft(int *rgb, int *y);
int main(){
int *rgb, *hw_y, *sw_y;
int *h, *s;
// メモリをアロケートする
if ((rgb =(int *)malloc(sizeof(int) * (DATA_SIZE))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_y =(int *)malloc(sizeof(int) * (DATA_SIZE))) == NULL){
fprintf(stderr, "Can't allocate hw_lapd memory\n");
exit(1);
}
if ((sw_y =(int *)malloc(sizeof(int) * (DATA_SIZE))) == NULL){
fprintf(stderr, "Can't allocate sw_lapd memory\n");
exit(1);
}
for (int i=0; i<DATA_SIZE; i++)
rgb[i] = i<<16 + i<<8 + i;
conv_rgb2ym(rgb, hw_y);
conv_rgb2ym_soft(rgb, sw_y);
for (int i=0; i<DATA_SIZE; i++){
if (hw_y[i] != sw_y[i]){
printf("ERROR HW and SW results mismatch i = %d, HW = %d, SW = %d\n", i, hw_y[i], sw_y[i]);
return(1);
}
}
printf("Success HW and SW results match\n");
free(rgb);
free(hw_y);
free(sw_y);
}
int conv_rgb2ym_soft(int *rgb, int *y){
int r, g, b, y_f;
int rgb_val;
for (int i=0; i<DATA_SIZE; i++){
rgb_val = *rgb++;
b = rgb_val & 0xff;
g = (rgb_val>>8) & 0xff;
r = (rgb_val>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
*y++ = y_f >> 8; // 256で割る
}
return(0);
}
# dvi2vga_lap.tcl
# I have to modify the output file of "write project tcl ...".
# by marsee
# 2015/09/13
# Set the reference directory for source file relative paths (by default the value is script directory path)
set origin_dir "."
# Create project
create_project dvi2vga_lap ./dvi2vga_lap
# Set the directory path for the new project
set proj_dir [get_property directory [current_project]]
# Set project properties
set obj [get_projects dvi2vga_lap]
set_property "default_lib" "xil_defaultlib" $obj
set_property "part" "xc7z010clg400-1" $obj
set_property "simulator_language" "Mixed" $obj
# Create 'sources_1' fileset (if not found)
if {[string equal [get_filesets -quiet sources_1] ""]} {
create_fileset -srcset sources_1
}
# Set IP repository paths
set obj [get_filesets sources_1]
set_property "ip_repo_paths" "[file normalize "$origin_dir/config_files/lap_fil_axis_cnone"] [file normalize "$origin_dir/config_files/synchro/synchro.srcs/sources_1/new"] [file normalize "$origin_dir/config_files/dvi2rgb_v1_5"] [file normalize "$origin_dir/config_files/rgb2vga_v1_0"]" $obj
# Rebuild user ip_repo's index before adding any source files
update_ip_catalog -rebuild
source "$origin_dir/config_files/dvi2vga.tcl"
regenerate_bd_layout
save_bd_design
make_wrapper -files [get_files "$origin_dir/dvi2vga_lap/dvi2vga_lap.srcs/sources_1/bd/dvi2vga/dvi2vga.bd"] -top
add_files -norecurse "$origin_dir/dvi2vga_lap/dvi2vga_lap.srcs/sources_1/bd/dvi2vga/hdl/dvi2vga_wrapper.v"
add_files -fileset constrs_1 -norecurse "$origin_dir/config_files/dvi2vga.xdc"
update_compile_order -fileset sources_1
update_compile_order -fileset sim_1
// lap_filter_axis.h
// 2015/05/01
#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)
つまり、800 x 600 だけ画像が出力されなかった。やはり、800 x 600 は映らない。1920 x 1080 ◯
1280 x 768 ◯
1280 x 720 ◯
1152 x 864 ◯
1024 x 768 ◯
1024 x 600 ◯
800 x 600 X
に設定してある。C/RLT コシミュレーションが終了したら#pragma HLS INTERFACE ap_ctrl_hs port=return
に戻す予定だ。#pragma HLS INTERFACE ap_ctrl_none port=return
C/RTLコシミュレーションの結果の波形が表示された。cd C:/Users/Masaaki/Documents/Vivado_HLS/ZYBO/lap_fil_aixs_cnone_14_4/solution1/sim/verilog
current_fileset
open_wave_database lap_filter_axis.wdb
open_wave_config lap_filter_axis.wcfg
に設定してから、もう一度、C からRTL への合成を行って、IP化した。#pragma HLS INTERFACE ap_ctrl_none port=return
//
// lap_filter_axis.cpp
// 2015/05/01
// 2015/06/25 : 修正、ラプラシアンフィルタの値が青だけになっていたので、RGBに拡張した
// 2015/08/31 : lap_fil_enable を追加。lap_fil_enable が 1 の時にラプラシアンフィルタ処理、0 の時は、入力画像をそのまま出力する
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "lap_filter_axis.h"
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axis(ap_uint<1> lap_fil_enable, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE ap_none port=lap_fil_enable
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_none port=return
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> lap;
int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete
int lap_fil_val;
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int k=0; k<3; k++){
for (int m=0; m<2; m++){
#pragma HLS UNROLL
pix_mat[k][m] = pix_mat[k][m+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
int y_val = conv_rgb2y(pix.data);
pix_mat[2][2] = y_val;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = y_val;
lap_fil_val = laplacian_fil( pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので0とする
lap.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
lap.user = 1;
else
lap.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
lap.last = 1;
else
lap.last = 0;
if (lap_fil_enable)
outs << lap; // AXI4-Stream へ出力
else
outs << pix; // 入力画像をそのまま出力
}
}
return 0;
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// lap_filter_axis_tb.cpp
// 2015/05/01
// 2015/08/17 : BMPファイルを読み書きするように変更した
// 2015/08/31 : lap_fil_enable を追加した
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>
#include "lap_filter_axis.h"
#include "bmp_header.h"
int lap_filter_axis(ap_uint<1> lap_fil_enable, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axis_soft(ap_uint<1> lap_fil_enable, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);
#define CLOCK_PERIOD 10
int main()
{
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins;
hls::stream<ap_axis<32,1,1,1> > ins_soft;
hls::stream<ap_axis<32,1,1,1> > outs;
hls::stream<ap_axis<32,1,1,1> > outs_soft;
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> vals;
ap_axis<32,1,1,1> vals_soft;
int m_seq = 1; // M系列の値
int i;
int xor_shift;
BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
FILE *fbmpr, *fbmpw;
int *rd_bmp, *hw_lapd;
int blue, green, red;
if ((fbmpr = fopen("test.bmp", "rb")) == NULL){ // test.bmp をオープン
fprintf(stderr, "Can't open test.bmp by binary read mode\n");
exit(1);
}
// bmpヘッダの読み出し
fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);
// ピクセルを入れるメモリをアロケートする
if ((rd_bmp =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate rd_bmp memory\n");
exit(1);
}
if ((hw_lapd =(int *)malloc(sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
fprintf(stderr, "Can't allocate hw_lapd memory\n");
exit(1);
}
// rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = fgetc(fbmpr);
green = fgetc(fbmpr);
red = fgetc(fbmpr);
rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
}
}
fclose(fbmpr);
// ins に入力データを用意する
for(int i=0; i<5; i++){ // dummy data
pix.user = 0;
pix.data = i;
ins << pix;
}
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];
if (j==0 && i==0) // 最初のデータの時に TUSER を 1 にする
pix.user = 1;
else
pix.user = 0;
if (i == bmpihr.biWidth-1) // 行の最後でTLASTをアサートする
pix.last = 1;
else
pix.last = 0;
ins << pix;
ins_soft << pix;
}
}
lap_filter_axis(0, ins, outs);
lap_filter_axis_soft(0, ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight);
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
cout << endl;
cout << "outs" << endl;
for(int j=0; j < bmpihr.biHeight; j++){
for(i=0; i < bmpihr.biWidth; i++){
outs >> vals;
outs_soft >> vals_soft;
ap_int<32> val = vals.data;
ap_int<32> val_soft = vals_soft.data;
hw_lapd[(j*bmpihr.biWidth)+i] = (int)val;
if (val != val_soft){
printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
return(1);
}
if (vals.last)
cout << "AXI-Stream is end" << endl;
}
}
cout << "Success HW and SW results match" << endl;
cout << endl;
// ハードウェアのラプラシアンフィルタの結果を temp_lap.bmp へ出力する
if ((fbmpw=fopen("temp_lap.bmp", "wb")) == NULL){
fprintf(stderr, "Can't open temp_lap.bmp by binary write mode\n");
exit(1);
}
// BMPファイルヘッダの書き込み
fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);
// RGB データの書き込み、逆順にする
for (int y=0; y<bmpihr.biHeight; y++){
for (int x=0; x<bmpihr.biWidth; x++){
blue = hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
green = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
red = (hw_lapd[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;
fputc(blue, fbmpw);
fputc(green, fbmpw);
fputc(red, fbmpw);
}
}
fclose(fbmpw);
free(rd_bmp);
free(hw_lapd);
return 0;
}
int lap_filter_axis_soft(ap_uint<1> lap_fil_enable, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
ap_axis<32,1,1,1> pix;
ap_axis<32,1,1,1> lap;
int **line_buf;
int pix_mat[3][3];
int lap_fil_val;
int i;
// line_buf の1次元目の配列をアロケートする
if ((line_buf =(int **)malloc(sizeof(int *) * 2)) == NULL){
fprintf(stderr, "Can't allocate line_buf[3][]\n");
exit(1);
}
// メモリをアロケートする
for (i=0; i<2; i++){
if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
exit(1);
}
}
do { // user が 1になった時にフレームがスタートする
ins >> pix;
} while(pix.user == 0);
for (int y=0; y<height; y++){
for (int x=0; x<width; x++){
if (!(x==0 && y==0)) // 最初の入力はすでに入力されている
ins >> pix; // AXI4-Stream からの入力
for (int k=0; k<3; k++){
for (int m=0; m<2; m++){
pix_mat[k][m] = pix_mat[k][m+1];
}
}
pix_mat[0][2] = line_buf[0][x];
pix_mat[1][2] = line_buf[1][x];
int y_val = conv_rgb2y_soft(pix.data);
pix_mat[2][2] = y_val;
line_buf[0][x] = line_buf[1][x]; // 行の入れ替え
line_buf[1][x] = y_val;
lap_fil_val = laplacian_fil_soft( pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
lap.data = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
if (x<2 || y<2) // 最初の2行とその他の行の最初の2列は無効データなので0とする
lap.data = 0;
if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
lap.user = 1;
else
lap.user = 0;
if (x == (HORIZONTAL_PIXEL_WIDTH-1)) // 行の最後で TLAST をアサートする
lap.last = 1;
else
lap.last = 0;
if (lap_fil_enable)
outs << lap; // AXI4-Stream へ出力
else
outs << pix; // 入力画像をそのまま出力
}
}
for (i=0; i<2; i++)
free(line_buf[i]);
free(line_buf);
return 0;
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | - | - | - |