HLS图像处理总结(一)
HLS工具
以个人的理解,xilinx将HLS(高层次综合)定位于更方便的将复杂算法转化为硬件语言,通过添加某些配置条件HLS工具可以把可并行化的C/C++的代码转化为vhdl或verilog,相比于纯人工使用vhdl实现图像算法,该工具综合出的代码的硬件资源占用可能较多,但并没有相差太大(见论文:基于HLS的 SURF特征提取硬件加速单元设计与实现),而纯人工用硬件描述语言实现一个复杂的图像处理算法要求十分深厚的FPGA功底,下面简单总结下好早之前做的一个在zybo开发板上的HLS图像处理通路。
主要从三个工程分析
1.sobel边缘检测
头文件部分涉及到‘hls_video.h’:主要就做这么几件事情,定义头文件名,导入需要的库文件,定义参数,重定义数据结构,声明函数
#ifndef _TOP_H_
#define _TOP_H_
#include"hls_video.h" //这里调用可以综合的视频库
// maximum image size
#define MAX_WIDTH 1920
#define MAX_HEIGHT 1080
// I/O Image Settings
#define INPUT_IMAGE "test_1080p.jpg"
#define OUTPUT_IMAGE "result_1080p.jpg"
#define OUTPUT_IMAGE_GOLDEN "result_1080p_golden.jpg"
// typedef video library core structures
typedef hls::stream<ap_axiu<,,,> > AXI_STREAM_IN;
typedef hls::stream<ap_axiu<,,,> > AXI_STREAM_OUT;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
// top level function for HW synthesis
void hls_sobel(AXI_STREAM_IN& src_axi, AXI_STREAM_OUT& dst_axi, int rows, int cols); #endif
主要函数的具体定义:
#include "top.h"
void hls_sobel(AXI_STREAM_IN& input, AXI_STREAM_OUT& output, int rows, int cols) {
#pragma HLS RESOURCE variable=input core=AXI4Stream metadata="-bus_bundle INPUT_STREAM"
#pragma HLS RESOURCE variable=output core=AXI4Stream metadata="-bus_bundle OUTPUT_STREAM"
#pragma HLS INTERFACE ap_none port=cols
#pragma HLS INTERFACE ap_none port=rows
//AP_CONTROL_BUS_AXI(CONTROL_BUS);
//set_directive_interface -mode ap_ctrl_none hls_sobel
#pragma HLS interface ap_ctrl_none port=return RGB_IMAGE img_0(rows, cols);//输入图像的存储空间
RGB_IMAGE img_1(rows, cols);//输出图像内存大小的指定
#pragma HLS DATAFLOW // must use data flow to stream the data
hls::AXIvideo2Mat(input, img_0); //read video stream by frames
hls::Sobel<,,>(img_0, img_1);//use Hls Sobel
//根据模板,<1,0,3>中前两个部分规定了x方向的检测还是y方向的检测,<1,0>表示的是y方向的检测,size=3代表sobel算子的维数规定。
//hls::Erode<>();//use Hls Sobel
hls::Mat2AXIvideo(img_1, output); //write the frames to video stream
}
除了优化部分以外,主要做的就是定义输入输出图像的内存空间,然后将输入的数据格式转换为mat格式,用于实现ip1image的处理,然后就是直接调用库里的sobel函数,最后图像转化为video-stream输出即可。
需要注意优化部分:视频输入输出接口优化为stream格式,将控制接口分配到AXI4 Lite接口,指定“rows”可通过AXI4-Lite接口进行访问并且声明在函数执行过程中 “rows”不会改变,其实这几句优化语句中最关键的一条指令为启用数据流优化:#pragma HLS dataflow,它使得任务之间以流水线的方式执行,还有就是#pragma HLS interface ap_ctrl_none port=return。
测试函数:
#include "top.h"
#include "opencv/cv.h"
#include "opencv/cxcore.h"
#include "opencv/highgui.h"
#include "hls_opencv.h"
int main (int argc, char** argv) //argc 是 argument count的缩写,表示传入main函数的参数个数;
//argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径,所以确切的说需要我们输入的main函数的参数个数应该是argc-1个;
{
IplImage* src = cvLoadImage(INPUT_IMAGE);//为输入图像定义好存储空间
IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);//为输出图像定义好存储空间
AXI_STREAM_IN src_axi;//定义输入输出AXI数据流
AXI_STREAM_OUT dst_axi;//
IplImage2AXIvideo(src, src_axi); //将图像转为视频流结构
hls_sobel(src_axi, dst_axi, src->height, src->width);
AXIvideo2IplImage(dst_axi, dst);
cvSaveImage(OUTPUT_IMAGE, dst);
cvReleaseImage(&src);
cvReleaseImage(&dst);
}//不加符号
注意头文件导入时路径的问题,思路是定义好图像空间后定义视频图像的变量,然后将输入的图像转换为视频流结构,用自己写的函数处理后,观察处理后的结果即可
最后生成IP核的摸样
2.skin-detect部分
头文件
#ifndef _TOP_H_
#define _TOP_H_ #include "hls_video.h"
// maximum image size
#define MAX_WIDTH 1920
#define MAX_HEIGHT 1080 typedef unsigned char uchar; // I/O Image Settings
#define INPUT_IMAGE "test.jpg"
#define OUTPUT_IMAGE "result_1080p.bmp"
#define OUTPUT_IMAGE_GOLDEN "test_img1.jpg" // typedef video library core structures
typedef hls::stream<ap_axiu<,,,> > AXI_STREAM;
typedef hls::Mat<MAX_HEIGHT, MAX_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Scalar<, unsigned char> RGB_PIXEL; //函数声明,,,用到了命名空间,这就是一个虚拟文件夹的意思
namespace hls
{
void hls_skin_dection(RGB_IMAGE& src, RGB_IMAGE& dst,int rows, int cols,
int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper);
} void ImgProcess_Top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,
int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper); #endif
涉及到的mat以及scalar格式的数据结构可参考:
主要函数:
#include "top.h"
#include <string.h> void hls::hls_skin_dection(RGB_IMAGE& src, RGB_IMAGE& dst,int rows, int cols,
int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)
{ LOOp_ROWS:for(int row = ; row < rows ; row++)
{
//#pragma HLS loop_flatten off
LOOp_COLS:for(int col = ; col < cols; col++)
{
#pragma HLS pipeline II=1 off //--------------------------优化指令1
//变量定义
RGB_PIXEL src_data;
RGB_PIXEL pix;
RGB_PIXEL dst_data;
bool skin_region; if(row < rows && col < cols) {
src >> src_data;
} //获取RGB图像通道数据
uchar B = src_data.val[];
uchar G = src_data.val[];
uchar R = src_data.val[]; //RGB-->YCbCr颜色空间转换
uchar y = ( * R + * G + * B) >> ;
uchar cb = ((*B -*R - *G)>>) + ;
uchar cr = ((*R -*G - * B)>>)+ ; //肤色区域判定
if (y > y_lower && y < y_upper && cb > cb_lower && cb < cb_upper && cr > cr_lower && cr < cr_upper)
skin_region = ;
else
skin_region = ;
//将肤色区域的值大小置为255,即白色
uchar temp0= (skin_region == )? (uchar): B;
uchar temp1= (skin_region == )? (uchar): G;
uchar temp2= (skin_region == )? (uchar): R; dst_data.val[] = temp0;
dst_data.val[] = temp1;
dst_data.val[] = temp2;
//复制处理完成后输出图像
dst << dst_data;
}
}
}
//该函数的作用主要是把上面的skin-detect函数的输入输出端口做一个封装,以便处理视频输入信号
void ImgProcess_Top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,
int y_lower,int y_upper,int cb_lower,int cb_upper,int cr_lower,int cr_upper)
//定义该函数的功能用于将上面的肤色检测用AXI_STREAM结构封装端口
{
///*
#pragma HLS RESOURCE variable=input core=AXIS metadata="-bus_bundle INPUT_STREAM"
#pragma HLS RESOURCE variable=output core=AXIS metadata="-bus_bundle OUTPUT_STREAM" #pragma HLS RESOURCE core=AXI_SLAVE variable=rows metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=cols metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=y_lower metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=y_upper metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=cb_lower metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=cb_upper metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=cr_lower metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=cr_upper metadata="-bus_bundle CONTROL_BUS"
#pragma HLS RESOURCE core=AXI_SLAVE variable=return metadata="-bus_bundle CONTROL_BUS" #pragma HLS INTERFACE ap_stable port=rows
#pragma HLS INTERFACE ap_stable port=cols
#pragma HLS INTERFACE ap_stable port=y_lower
#pragma HLS INTERFACE ap_stable port=y_upper
#pragma HLS INTERFACE ap_stable port=cb_lower
#pragma HLS INTERFACE ap_stable port=cb_upper
#pragma HLS INTERFACE ap_stable port=cr_lower
#pragma HLS INTERFACE ap_stable port=cr_upper
///*/
RGB_IMAGE img_0(rows, cols);
RGB_IMAGE img_1(rows, cols); #pragma HLS dataflow
hls::AXIvideo2Mat(input,img_0);//将video图像数据结构转换为mat型(RGB图像)数据,以便于输入到下面的检测函数中。
hls::hls_skin_dection(img_0,img_1,rows,cols,y_lower,y_upper,cb_lower,cb_upper,cr_lower,cr_upper);
hls::Mat2AXIvideo(img_1, output);//将mat型(RGB图像)数据转换为video图像数据结构输出
}
我们对视频接口的约束如下:将src和dst指定为为以 “INPUT_STREAM” 命名的AXI4 Stream,将控制接口分配到AXI4 Lite接口,指定“rows”可通过AXI4-Lite接口进行访问并且声明在函数执行过程中 “rows”不会改变,其实这几句优化语句中最关键的一条指令为启用数据流优化:#pragma HLS dataflow,它使得任务之间以流水线的方式执行,即hls::AXIvideo2Mat(src,img_0);hls::skin_detect(img_0,img_1,rows,cols ,cb_lower,cb_upper,cr_lower,cr_upper);hls::Mat2AXIvideo(img_1, dst),这三个函数之间为流水线方式。
测试文件:思路也是导入图像文件,然后创建好保存结果的空间,然后定义视频流变量,将图像输入转换为axi-stream格式,然后用自己编写的函数处理后,输出转换为IplImage格式后,输出图像观察即可。
#include "top.h"
#include "hls_opencv.h"
#include "iostream"
#include <time.h> using namespace std;
using namespace cv; int main (int argc, char** argv)
{
//IplImage* src = cvLoadImage(INPUT_IMAGE);
IplImage* src = cvLoadImage("test.jpg");
//IplImage* src = cvLoadImage("test_img1.jpg");
IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels); AXI_STREAM src_axi, dst_axi;
IplImage2AXIvideo(src, src_axi); ImgProcess_Top(src_axi, dst_axi, src->height, src->width,,,,,,);
AXIvideo2IplImage(dst_axi, dst); cvShowImage("src",src);
cvShowImage("dst_hls",dst);
waitKey();//参数<=0时等待按键事件发生,按下键的话返回按键的值, 否则返回-1; return ;
}
下一篇介绍:
3.FFT的HLS实现
3.HOG实现部分https://www.cnblogs.com/zhazhiqiang/p/3595266.html
HLS图像处理总结(一)的更多相关文章
- HLS图像处理系列——肤色检測
本博文採用Xilinx HLS 2014.4工具.实现一个肤色检測的模块.当中,本文重点是构建HLS图像处理函数. 新建HLSproject的步骤,本博文不再详述. 本project新建之后,仅仅加入 ...
- Zynq开发之HLS
Zynq开发之HLS 由 FPGA菜鸟 于 星期三, 06/28/2017 - 11:53 发表 HLS简介 HLS(High Level Synthesis)即高层次综合,不同于以往的FPGA逻辑开 ...
- OpenCV2计算机编程手册(二)基于类的图像处理
1. 在算法设计中使用策略(Strategy)模式 策略设计模式的目标是将算法封装在类中.因此,可以更容易地替换一个现有的算法,或者组合使用多个算法以拥有更复杂的处理逻辑.此外,该模式将算法的复杂度隐 ...
- HLS:OpenCV和RTL代码转换关系
OpenCV 图像处理是基于存储器帧缓存而构建的, 它总是假设视频帧数据存放在外部 DDR 存储器中. 由于处理器的小容量高速缓存性能的限制, 因此, OpenCV 访问局部图像性能较差. 并且, 从 ...
- Java版流媒体编解码和图像处理(JavaCPP+FFmpeg)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Python图像处理丨基于OpenCV和像素处理的图像灰度化处理
摘要:本篇文章讲解图像灰度化处理的知识,结合OpenCV调用cv2.cvtColor()函数实现图像灰度操作,使用像素处理方法对图像进行灰度化处理. 本文分享自华为云社区<[Python图像处理 ...
- OpenCV图像处理与视频分析详解
1.OpenCV4环境搭建 VS2017新建一个控制台项目 配置包含目录 配置库目录 配置链接器 配置环境变量 重新启动VS2017 2.第一个图像显示程序 main.cpp #include< ...
- Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉
Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉 1.1. 按照当前流行的分类方法,可以分为以下三部分:三部分 图像处理 图像分析 计算机视觉1 1.2. 图像处理需要 ...
- Atitit 图像处理的摩西五经attilax总结
Atitit 图像处理的摩西五经attilax总结 1. 数字图像处理(第三版)1 2. 图像处理基础(第2版)(世界著名计算机教材精选)1 3. 计算机视觉特征提取与图像处理(第三版)2 4. Op ...
随机推荐
- python 2.7编译安装
一 官网下载python2.7源码: python安装pip python -m ensurepip --default-pip
- UVA 10273
我是用暴力过的,虽然网上说刘汝佳出的这道题考的是堆,我不太懂,..用暴力时间复杂度高一些,但是一样能过 所要注意的就是周期问题,因为只要同时存在某一天超过一头牛产奶量最小,就不会杀牛,而每头牛的周期和 ...
- 干货|Kubernetes集群部署
Nginx-ingress Controller
Kubernetes提供了两种内建的云端负载均衡机制用于发布公共应用,一种是工作于传输层的Service资源,它实现的是TCP负载均衡器:另一种是Ingress资源,它实现的是HTTP(S)负载均衡器 ...
- 吴裕雄--天生自然Linux操作系统:Linux 文件与目录管理
Linux的目录结构为树状结构,最顶级的目录为根目录 /. 其他目录通过挂载可以将它们添加到树中,通过解除挂载可以移除它们. 绝对路径: 路径的写法,由根目录 / 写起,例如: /usr/share/ ...
- ccf-csp 任务调度,回溯算法我觉得ok神**wa了
#include<iostream> #include<string.h> #include<cmath> #define M 41 #define min(a,b ...
- vector内部的实现1
写vector的内部方法 #include<vector> using std::vector; //写一个动态内存 class CA{ int a; public: CA(int i){ ...
- Python—快速排序算法
# _*_ coding=utf-8 _*_ """ 快速排序: 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比 另外一部分的所有数据都要小,然后 ...
- BZOJ4422[Cerc2015]Cow Confinement(扫描线+线段树)
很容易发现一个O(n2)DP,f[i][j]=f[i][j+1]+f[i+1][j]-f[i+1][j+1].然后由于有栅栏,一些位置没办法走,然后就可以用类似差分的方法,f[i]表示当前行f[i+1 ...
- GetTextExtentPoint32
/////////////////////////////////////////////////////////////// // 04FirstWindow.cpp文件 #include < ...
- 《C程序设计(第四版)》小记
我看的这本书很经典,它是谭浩强写的,也就是广为流传的“C语言红皮书”.在网上看了很多帖子,生活中也问过一些朋友,大多数人是不认可这本书的.很多人都说这本书很烂,看不懂,然后去“追逐”国外的一些教材.其 ...