学fpga(hls之图像处理)
Posted 费晓行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学fpga(hls之图像处理)相关的知识,希望对你有一定的参考价值。
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
本身hls为了推广,寻找了一些适合hls开发的领域。图像处理就是其中一个方向。图像处理的应用十分广泛,本身又需要进行短时间的大数据量处理,十分适合hls的使用。所以,xilinx官方提供了hls的函数库,同时为了进行testbench的测试,这些接口本身也兼容opencv已有的接口。
1、头文件引用
#include <hls_video.h>
#define MAX_HEIGHT 800
#define MAX_WIDTH 1280
typedef hls::stream<ap_axiu<24,1,1,1> > AXI_STREAM;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC1> GRAY_IMAGE;
typedef unsigned char uchar;
typedef hls::Scalar<1, uchar> GRAY_PIXEL;
头文件引用的部分比较简单,本身只要包含hls_video.h文件即可,剩下来的就是对stream、Mat、Scalar进行类型定义操作。因为在计算的过程中涉及到大量的模板处理,所以编写代码的时候最好选用cpp文件。
2、灰化处理
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
RGB_IMAGE img_2(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_1, img_2);
hls::Mat2AXIvideo(img_2, output_stream);
灰化处理是图像处理的第一步,最大的好处就是可以减少计算的数据量。这里的hls::CvtColor都是官方提供的函数。之所以会有两个函数,是因为数据格式的问题,毕竟最后还要回归到AXI_STREAM的形式。
3、高斯滤波
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::GaussianBlur<3,3>(img_1, img_2);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_2, img_3);
hls::Mat2AXIvideo(img_3, output_stream);
高斯滤波是实际场景中经常使用到的算法。<3,3>模板也是可以选择的,一般3、5、7都是用的比较多的模板,可以根据实际情况灵活进行配置。
4、直方图增强
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::EqualizeHist<HLS_8UC1, HLS_8UC1, MAX_HEIGHT, MAX_WIDTH>(img_1, img_2);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_2, img_3);
hls::Mat2AXIvideo(img_3, output_stream);
直方图增强也是用的比较多的一种方法。它的基本原理就是计算出每个像素个数在整体像素里面的比例,据此依据这个比例来对像素值做出修正处理。
5、Sobel算子
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
// sobel算子
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::Sobel<1,0,3>(img_1, img_2);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_2, img_3);
hls::Mat2AXIvideo(img_3, output_stream);
各种算子一般用来对图像进行边缘检测。算子计算式二值化之前的重要步骤。一般经过边缘检测之后,图像中物体的轮廓会变得非常明显,和周围的其他像素有着明显的区别。
6、二值化
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::Threshold(img_1, img_2, 150, 255, HLS_THRESH_BINARY);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_2, img_3);
hls::Mat2AXIvideo(img_3, output_stream);
做完了算子计算,下面就是二值化。小于某个数值的像素全部置为0,大于某个数值的像素全部置为255。和灰化类似,通过二值化之后,像素中的信息更为集中和聚焦。
7、膨胀和腐蚀
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
GRAY_IMAGE img_3(rows, cols);
RGB_IMAGE img_4(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
hls::Dilate(img_1, img_2);
hls::Erode(img_2, img_3);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_3, img_4);
hls::Mat2AXIvideo(img_4, output_stream);
二值化之后的图像一般还会存在着空洞、藕断丝连的情况。这个时候可以通过进行开运算、或者是闭运算来解决。换言之,就是用膨胀、腐蚀的方法来解决。这也是图像处理的必要步骤。
8、轮廓提取
轮廓提取一般还是通过cpu来完成,这部分不适合用fpga来进行加速处理。通常fpga做好了灰化、增强、滤波、sobel算子、二值化和膨胀腐蚀之后,会把图像交还给cpu继续进行处理,完成剩下来的操作,这部分式必不可少的。当然,做完了轮廓提取,还要通过周长、面积、圆度等特征做进一步的提取和分析。
9、接口部分
这部分的算法只是完成了AXI_STREAM到AXI_STREAM的转换,如果要进行显示,或者返回到cpu运算,还需要其他IP核的协调核帮助。但总体来说,这部分还是最重要的。
10、自定义图像算法
void pixel_binary(GRAY_IMAGE& src, GRAY_IMAGE& dst, uchar binary)
uchar value;
GRAY_PIXEL src_data;
GRAY_PIXEL dst_data;
for(int i =0 ; i < MAX_HEIGHT; i++)
for(int j = 0; j < MAX_WIDTH; j++)
#pragma HLS PIPELINE II=1
src >> src_data;
value = src_data.val[0];
dst_data.val[0] = value > binary ? 255:0;
dst << dst_data;
void rgb2gray(AXI_STREAM& input_stream,
AXI_STREAM& output_stream,
int rows,
int cols,
uchar binary)
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE s_axilite port=binary
#pragma HLS INTERFACE axis port=output_stream
#pragma HLS INTERFACE axis port=input_stream
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS DATAFLOW
RGB_IMAGE img_0(rows, cols);
GRAY_IMAGE img_1(rows, cols);
GRAY_IMAGE img_2(rows, cols);
RGB_IMAGE img_3(rows, cols);
hls::AXIvideo2Mat(input_stream, img_0);
hls::CvtColor<HLS_RGB2GRAY, HLS_8UC3, HLS_8UC1>(img_0, img_1);
pixel_binary(img_1, img_2, binary);
hls::CvtColor<HLS_GRAY2RGB, HLS_8UC1, HLS_8UC3>(img_2, img_3);
hls::Mat2AXIvideo(img_3, output_stream);
除了hls提供的标准算之外,很多时候用户还需要自定义自己的算法。比如10中的pixel_binary这个函数。binary是通过s_axilite传递的参数,参数直接传递给pixel_binary。在函数中,通过GRAY_PIXEL和binary比较的方法,直接将像素设定为0或者式255。当然,实际应用的场景可能会比这个复杂一点,到时候只要根据具体情况具体分析即可。
11、关于testbench
IplImage2AXIvideo
AXIvideo2IplImage
做testbench的时候,需要把图像换成AXIvideo,等到做完之后,如果需要保存的话,还需要把AXIvideo转换成图像,这一点需要注意一下。
以上是关于学fpga(hls之图像处理)的主要内容,如果未能解决你的问题,请参考以下文章