// laplacian_filter.c
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
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_axim(int *cam_addr, int *lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE ap_hs port=cam_addr
#pragma HLS INTERFACE ap_vld port=lap_addr
#pragma HLS RESOURCE variable=cam_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=lap_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=return core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
#pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
#pragma HLS RESOURCE variable=cam_fb core=AXI4M
#pragma HLS RESOURCE variable=lap_fb core=AXI4M
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
unsigned int offset;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
offset = *cam_addr/sizeof(int);
memcpy(line_buf[a], (const int*)(cam_fb+offset+(a*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
offset = *cam_addr/sizeof(int);
memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+offset+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
offset = *lap_addr/sizeof(int);
memcpy((const int*)(lap_fb+offset+(y*HORIZONTAL_PIXEL_WIDTH)), lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
return(1);
}
// 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_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
// return(abs(-x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2)); // 元の実装
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// Testbench of laplacian_filter.c
// M系列データをハードウェアとソフトウェアで、ラプラシアン・フィルタを掛けて、それを比較する
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 40
#define VERTICAL_PIXEL_WIDTH 20
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
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_axim(int cam_addr, int lap_addr, volatile int *cam_fb, volatile int *lap_fb); // hardware
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb); // software
int mseq_po[ALL_PIXEL_VALUE];
int hw_lap_po[ALL_PIXEL_VALUE];
int sf_lap_po[ALL_PIXEL_VALUE];
int main()
{
// int *mseq_po, *hw_lap_po, *sf_lap_po;
int *s, *h;
int x, y;
unsigned int lfsr = 1;
int cam_addr, lap_addr;
// ピクセルデータ領域にM系列データを入力
for (y=0, s=mseq_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); /* taps 32 31 29 1 */
// ”線形帰還シフトレジスタ ”参照 : http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%B8%B0%E9%82%84%E3%82%B7%E3%83%95%E3%83%88%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF
*s = lfsr;
s++;
}
}
cam_addr = (int)mseq_po;
lap_addr = (int)hw_lap_po;
lap_filter_axim(cam_addr, lap_addr, (volatile int *)0, (volatile int *)0); // ハードウェアのラプラシアン・フィルタ
laplacian_filter_soft(mseq_po, sf_lap_po); // ソフトウェアのラプラシアン・フィルタ
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
for (y=0, h=hw_lap_po, s=sf_lap_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (*h != *s){
printf("ERROR HW and SW results mismatch x = %d, y = %d, HW = %d, SW = %d\n", x, y, *h, *s);
return(1);
} else {
h++;
s++;
}
}
}
printf("Success HW and SW results match\n");
}
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb)
{
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
memcpy(&line_buf[a][0], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[(y+1)%3], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
}
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
memcpy(&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
}
// 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);
}
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.2
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
//
// ==============================================================
`timescale 1 ns / 1 ps
module lap_filter_axim_top (
m_axi_cam_fb_AWID,
m_axi_cam_fb_AWADDR,
m_axi_cam_fb_AWLEN,
m_axi_cam_fb_AWSIZE,
m_axi_cam_fb_AWBURST,
m_axi_cam_fb_AWLOCK,
m_axi_cam_fb_AWCACHE,
m_axi_cam_fb_AWPROT,
m_axi_cam_fb_AWQOS,
m_axi_cam_fb_AWUSER,
m_axi_cam_fb_AWVALID,
m_axi_cam_fb_AWREADY,
m_axi_cam_fb_WDATA,
m_axi_cam_fb_WSTRB,
m_axi_cam_fb_WLAST,
m_axi_cam_fb_WUSER,
m_axi_cam_fb_WVALID,
m_axi_cam_fb_WREADY,
m_axi_cam_fb_BID,
m_axi_cam_fb_BRESP,
m_axi_cam_fb_BUSER,
m_axi_cam_fb_BVALID,
m_axi_cam_fb_BREADY,
m_axi_cam_fb_ARID,
m_axi_cam_fb_ARADDR,
m_axi_cam_fb_ARLEN,
m_axi_cam_fb_ARSIZE,
m_axi_cam_fb_ARBURST,
m_axi_cam_fb_ARLOCK,
m_axi_cam_fb_ARCACHE,
m_axi_cam_fb_ARPROT,
m_axi_cam_fb_ARQOS,
m_axi_cam_fb_ARUSER,
m_axi_cam_fb_ARVALID,
m_axi_cam_fb_ARREADY,
m_axi_cam_fb_RID,
m_axi_cam_fb_RDATA,
m_axi_cam_fb_RRESP,
m_axi_cam_fb_RLAST,
m_axi_cam_fb_RUSER,
m_axi_cam_fb_RVALID,
m_axi_cam_fb_RREADY,
m_axi_lap_fb_AWID,
m_axi_lap_fb_AWADDR,
m_axi_lap_fb_AWLEN,
m_axi_lap_fb_AWSIZE,
m_axi_lap_fb_AWBURST,
m_axi_lap_fb_AWLOCK,
m_axi_lap_fb_AWCACHE,
m_axi_lap_fb_AWPROT,
m_axi_lap_fb_AWQOS,
m_axi_lap_fb_AWUSER,
m_axi_lap_fb_AWVALID,
m_axi_lap_fb_AWREADY,
m_axi_lap_fb_WDATA,
m_axi_lap_fb_WSTRB,
m_axi_lap_fb_WLAST,
m_axi_lap_fb_WUSER,
m_axi_lap_fb_WVALID,
m_axi_lap_fb_WREADY,
m_axi_lap_fb_BID,
m_axi_lap_fb_BRESP,
m_axi_lap_fb_BUSER,
m_axi_lap_fb_BVALID,
m_axi_lap_fb_BREADY,
m_axi_lap_fb_ARID,
m_axi_lap_fb_ARADDR,
m_axi_lap_fb_ARLEN,
m_axi_lap_fb_ARSIZE,
m_axi_lap_fb_ARBURST,
m_axi_lap_fb_ARLOCK,
m_axi_lap_fb_ARCACHE,
m_axi_lap_fb_ARPROT,
m_axi_lap_fb_ARQOS,
m_axi_lap_fb_ARUSER,
m_axi_lap_fb_ARVALID,
m_axi_lap_fb_ARREADY,
m_axi_lap_fb_RID,
m_axi_lap_fb_RDATA,
m_axi_lap_fb_RRESP,
m_axi_lap_fb_RLAST,
m_axi_lap_fb_RUSER,
m_axi_lap_fb_RVALID,
m_axi_lap_fb_RREADY,
s_axi_LiteS_AWADDR,
s_axi_LiteS_AWVALID,
s_axi_LiteS_AWREADY,
s_axi_LiteS_WDATA,
s_axi_LiteS_WSTRB,
s_axi_LiteS_WVALID,
s_axi_LiteS_WREADY,
s_axi_LiteS_BRESP,
s_axi_LiteS_BVALID,
s_axi_LiteS_BREADY,
s_axi_LiteS_ARADDR,
s_axi_LiteS_ARVALID,
s_axi_LiteS_ARREADY,
s_axi_LiteS_RDATA,
s_axi_LiteS_RRESP,
s_axi_LiteS_RVALID,
s_axi_LiteS_RREADY,
interrupt,
aresetn,
aclk
);
parameter C_M_AXI_CAM_FB_ID_WIDTH = 1;
parameter C_M_AXI_CAM_FB_ADDR_WIDTH = 32;
parameter C_M_AXI_CAM_FB_DATA_WIDTH = 32;
parameter C_M_AXI_CAM_FB_AWUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_ARUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_WUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_RUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_BUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_USER_DATA_WIDTH = 32;
parameter C_M_AXI_CAM_FB_TARGET_ADDR = 32'h00000000;
parameter C_M_AXI_CAM_FB_USER_VALUE = 1'b0;
parameter C_M_AXI_CAM_FB_PROT_VALUE = 3'b010;
parameter C_M_AXI_CAM_FB_CACHE_VALUE = 4'b0000;
parameter C_M_AXI_LAP_FB_ID_WIDTH = 1;
parameter C_M_AXI_LAP_FB_ADDR_WIDTH = 32;
parameter C_M_AXI_LAP_FB_DATA_WIDTH = 32;
parameter C_M_AXI_LAP_FB_AWUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_ARUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_WUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_RUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_BUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_USER_DATA_WIDTH = 32;
parameter C_M_AXI_LAP_FB_TARGET_ADDR = 32'h00000000;
parameter C_M_AXI_LAP_FB_USER_VALUE = 1'b0;
parameter C_M_AXI_LAP_FB_PROT_VALUE = 3'b010;
parameter C_M_AXI_LAP_FB_CACHE_VALUE = 4'b0000;
parameter C_S_AXI_LITES_ADDR_WIDTH = 6;
parameter C_S_AXI_LITES_DATA_WIDTH = 32;
parameter RESET_ACTIVE_LOW = 1;
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 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 |