HLS和FPGA实现是怎么一回事
HLS已有库说明
HLS语法讲解与实例
HLS自定义模板
HLS实现OpenCV函数
主要还是工作中用到,HLS毕竟还是小众模版库,就目前来看,连Verilog普及都没有,希望原厂能有的放矢,一蹴而就。学语言,是程序员的一把斧,需要熟练与精通。希望今天的付出值得。
HLS的出现提高了FPGA实现逻辑的复杂程度,但同时又带来一些不确定的结果,总的来说,提高了实现的效率。
FPGA是一种集成电路IC,可以编写不同算法的介质。现代FPGA包含200万个逻辑单元,可以实现不同的算法。
使用HLS编译器,很重要的一点是知道FPGA使用资源、以及他们是如何在FPGA上执行的。
FPGA架构主要由几部分组成:LUT、FF、Wires、IO pads.
(待续)
HLS视频库是通过Vivado HLS调用C/C++库加速机器视觉、图像处理在FPGA上实现。它包括通用的数据结构、OpenCV接口、AXI4-Stream接口和视频处理函数。视频库使用OpenCV库作为参考模型,大多数视频处理功能与相应的opencv函数有类似的界面和同等的功能。
简单来说,有两个头文件可以帮助我们进行HLS 视频库调用:
#include
#include
当然,这两个文件中包含了视频处理的一些头文件,具体可以查看安装目录下Include,也可以直接在工程中点击对应头文件,查看源文件。
下面是HLS视频库基本数据结构的模板类,是针对FPGA进行优化设计。
hls::Mat
hls::Scalar
hls::Window
hls::LineBuffer
1)OpenCV接口函数
OpenCV接口函数是保证重建的OpenCV可以在FPGA实现,满足一种以AXI4-Streaming流的数据处理方式。
IplImage2AXIvideo
AXIvideo2IplImage
cvMat2AXIvideo
AXIvideo2cvMat
CvMat2AXIvideo
AXIvideo2CvMat
IplImage2hlsMat
hlsMat2IplImage
cvMat2hlsMat
hlsMat2cvMat
CvMat2hlsMat
hlsMat2CvMat
CvMat2hlsWindow
hlsWindow2CvMat
2)AXI4-Stream接口函数
IO函数是将HLS::Mat格式转化为AXI4-Stream设计的。
hls::AXIvideo2Mat
hls::Mat2AXIvideo
3)视频处理函数
下面函数是根据OpenCV相同功能进行加速设计的库函数。
hls::AbsDiff
hls::AddS
hls::AddWeighted
hls::And
hls::Avg
hls::AvgSdv
hls::Cmp
hls::CmpS
hls::CornerHarris
hls::CvtColor
hls::Dilate
hls::Duplicate
hls::EqualizeHist
hls::Erode
hls::FASTX
hls::Filter2D
hls::GaussianBlur
hls::Harris
hls::HoughLines2
hls::Integral
hls::InitUndistortRectifyMap
hls::Max
hls::MaxS
hls::Mean
hls::Merge
hls::Min
hls::MinMaxLoc
hls::MinS
hls::Mul
hls::Not
hls::PaintMask
hls::Range
hls::Remap
hls::Reduce
hls::Resize
hls::Set
hls::Scale
hls::Sobel
hls::Split
hls::SubRS
hls::SubS
hls::Sum
hls::Threshold
hls::Zero
(待续)
关于数据类型,HLS有自己独特的定义方式,也包含C++的大部分数据类型,但是,有些类型还没有实现可综合。
HLS Scale
hls::Scale: 该标量是HLS像素点表示方法;
HLS Mat
hls::Mat
(待续)
// 单通道转双通道
void gray2YUYV(
IMAGE_C1 &gray,
IMAGE_C2 &yuyv
)
{
int rows = gray.rows;
int cols = gray.cols;
PIXEL_C1 s;
PIXEL_C2 d;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
#pragma HLS loop_flatten off
#pragma HLS pipeline II=1
gray >> s;
d.val[0] = s.val[0];
d.val[1] = 128;
yuyv << d;
}
}
}
该摸板函数实现单通道灰度图像转双通道YUV图像。上述函数只实现像素点操作,不需要进行缓存,所以,实现起来相对容易。
(待续)
实例一:
hls::FASTX
该函数实现FAST算法的角点检测,并生成一副Mask图像,或者角点数组。
具体代码:
(PART ONE)
template
void FASTX(
Mat &_src,
Mat &_mask,
HLS_TNAME(SRC_T) _threshold,
bool _nomax_supression
)
{
#pragma HLS INLINE
int flag[16][2]={{3,0},{4,0},{5,1},{6,2},{6,3},{6,4},{5,5},{4,6},
{3,6},{2,6},{1,5},{0,4},{0,3},{0,2},{1,1},{2,0}};
FAST_t_opr<16,7>(_src,_mask,_threshold,_nomax_supression,flag);
}
(PART TWO)
//generate array
template
void FAST_t_opr(
Mat &_src,
Point_ (&_keypoints)[N],
HLS_TNAME(SRC_T) _threshold,
bool _nonmax_supression,
int (&flag)[PSize][2]
)
{
typedef typename pixel_op_type::T INPUT_T;
LineBuffer k_buf;
LineBuffer<2,COLS+KERNEL_SIZE,ap_int<16> > core_buf;
Window<3,3,ap_int<16> > core_win;
Window win;
Scalar s;
int rows= _src.rows;
int cols= _src.cols;
assert(rows <= ROWS);
assert(cols <= COLS);
int kernel_half=KERNEL_SIZE/2;
ap_uint<2> flag_val[PSize+PSize/2+1];
int flag_d[PSize+PSize/2+1];
#pragma HLS ARRAY_PARTITION variable=flag_val dim=0
#pragma HLS ARRAY_PARTITION variable=flag_d dim=0
int index=0;
int offset=KERNEL_SIZE/2;
if(_nonmax_supression)
{
offset=offset+1;
}
loop_height: for(HLS_SIZE_T i=0;i>s;
win.val[KERNEL_SIZE-1][KERNEL_SIZE-1]=s.val[0];
k_buf.val[KERNEL_SIZE-2][j]=s.val[0];
}
//------core
for(int r= 0;r<3;r++)
{
for(int c=0;c<3-1;c++)
{
core_win.val[r][c]=core_win.val[r][c+1];//column left shift
}
}
core_win.val[0][3-1]=core_buf.val[0][j];
for(int buf_row= 1;buf_row< 3-1;buf_row++)
{
core_win.val[buf_row][3-1]=core_buf.val[buf_row][j];
core_buf.val[buf_row-1][j]=core_buf.val[buf_row][j];
}
int core=0;
//output
//if(i>=KERNEL_SIZE-1&&j>=KERNEL_SIZE-1)
if(i>=KERNEL_SIZE-1 && i=KERNEL_SIZE-1 & j(win,(INPUT_T)_threshold,flag_val,flag_d,flag,core,_nonmax_supression);
if(iscorner&&!_nonmax_supression)
{
if(index=rows||j>=cols)
{
core=0;
}
if(_nonmax_supression)
{
core_win.val[3-1][3-1]=core;
core_buf.val[3-2][j]=core;
if(i>=KERNEL_SIZE&&j>=KERNEL_SIZE&&core_win.val[1][1]!=0)
{
bool iscorner=fast_nonmax(core_win);
if(iscorner)
{
if(index
(待续)
注意该函数的使用:
hls::Duplicate(img_0, img_1, img_1_); 该函数可以避免 Hanging Up和read empty.
学习一门语言,编成一系列博客,这个过程可以看出一个工程师的思维逻辑。所以,每一次这样去做的时候,总是不断修正自己的逻辑,达到一种与时俱进的状态。