你的位置:EETOP 赛灵思(Xilinx) 社区 >> >> 全部 >> 详细内容

HLS图像处理系列——肤色检测

发布者:jackzhang 时间:2015-10-09 12:59:45

本博文采用Xilinx HLS 2014.4工具,实现一个肤色检测的模块。其中,本文重点是构建HLS图像处理函数。新建HLS工程的步骤,本博文不再详述。

本工程新建之后,只添加了五个文件,如下图所示。其中,top.cpp中的主函数最终会综合生成HLS硬件图像处理模块。test.cpp是测试文件,调用测试图片,测试top.cpp的图像处理函数功能。


top.cpp的源码如下:

  1. #include "top.h"  
  2. #include "imgprocess.h"  
  3. #include <string.h>  
  4.   
  5. void ImgProcess_Top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,  
  6.         int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)  
  7. {  
  8.     #pragma HLS RESOURCE variable=input core=AXIS metadata="-bus_bundle INPUT_STREAM"  
  9.     #pragma HLS RESOURCE variable=output core=AXIS metadata="-bus_bundle OUTPUT_STREAM"  
  10.     #pragma HLS RESOURCE core=AXI_SLAVE variable=rows metadata="-bus_bundle CONTROL_BUS"  
  11.     #pragma HLS RESOURCE core=AXI_SLAVE variable=cols metadata="-bus_bundle CONTROL_BUS"  
  12.     #pragma HLS RESOURCE core=AXI_SLAVE variable=y_lower metadata="-bus_bundle CONTROL_BUS"  
  13.     #pragma HLS RESOURCE core=AXI_SLAVE variable=y_upper metadata="-bus_bundle CONTROL_BUS"  
  14.     #pragma HLS RESOURCE core=AXI_SLAVE variable=cb_lower metadata="-bus_bundle CONTROL_BUS"  
  15.     #pragma HLS RESOURCE core=AXI_SLAVE variable=cb_upper metadata="-bus_bundle CONTROL_BUS"  
  16.     #pragma HLS RESOURCE core=AXI_SLAVE variable=cr_lower metadata="-bus_bundle CONTROL_BUS"  
  17.     #pragma HLS RESOURCE core=AXI_SLAVE variable=cr_upper metadata="-bus_bundle CONTROL_BUS"  
  18.     #pragma HLS RESOURCE core=AXI_SLAVE variable=return metadata="-bus_bundle CONTROL_BUS"  
  19.   
  20.     #pragma HLS INTERFACE ap_stable port=rows  
  21.     #pragma HLS INTERFACE ap_stable port=cols  
  22.     #pragma HLS INTERFACE ap_stable port=y_lower  
  23.     #pragma HLS INTERFACE ap_stable port=y_upper  
  24.     #pragma HLS INTERFACE ap_stable port=cb_lower  
  25.     #pragma HLS INTERFACE ap_stable port=cb_upper  
  26.     #pragma HLS INTERFACE ap_stable port=cr_lower  
  27.     #pragma HLS INTERFACE ap_stable port=cr_upper  
  28.     RGB_IMAGE  src_mat(rows,cols);  
  29.     RGB_IMAGE  dst_mat(rows,cols);  
  30.     #pragma HLS dataflow  
  31.     hls::AXIvideo2Mat(input, src_mat);  
  32.     SkinColorDetect(src_mat,dst_mat, y_lower, y_upper, cb_lower, cb_upper, cr_lower, cr_upper);  
  33.     hls::Mat2AXIvideo(dst_mat, output);  
  34. }  
其中,ImgProcess_Top这个函数最后生成一个IP核,可以放在图像通路中使用。函数的接口如下:

input:视频流输入,axi-stream接口;

output:视频流输出,axi-stream接口;

rows,cols:可配置参数,图像的行数、列数。通过AXI-Lite接口,由PS配置。

y_lower,y_upper,cb_lower,cb_upper,cr_lower,cr_upper:可配置参数,肤色检测的一些阈值。通过AXI-Lite接口,由PS配置。

上述代码中,比较重要的一条优化指令为:#pragma HLS dataflow。它使得任务之间为流水线方式,也就是hls::AXIvideo2Mat(input, src_mat);SkinColorDetect(src_mat,dst_mat, y_lower, y_upper, cb_lower, cb_upper, cr_lower, cr_upper);hls::Mat2AXIvideo(dst_mat, output);这三个函数之间为流水线方式执行。

肤色检测的核心函数为SkinColorDetect(src_mat,dst_mat, y_lower, y_upper, cb_lower, cb_upper, cr_lower, cr_upper);它包含在imgprocess.h源码如下:

  1. #ifndef ___IMAGEPROCESS__  
  2. #define ___IMAGEPROCESS__  
  3. #include "top.h"  
  4.   
  5. u1 rgb2ycbcr(u8 B, u8 G, u8 R, int y_lower, int y_upper, int cb_lower, int cb_upper, int cr_lower, int cr_upper)  
  6. {  
  7. #pragma HLS PIPELINE  
  8.     u8 y, cr, cb;  
  9.     y = (76 * R.to_int() + 150 * G.to_int() + 29 * B.to_int()) >> 8;  
  10.     cb = 128 + ((128*B.to_int() -43*R.to_int() - 85*G.to_int())>>8);  
  11.     cr = 128 + ((128*R.to_int() -107*G.to_int() - 21 * B.to_int())>>8);  
  12.   
  13.     if (y > y_lower && y < y_upper && cb > cb_lower && cb < cb_upper  
  14.             && cr > cr_lower && cr < cr_upper)  
  15.          return 1;  
  16.     else  
  17.          return 0;  
  18. }  
  19.   
  20. namespace hls {  
  21. template<int SRC_T, int DST_T,int ROW, int COL>  
  22. void ImgProcess(Mat<ROW, COL, SRC_T> &_src, Mat<ROW, COL, DST_T>    &_dst,  
  23.         int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)  
  24. {  
  25.     loop_height: for(HLS_SIZE_T i= 0;i< ROW;i++)  
  26.     {  
  27.     #pragma HLS LOOP_TRIPCOUNT max=ROW  
  28.         loop_width: for (HLS_SIZE_T j= 0;j< COL;j++)  
  29.         {  
  30.         #pragma HLS LOOP_FLATTEN OFF  
  31.         #pragma HLS LOOP_TRIPCOUNT max=COL  
  32.         #pragma HLS DEPENDENCE array inter false  
  33.         #pragma HLS PIPELINE  
  34.             u8 r, g, b;  
  35.             u1 skin_region;  
  36.   
  37.             HLS_TNAME(SRC_T) temp0=0;  
  38.             HLS_TNAME(SRC_T) temp1=0;  
  39.             HLS_TNAME(SRC_T) temp2=0;  
  40.             /***********stream input *********/  
  41.             _src.data_stream[0]>>temp0;  
  42.             _src.data_stream[1]>>temp1;  
  43.             _src.data_stream[2]>>temp2;  
  44.   
  45.             b = temp0;  
  46.             g = temp1;  
  47.             r = temp2;  
  48.             /********detect skin region*******/  
  49.             skin_region = rgb2ycbcr(b, g, r,y_lower,y_upper,cb_lower,cb_upper,cr_lower,cr_upper);  
  50.             HLS_TNAME(DST_T) temp_dst0=0;  
  51.             HLS_TNAME(DST_T) temp_dst1=0;  
  52.             HLS_TNAME(DST_T) temp_dst2=0;  
  53.   
  54.             temp_dst0= (skin_region == 1)? b : (u8)0;  
  55.             temp_dst1= (skin_region == 1)? g : (u8)0;  
  56.             temp_dst2= (skin_region == 1)? r : (u8)0;  
  57.   
  58.             /***********stream output ********/  
  59.             _dst.data_stream[0]<<temp_dst0;  
  60.             _dst.data_stream[1]<<temp_dst1;  
  61.             _dst.data_stream[2]<<temp_dst2;  
  62.   
  63.         }  
  64.     }  
  65. }  
  66.   
  67.   
  68.   
  69. template<int SRC_T, int DST_T,int ROW, int COL>  
  70. void SkinColorDetect(Mat<ROW, COL, SRC_T> &_src,Mat<ROW, COL, DST_T> &_dst,  
  71.         int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)  
  72. {  
  73. #pragma HLS INLINE  
  74.     ImgProcess(_src, _dst, y_lower, y_upper, cb_lower, cb_upper, cr_lower, cr_upper);  
  75. }  
  76.   
  77. }  
  78.   
  79.   
  80.   
  81. #endif  


核心函数是rgb2ycbcr这个函数。关于肤色检测有多种方式,本文的肤色检测方法是将rgb转换为ycbcr,然后设置阈值。

保存后,综合。综合完毕,打开分析工具:


点击红框里的内容:


可以看到imgprocess.h中,ImgProcess这个函数的执行状态:


然后点击ImgProcess_Top_rgb2ycbcr,可以看到如下图:


我们发现,只需一个时钟周期即可执行完毕。这是因为rgb2ycbcr这个函数采用了流水线的优化指令:#pragma HLS PIPELINE。

综合之后,就可以测试了。test.cpp内容如下:

  1. #include "top.h"  
  2. #include "hls_opencv.h"  
  3. #include"iostream"  
  4. #include<time.h>  
  5. using namespace std;  
  6. using namespace cv;  
  7.   
  8.   
  9. int main (int argc, char** argv) {  
  10.   
  11.   
  12.   
  13.     Mat src = imread("test.jpg");  
  14.     AXI_STREAM  src_axi, dst_axi;  
  15.     Mat dst(Size(640,480),CV_8UC3);  
  16.   
  17.     resize(src,src,Size(640,480));  
  18.     //mat to axi video  
  19.     cvMat2AXIvideo(src, src_axi);  
  20.     //test function  
  21.     ImgProcess_Top(src_axi, dst_axi, 480, 640,0,255,80,135,131,185);  
  22.     //axi video to mat  
  23.     AXIvideo2cvMat(dst_axi, dst);  
  24.   
  25.     imshow("src",src);  
  26.     imshow("dst_hls",dst);  
  27.   
  28.     waitKey(0);  
  29.   
  30.     return 0;  
  31. }  
测试的图像如下:

运行测试程序后,输出图像如下:

通过测试后,点击hls界面工具栏的export RTL按钮,打包生成ip。最后的IP如下所示:

最新课程

  • 深入浅出玩儿转FPGA

    本视频基于Xilinx公司的Artix-7FPGA器件以及各种丰富的入门和进阶外设,提供了一些典型的工程实例,帮助读者从FPGA基础知识、逻辑设计概念

  • 从零开始大战FPGA基础篇

    本课程为“从零开始大战FPGA”系列课程的基础篇。课程通俗易懂、逻辑性强、示例丰富,课程中尤其强调在设计过程中对“时序”和“逻辑”的把控,以及硬件描述语言与硬件电路相对应的“

  • Verilog基础及典型数字

    课程中首先会给大家讲解在企业中一般数字电路从算法到流片这整个过程中会涉及到哪些流程,都分别使用什么工具,以及其中每个流程都分别做了