使用Vivado HLS实现OpenCV的开发流程
0赞转载自:http://www.chinaaet.com/article/217492
本文通过对OpenCV中图像类型和函数处理方法的介绍,通过设计实例描述在vivadoHLS中调用Op
开源计算机视觉 (OpenCV) 被广泛用于开发计算机视觉应用,它包含2500多个优化的视频函数的函数库并且专门针对台式机处理器和GP
1OpenCV中图像IplImage, CvMat, Mat 类型的关系和VivadoHLS中图像hls::Mat类型介绍
OpenCv中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以
1.1 OpenCV中Mat类型:矩阵类型(Matrix)。
在openCV中,Mat是一个多维的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的多维
Mat有3个重要的方法:
1、Mat mat = imread(const String* filename);
2、imshow(const string frameName, InputArray mat)
3、imwrite (const string& filename, InputArray im
Mat类型较CvMat与IplImage类型来说,有更强的矩阵运算能力,支持常见的矩阵运算。在计算密
1.2 OpenCV中CvMat类型与IplImage类型:“图像”类型
在openCV中,Mat类型与CvMat和IplImage类型都可以代表和显示图像,但是,Mat类型
补充:IplImage由CvMat派生,而CvMat由CvArr派生即CvArr -> CvMat ->
CvArr用作函数的参数,无论传入的是CvMat或IplImage,内部都是按CvMat处
在openCV中,没有向量(vector)的数据结构。任何时候,但我们要表示向量时,用矩阵数据表示即
但是,CvMat类型与我们在线性代数课程上学的向量概念相比,更抽象,比如CvMat的元素数据类型并不
CvMat* cvCreatMat(int rows ,int cols , int t
这里的type可以是任意的预定义数据类型,比如RGB或者别的多通道数据。这样我们便可以在一个CvMa
1.3 OpenCV中IplImage类型
在OpenCV类型关系上,我们可以说IplImage类型继承自CvMat类型,当然还包括其他的变量将
IplImage类型较之CvMat多了很多参数,比如depth和nChannels。在普通的矩阵类型
IplImage的对图像的另一种优化是变量origin----原点。在计算机视觉处理上,一个重要的不
1.4 VivadoHLS中图像数据类型hls::Mat<>
VivadoHLS视频处理函数库使用hls::Mat<>数据类型,这种类型用于模型化视频像素流处理,
2 使用VivadoHLS实现OpenCV到RTL代码转换的流程
2.1 OpenCV设计中的权衡
OpenCV图像处理是基于存储器帧缓存而构建的,它总是假设视频frame数据存放在外部DDR 存储器中,因此,OpenCV对于访问局部图像性能较差,因为处理器的小容量高速缓存性能不足以完成这个任
基于视频流的架构能提供高性能和低功耗,链条化的图像处理函数能减少外部存储器访问,针对视频优化的行缓存
VivadoHLS对OpenCV的支持,不是指可以将OpenCV的函数库直接综合成RTL代码,而是需
OpenCV函数不能直接通过HLS进行综合,因为OpenCV函数一般都包含动态的内存分配、浮点以及假
VivadoHLS视频库用于替换很多基本的 OpenCV函数,它与OpenCV具有相似的接口和算法,主要针对在FPGA架构中实现的图像处理函数,
2.2 VivadoHLS实现OpenCV设计流程介绍
使用VivadoHLS实现OpenCV的开发,主要的三个步骤如下:
在计算机上开发OpenCV应用,由于是开源的设计,采用C++的编译器对其进行编译,仿真和debug,
最后产生可执行文件。这些设计无需修改即可在 ARM内核上运行OpenCV应用。
使用I/O函数抽取FPGA实现的部分,并且使用可综合的VivadoHLS Video库函数代码代替OpenCV函数的调用。
运行HLS生成RTL代码,在vivadoHLS工程中启动co-sim,重用openCV的测试激励验证
产生的RTL代码。在ISE或者Vivado开发环境中做RTL的集成和SOC/FPGA实现。
2.2.1 VivadoHLS视频库函数
HLS视频库是包含在hls命名空间内的C++代码。#include “hls_video.h”
与OpenCV等具有相似的接口和等效的行为,例如:
OpenCV库:cvScale(src, dst, scale, shift);
HLS视频库:hls:cale<...>(src, dst, scale, shift);
一些构造函数具有类似的或替代性的模板参数,例如:
OpenCV库:cv::Mat mat(rows, cols, CV_8UC3);
HLS视频库:hls::Mat
ROWS和COLS指定处理的最大图像尺寸
表2.2.1 VivadoHLS视频处理函数库
2.2.2 VivadHLS实现OpenCV设计的局限性
首先,必须用HLS视频库函数代替OpenCV调用。
其次,不支持OpenCV通过指针访问帧缓存,可以在HLS中使用VDMA和 AXI Stream adpater函数代替。
再者,不支持OpenCV的随机访问。HLS对于读取超过一次的数据必须进行复制,更多的例子可以参见见h
最后,不支持OpenCVS的In-place更新,比如 cvRectangle (img, point1, point2)。
下面表格2.2.2列举了OpenCV中随机访问一帧图像处理对应HLS视频库的实现方法。
OpenCV |
HLS视频库 |
|
读操作 |
pix = cv_mat.at
pix = cvGet2D(cv_img,i,j) |
hls_img >> pix |
写操作 |
cv_mat.at
cvSet2D(cv_img,i,j,pix) |
hls_img << pix |
表 2.2.2 OpenCV和HLS中对一帧图像像素访问对应方法
2.3 用HLS实现OpenCV应用的实例(快速角点滤波器image_filter)
我们通过快速角点的例子,说明通常用VivadoHLS实现OpenCV的流程。首先,开发基于OpenC
2.3.1 设计基于OpenCV的视频滤波器设计和测试激励
在这个例子中,首先设计开发完全调用OpenCV库函数的快速角点滤波器设计opencv_image_f
void opencv_image_filter(IplImage* src, IplImage* dst)
{
IplImage* gray = cvCreateImage( cvGetSize(src), 8, 1 );
std::vector
cv::Mat gray_mat(gray,0);
cvCvtColor( src, gray, CV_BGR2GRAY );
cv::FAST( gray_mat, keypoints, 20, true);
cvCopy( src,dst);
for (int i=0;i
{
cvRectangle(dst, cvPoint(keypoints[i].pt.x-1,keypoints[i].pt.y-1),
cvPoint(keypoints[i].pt.x+1,keypoints[i].pt.y+1), cvScalar(255,0,0),CV_FILLED);
}
cvReleaseImage( &gray );
}
例子2.3.1.1 通常的OpenCV视频处理代码opencv_image_filter.cpp
int main (int argc, char** argv) {
IplImage* src=cvLoadImage(INPUT_IMAGE);
IplImage* dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
opencv_image_filter(src, dst);
cvSaveImage(OUTPUT_IMAGE_GOLDEN, dst);
cvReleaseImage(&src);
cvReleaseImage(&dst);
return 0;
}
例子2.3.1.2 OpenCV视频处理测试激励代码opencv_image_filter_tb.cpp
上面的例子是直接调用OpenCV在处理器上软件应用实现的例子,可以看到在算法设计中直接调用openc
2.3.2 使用IO函数和Vivado HLS视频库替换OpenCV函数库
需要特别说明的是,xilinx通常使用的视频处理模块都是基于axi4 streaming协议进行不同模式见像素数据的交互,也就是我们所说的AXI4 video接口协议格式。为了和xilinx视频库接口协议统一,VivadoHLS提供了视频接口函数库
VivadoHLS可综合的视频接口函数:
Hls::AXIvideo2Mat 转换AXI4 video stream到hls::Mat表示格式
Hls::Mat2AXIvideo 转换hls::Mat数据格式到AXI4 video stream
首先,我们对2.3.1中OpenCV的设计进行改写,改写的代码还是完全基于OpenCV的函数,目的是
void opencv_image_filter(IplImage* src, IplImage* dst)
{
IplImage* gray = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* mask = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* dmask = cvCreateImage( cvGetSize(src), 8, 1 );
std::vector
cv::Mat gray_mat(gray,0);
cvCvtColor(src, gray, CV_BGR2GRAY );
cv::FAST(gray_mat, keypoints, 20, true);
GenMask(mask, keypoints);
cvDilate(mask,dmask);
cvCopy(src,dst);
PrintMask(dst,dmask,cvScalar(255,0,0));
cvReleaseImage( &mask );
cvReleaseImage( &dmask );
cvReleaseImage( &gray );
}
例子2.3.2.1另一种OpenCV设计应用opencv_image_filter.cpp
其次,使用Vivado HLS视频库替代标准OpenCV函数,并使用可综合的视频接口函数,采用video stream的方式交互视频数据。用于FPGA的硬件可综合模块由VivadoHLS视频库函数与接口组成
void image_filter(AXI_STREAM& input, AXI_STREAM& output, int rows, int cols)
{
//Create AXI streaming interfaces for the core
#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=return metadata="-bus_bundle CONTROL_BUS"
#pragma HLS interface ap_stable port=rows
#pragma HLS interface ap_stable port=cols
hls::Mat
hls::Mat
#pragma HLS dataflow
hls::AXIvideo2Mat(input, _src);
hls::Mat
hls::Mat
#pragma HLS stream depth=20000 variable=src1.data_stream
hls::Mat
hls::Mat
hls:calar<3,unsigned char> color(255,0,0);
hls:uplicate(_src,src0,src1);
hls::Mat
hls::CvtColor
hls::FASTX(gray,mask,20,true);
hls:ilate(mask,dmask);
hls:aintMask(src1,dmask,_dst,color);
hls::Mat2AXIvideo(_dst, output);
}
例子2.3.2.2 采用VivadoHLS视频库替换后可综合的设计opencv_image_filter.cpp
最后,在vivadoHLS开发环境下综合例子2.3.2.2的设计,产生RTL代码并重用OpenCV的
3 VHLS实现OpenCV设计流程总结
通过上面章节介绍以及在vivadoHLS工具中实现opencV设计的例子可以看出,OpenCV函数可