HLS图像处理系列——在ZEDBoard搭建DDR图像处理通路

ZYNQ芯片内包含一个丰富特性的基于双核ARM Cortex-A9的处理子系统(Processing System,PS)和Xilinx 28nm可编程逻辑(Programmable Logic,PL)。PS除了核心外还包括片上存储器、外部存储器接口以及大量外设连接接口。

利用ARM,我们可以做嵌入式操作系统相关的任务,如图形界面、用户输入、网络、DDR3控制等,由于ARM本身具有丰富的外设接口,而且支持多级流水线,处理这些事务游刃有余,但对于计算量较大的应用却捉襟见肘,因为ARM本身还是典型的串行处理器,不适合做大数据、实时性较高的处理任务。FPGA恰好弥补了这一点,利用可编程逻辑可以实现并行处理,只要逻辑资源够用,我们可以采用以空间换时间的策略,使多个计算单元同时进行,可大大缩短处理时间。

用ZYNQ进行图像处理具有架构上的优势,因此对于用ZYNQ做视频相关的开发人员,一套ZYNQ上的图像通路是必须的。本博文介绍的是一种摄像头+HLS图像处理+DDR存储+VGA显示的图像通路。该通路是本人和另外一位同事合作实现,本人负责摄像头的FPGA驱动、HLS图像处理IP的实现以及系统的后期优化。由于涉及公司项目,因此不能提供工程文件,只提供框架和思路。

系统框架如下:

重点模块介绍:

Camera:采用ov7725摄像头,帧率60fps,分辨率640*480。关于摄像头时序的详解,请参考本人博文《教程——在ZEDBoard实现图像通路(Block Ram版本)》

封装后的摄像头IP如下图:

VDMA:在本设计中,VDMA的地位和通常设计中的DMA相似。但是,和DMA不同的是,VDMA专门为视频流数据提供的高度存储访问模块。其通过AXI-Stream协议接收视频数据,而控制信号(比如帧缓冲的大小,DMA功能的开启和关闭,以及一些其他的设置)则通过AXI-Lite从其他接口访问。

VDMA拥有两条DMA通路,S2MM通路将输入的AXI4-Stream数据流映射到指定的帧缓冲,而MM2S则相反,将帧缓冲输出为AXI4-Stream类型的数据流。

VDMA的配置界面如图:

其中可以看到一些对于数据帧的配置信息,以及FrameBuffers数量的设置。FrameBuffers数量至少为3个,因为如果少于3个,那么会出现写入DDR与读取DDR的冲突,导致图像出现断层现象。在本设计中,FrameBuffers设置为3个。

Video In to AXI4-Stream 与 AXI4-Stream to Video Out:由于摄像头传入的信号使用的协议并非AXI4-Stream,而VDMA却需要接收AXI4-Stream类型的数据,所以需要有专门的IP核来进行两者之间的转换。

这两个IP核是:

Video In to AXI4-Stream,该IP将视频数据转化为AXI4-Stream类型。本工程中,视频数据来自于camera模块,只需要camera提供四路信号:行同步、场同步、24bit的像素、数据有效信号。

AXI4-Stream to Video Out,该IP将AXI4-Stream类型数据转化为视频数据。视频数据即为VGA信号,包含行同步、场同步、数据有效信号以及像素。该模块有一个timing的输入,在本系统中,来自于video timing control IP。video timing control模块给AXI4-Stream to Video Out IP提供一个640*480p的VGA时序信号。

下图为Video In to AXI4-Stream IP与AXI4-Stream to Video Out IP:

这两个IP核在本设计中处于桥梁地位,用于连接外部IO和VDMA。在这两个模块内部的视频数据都是AXI4-Stream类型,省去了地址,因此速度更快、更容易处理。一般而言,HLS硬件图像处理模块都会放在这两个IP核之间。

HLS图像处理模块:本设计中,构建了一个简单的Sobel图像处理模块,由HLS工具生成打包成IP。关于HLS工具不多介绍,可以参考本人博客《HLS图像处理系列——前言》来初步了解HLS。HLS生成的IP输入输出视频流都符合AXI4-Stream协议。

然后,附上vivado的工程截图:

在SDK工程,主要是进行HLS IP的初始化与VDMA的初始化。只有初始化之后,整个图像通路才能正确运行。HLS初始化源码短短几行,但也是折磨了我好久,因为需要关闭中断,好长时间内都没有发现这个问题。初始化重点源码如下:

/************config hls ip********/
void ConfigureHlsIP(XImgprocess_top *ImgProcess)
{
	ImgProcess->Control_bus_BaseAddress = XPAR_IMGPROCESS_TOP_0_S_AXI_CONTROL_BUS_BASEADDR;
	ImgProcess->IsReady = XIL_COMPONENT_IS_READY;

	XImgprocess_top_EnableAutoRestart(ImgProcess);
	XImgprocess_top_SetRows(ImgProcess, 480);
	XImgprocess_top_SetCols(ImgProcess,640);

	XImgprocess_top_InterruptDisable(ImgProcess, 0xFFFFFFFF);
	XImgprocess_top_InterruptGlobalDisable(ImgProcess);
	XImgprocess_top_Start(ImgProcess);
}

int main()
{
    init_platform();
	usleep(100000);
    print("Hello World\n\r");
    ConfigureHlsIP(&ImgProcess);
	// MM2S
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x00, 0x008B);		// enable run, circular_park, GenlockEn, GenlockSrc
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x5C, 0x01000000);	// Start address of the 1st frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x60, 0x02000000);	// Start address of the 2nd frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x64, 0x03000000);	// Start address of the 3rd frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x58, 0x0780);		// Stride number
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x54, 0x0780);		// number of bytes per line(640 x 3)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x50, 0x01E0);		// number of lines per frame(480)

	//S2MM
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x30, 0x108B);		// enable run, circular_park
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xAC, 0x01000000);	// Start address of the 1st frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xB0, 0x02000000);	// Start address of the 2nd frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xB4, 0x03000000);	// Start address of the 3rd frame(3 frames in all)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA8, 0x0780);		// Stride number
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA4, 0x0780);		// number of bytes per line(640 x 3)
	Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA0, 0x01E0);		// number of lines per frame(480)

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 14:56:24

HLS图像处理系列——在ZEDBoard搭建DDR图像处理通路的相关文章

javacpp-opencv图像处理系列:国内车辆牌照检测识别系统(万份测试车牌识别准确率99.7%以上,单次平均耗时39ms)

javaCV图像处理系列: 一.javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体.位置.大小.粗度.翻转.平滑等操作 二.javaCV图像处理之2:实时视频添加图片水印,实现不同大小图片叠加,图像透明度控制 三.opencv图像处理3:使用opencv原生方法遍历摄像头设备及调用(方便多摄像头遍历及调用,相比javacv更快的摄像头读取速度和效率,方便读取后的图像处理) 四.opencv图像处理系列:国内车辆牌照检测识别系统(万份测试准确率99.7%以上

Matlab图像处理系列1———线性变换和直方图均衡

注:本系列来自于图像处理课程实验,用Matlab实现最基本的图像处理算法 图像点处理是图像处理系列的基础,主要用于让我们熟悉Matlab图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操作,直方图是对像素灰度值的统计,直方图均衡是对灰度值分布的变换. 1.灰度线性变换 (1)线性变换函数 原图向灰度值为g,通过线性函数f(x)=kx+b转换为f(g)得到灰度的线性变换. (2)代码实现 Matlab中支持矩阵作为函数参数传入,定义一个线性转换函数,利用Matlab矩阵操作,用一行代

android 图像处理系列合集

为了便于大家对滤镜算法的学习,以后发布的图像处理滤镜系列帖子会在这里汇总,本人第一次写合集,写得不好的地方大家请见谅,手头上虽然有一些滤镜的算法,但是大多不是android版的,教程里的代码大多是我借鉴其他语言的算法转换而成的,效率上还存在优化的空间,大家可以自行优化.有些网友说代码能看懂,但是里面的某些数值不知道是怎么计算出来的,说实话有些数值我不查资料我也不是很清楚,但是当我需要知道的时候我也会慢慢查阅算法的核心思想,很多参数由此而来.同时也希望大家养成不懂就查的习惯. android 图像

Matlab图像处理系列2———空间域平滑滤波器

注:本系列来自于图像处理课程实验,用Matlab实现最基本的图像处理算法 本文章是Matlab图像处理系列的第二篇文章,介绍了空间域图像处理最基本的概念----模版和滤波器,给出了均值滤波起和中值滤波器的Matlab实现,最后简要讨论去躁效果. 1.空间域增强 (1)模版运算 图像处理中,模版可以看作是n*n(n一般是奇数)的窗口,模版连续地运动于整个图像中,对模版窗口范围内的像素做相应处理. 模版运算主要分为: 模版卷积 模版排序 模版卷积是把模版内像素的灰度值和模版中对应的灰度值相乘,求平均

android图像处理系列之七--图片涂鸦,水印-图片叠加

图片涂鸦和水印其实是一个功能,实现的方式是一样的,就是一张大图片和一张小点图片叠加即可.前面在android图像处理系列之六--给图片添加边框(下)-图片叠加中也讲到了图片叠加,里面实现的原理是直接操作像素点.下面给出别外一种方式让图片叠加--用Canvas处理图片,canvas已经封装好了,直接调用就行. 下面看效果: += 代码: [java] view plain copy /** * 组合涂鸦图片和源图片 * @param src 源图片 * @param watermark 涂鸦图片

C#中基于GDI+(Graphics)图像处理系列之前言

前言 图像处理工具类的全部源码 完整示例程序源码下载 示例程序截图 前言 图像处理是开发工程师们学习某种语言入门时就会遇到的问题,笔者刚开始接触C#使用GDI+进行图像处理,觉得太简单了,就没有深入研究,随着工作经验的积累,踏遍若干坑以后突然觉得还是有必要将这块的知识好好总结一下,毕竟还是有一些比较冷门的知识在实际应用中给我们的程序带来更多的灵活性,比如将图片保存成jpeg时进一步控制图片的质量.怎样获取任意角度旋转后的图像.怎样获取透明图像等等. 本文后面将直接放出图像处理工具类的全部源码和示

图像处理系列(1):测地线动态轮廓(geodesic active contour)

动态轮廓是图像分割的一个热点,从早期的snake,就有很多的优化版,测地线动态轮廓(GAC)就是其中之一.总体来说,其摒弃了snake对参数的依赖,并加入了水平集,使得轮廓曲线更贴近目标物的拓扑结构. 经典的动态轮廓模型(activecontour model)的能量公式为: (1) 其中,α,β,λ为正值常量.其中前两项控制曲线的平滑度,第三项吸引曲线向物体边界靠近.极小化该E(C)能量函数得到分割轮廓.VICENT(参考1)指出第二项有无对分割结果影响不大(即β=0).而最大化第三项,也是最

android图像处理系列之三--图片色调饱和度、色相、亮度处理

原图: 处理后: 下面贴代码: 一.图片处理层: [java] view plaincopy package com.jacp.tone.view; import java.util.ArrayList; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android

android图像处理系列之五--给图片添加边框(中)

前面一篇讲到给图片加边框的方式,只能给图片加一些有规则的边框,如果想加一些比较精美的效果,就有点麻烦了.下面就给出解决这个问题的思路. 思路是:一些比较精美的花边图片我们是很难用代码控制,就目前本人水平是达不到,不排除牛人,再说了PS那些效果都是程序员做出来,肯定有实现的方法,这可能就要涉及很复杂的图形学.扯远了,接来说怎么用那些精美的花边做为图片的边框.简单的方式是用两张图片叠加.最简单的一种是本文介绍的,用透明的PNG格式图片.因为Android是支持PNG图片处理的,而且PNG图片有透明度