0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用HLS封装的缩放IP来实现视频图像缩放功能

Hack电子 来源:米联客uisrc 作者:米联客uisrc 2022-10-11 14:21 次阅读

1.1 概述

这里向大家介绍使用HLS封装的缩放IP来实现视频图像缩放功能。将HLS封装的缩放IP加入到OV5640图像传输系统,验证图像放大和缩小功能。

测试使用模块:OV5640摄像头,LCD (RGB接口) 屏、ZYNQ FPGA开发板。

放大测试:将720P分辨率图像放大到1080P。

放大测试:将640x480分辨率图像放大到1024x600

缩小测试:将720P分辨率图像缩小到640x480。

实现的缩放IP主要用于功能验证,可以在此基础上,对数据流进行进一步处理,这里不在赘述。

1.2 缩放IP算法介绍

此部分主要介绍实现缩放的两种算法,最近邻插值法和双线性插值法。其中最近邻插值法简单易懂,但是误差较大。在最近邻插值法的基础上,引出双线性插值法,也就是此次设计的目标算法。

1.2.1 最邻近插值法

图像的缩放很好理解,就是图像的放大和缩小。传统的绘画工具中,有一种叫做“放大尺”的绘画工具,画家常用它来放大图画。当然,在计算机上,我们不再需要用放大尺去放大或缩小图像了,把这个工作交给程序来完成就可以了。下面就来讲讲计算机怎么来放大缩小图像。在本文中,我们所说的图像都是指点阵图,也就是用一个像素矩阵来描述图像的方法,对于另一种图像:用函数来描述图像的矢量图,不在本文讨论之列。

越是简单的模型越适合用来举例子,我们就举个简单的图像:3X3 的256级灰度图,也就是高为3个像素,宽也是3个像素的图像,每个像素的取值可以是 0-255,代表该像素的亮度,255代表最亮,也就是白色,0代表最暗,即黑色。假如图像的像素矩阵如下所示(这个原始图把它叫做源图,Source):

234 38 22

67 44 12

89 65 63

这个矩阵中,元素坐标(x,y)是这样确定的,x从左到右,从0开始,y从上到下,也是从零开始,这是图象处理中最常用的坐标系,就是这样一个坐标:

ab40c2d8-4922-11ed-a3b6-dac502259ad0.jpg

如果想把这副图放大为 4X4大小的图像,那么该怎么做呢?那么第一步肯定想到的是先把4X4的矩阵先画出来再说,好了矩阵画出来了,如下所示,当然,矩阵的每个像素都是未知数,等待着我们去填充(这个将要被填充的图的叫做目标图,Destination):

? ? ? ?

? ? ? ?

? ? ? ?

? ? ? ?

然后要往这个空的矩阵里面填值了,要填的值从哪里来呢?是从源图中来!好,先填写目标图最左上角的像素,坐标为(0,0),那么该坐标对应源图中的坐标可以由如下公式得出:

srcX=dstX* (srcWidth/dstWidth) , srcY = dstY * (srcHeight/dstHeight)

其中srcWidth为输入图像宽度,srcHeight为输入图像高度,dstWidth输出图像宽度,dstHeight为输出图像高度,srcX 、srcY为输入图像坐标值,dstX、dstY为输出图像坐标值。

现在到这里很清楚了,直接套用公式,就可以找到对应的原图的坐标了(0*(3/4),0*(3/4))=>(0*0.75,0*0.75)=>(0,0)

找到了源图的对应坐标,就可以把源图中坐标为(0,0)处的234像素值填到目标图的(0,0)这个位置了。

接下来,如法炮制,寻找目标图中坐标为(1,0)的像素对应源图中的坐标,套用公式:

(1*0.75,0*0.75)=>(0.75,0)

结果发现,得到的坐标里面竟然有小数,这可怎么办?计算机里的图像可是数字图像,像素就是最小单位了,像素的坐标都是整数,从来没有小数坐标。这时候采用的一种策略就是采用四舍五入的方法(也可以采用直接舍掉小数位的方法),把非整数坐标转换成整数,好,那么按照四舍五入的方法就得到坐标(1,0),完整的运算过程就是这样的:

(1*0.75,0*0.75)=>(0.75,0)=>(1,0)

那么就可以再填一个像素到目标矩阵中了,同样是把源图中坐标为(1,0)处的像素值38填入目标图中的坐标。

依次填完每个像素,一幅放大后的图像就诞生了,像素矩阵如下所示:

234 38 22 22

67 44 12 12

89 65 63 63

89 65 63 63

这种放大图像的方法叫做最近邻插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真。效果不好的根源就是其简单的最临近插值方法引入了严重的图像失真,比如,当由目标图的坐标反推得到的源图的的坐标是一个浮点数的时候,采用了四舍五入的方法,直接采用了和这个浮点数最接近的像素的值,这种方法是很不科学的,当推得坐标值为 0.75的时候,不应该就简单的取为1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目标像素值其实应该根据这个源图中虚拟的点四周的四个真实的点来按照一定的规律计算出来的,这样才能达到更好的缩放效果。双线性插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多。

1.2.2 双线性插值法

已知的红色数据点与待插值得到的绿色点。

ab674700-4922-11ed-a3b6-dac502259ad0.jpg

假如我们想得到未知函数f在点P= (x,y) 的值,假设我们已知函数f在Q11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四个点的值。

首先在x方向进行线性插值,得到R1和R2,然后在y方向进行线性插值,得到P。

这样就得到所要的结果f(x,y)。

其中红色点Q11,Q12,Q21,Q22为已知的4个像素点.

第一步:X方向的线性插值,在Q12,Q22中插入蓝色点R2,Q11,Q21中插入蓝色点R1;

第二步:Y方向的线性插值,通过第一步计算出的R1与R2在y方向上插值计算出P点。

线性插值的结果与插值的顺序无关。首先进行y方向的插值,然后进行x方向的插值,所得到的结果是一样的。双线性插值的结果与先进行哪个方向的插值无关。

如果选择一个坐标系统使得四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为

f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy

具体的双线性插值算法描述如下:

对于一个目标像素,通过反向变换得到的浮点坐标为(i+u,j+v) (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:

f(i+uj+v) = (1-u)(1-v)f(ij) + (1-u)vf(ij+1) + u(1-v)f(i+1j) + uvf(i+1j+1)

其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。

比如,刚才的例子,现在假定目标图的像素坐标为(1,1),那么反推得到的对应于源图的坐标是(0.75 , 0.75), 这其实只是一个概念上的虚拟像素,实际在源图中并不存在这样一个像素,那么目标图的像素(1,1)的取值不能够由这个虚拟像素来决定,而只能由源图的这四个像素共同决定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)离(1,1)要更近一些,那么(1,1)所起的决定作用更大一些,这从公式1中的系数uv=0.75×0.75就可以体现出来,而(0.75,0.75)离(0,0)最远,所以(0,0)所起的决定作用就要小一些,公式中系数为(1-u)(1-v)=0.25×0.25也体现出了这一特点。

1.3 HLS实现1.3.1 工程创建

新建一个HLS工程,并在Source中新建Top.cpp、Top.h文件,在Test Bench中新建Test.cpp并添加测试图片test1.jpg。

ab7cfb40-4922-11ed-a3b6-dac502259ad0.jpg

Top.cpp源码(Source中添加):

#include "top.h"
#include 


void hls_video_scaler_top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,int drows, int dcols)
{
      #pragma HLS INTERFACE axis port=INPUT_STREAM
      #pragma HLS INTERFACE axis port=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=drows metadata="-bus_bundle CONTROL_BUS"
      #pragma HLS RESOURCE core=AXI_SLAVE variable=dcols metadata="-bus_bundle CONTROL_BUS"
      #pragma HLS RESOURCE core=AXI_SLAVE variable=return metadata="-bus_bundle CONTROL_BUS"


      #pragma HLS INTERFACE ap_stable register port=dcols
      #pragma HLS INTERFACE ap_stable register port=drows
      #pragma HLS INTERFACE ap_stable register port=rows
      #pragma HLS INTERFACE ap_stable register port=cols


      RGB_IMAGE img_0(rows, cols);
      RGB_IMAGE img_1(drows, dcols);


      #pragma HLS dataflow
      hls::AXIvideo2Mat(input,img_0);
      hls::Resize(img_0,img_1,HLS_INTER_LINEAR);
      hls::Mat2AXIvideo(img_1, output);
}
    

Top.h源码(Source中添加):

#ifndef _TOP_H_
#define _TOP_H_


#include "hls_video.h"


#include "ap_int.h"
// maximum image size
#define MAX_WIDTH  4096
#define MAX_HEIGHT 2160


typedef unsigned char uchar;
// I/O Image Settings
#define INPUT_IMAGE           "test1.jpg"


// typedef video library core structures
typedef hls::stream >               AXI_STREAM;
typedef hls::Mat     RGB_IMAGE;


void hls_video_scaler_top(AXI_STREAM& input, AXI_STREAM& output,int rows, int cols,int drows, int dcols);




#endif

Test.cpp源码(Test Bench中添加):

#include "top.h"
#include "hls_opencv.h"
#include "iostream"
#include 


using namespace std;
using namespace cv;


int main (int argc, char** argv)
{
      IplImage* src = cvLoadImage(INPUT_IMAGE);


      CvSize s;
      s.width = 1920;
      s.height = 1080;
      IplImage* dst = cvCreateImage(s, 8, 3);


      AXI_STREAM  src_axi, dst_axi;
      IplImage2AXIvideo(src, src_axi);
      hls_video_scaler_top(src_axi, dst_axi, src->height, src->width,s.height,s.width);


      AXIvideo2IplImage(dst_axi, dst);


      cvShowImage("src",src);
      cvShowImage("dst_hls",dst);
      waitKey(0);


      return 0;
}

测试图片test1.jpg(Test Bench中添加):双击打开图片,右击->属性->查看图片原始分辨率。

1.4.2 综合和仿真

1、综合报告如下:

ab934dbe-4922-11ed-a3b6-dac502259ad0.jpg

2、仿真测试如下:直接单击开始进行仿真。可以看到原始的图片和经过缩放的图片

1) 缩小的图片(分辨率420x264)

2) 原始图片(分辨率840x528)

3)放大后的图片(1920x1080)

从仿真结果可以看出,缩放后,图片虽然有拉长或变短,但是图像仍然比较清晰。

3、导出封装好的IP

导出供VIVADO使用的IP。

1.4 硬件工程创建1.4.1 硬件平台搭建

本章使用的硬件工程,在OV5640 VDMA图像传输的基础上进行修改。将HLS生成的IP添加工程中,将Video In to AXI4-Stream的输出接口与HLS IP的输入接口连接,HLS IP的输出接口与VDMA的AXIS接口连接。

ac1dc124-4922-11ed-a3b6-dac502259ad0.jpg

重新编译工程,并导入SDK。

1.4.2 SDK工程修改

#include"I2C_16bit.h"
#include"xiicps.h"
#include"xil_io.h"
#include"xparameters.h"
#include"xhls_video_scaler_top.h"

#defineXPAR_HLS_VIDEO_SCALER_TOP_DEVICE_ID XPAR_HLS_VIDEO_SCALER_TOP_0_DEVICE_ID
#defineVDMA_BASEADDR XPAR_AXI_VDMA_0_BASEADDR

#defineVIDEO_BASEADDR0 0x01000000
#defineVIDEO_BASEADDR1 0x02000000
#defineVIDEO_BASEADDR2 0x03000000
//VDMA分辨率设置
#defineH_ACTIVE 1280
#defineV_ACTIVE 720
#defineH_STRIDE 1280

XHls_video_scaler_top XHls_video_scaler;
XIicPs Iic;
// HLSIP初始化
voidXHls_video_scaler_initialize(void)
{
intstatus;

status=XHls_video_scaler_top_Initialize(&XHls_video_scaler, XPAR_HLS_VIDEO_SCALER_TOP_DEVICE_ID);
if(0!=status)
{
xil_printf("XPAR_HLS_VIDEO_SCALER FAILED ");
}
}
// HLS IP参数设置
voidXHls_video_scaler_setup(u16row,u16col,u16drow,u16dcol)
{
XHls_video_scaler_top_SetRows(&XHls_video_scaler,row);
XHls_video_scaler_top_SetCols(&XHls_video_scaler, col);
XHls_video_scaler_top_SetDrows(&XHls_video_scaler, drow);
XHls_video_scaler_top_SetDcols(&XHls_video_scaler, dcol);
XHls_video_scaler_top_InterruptGlobalDisable(&XHls_video_scaler);
XHls_video_scaler_top_EnableAutoRestart(&XHls_video_scaler);
XHls_video_scaler_top_Start(&XHls_video_scaler);

}

voidmain()
{
// Initialize OV5640regesiter
I2C_config_init();

//Initialize XHls_video_scalerIp
XHls_video_scaler_initialize();
//set input and output resolution ratio
XHls_video_scaler_setup(720,1280,1080,1920);

//Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode
Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode
Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0); // start address
Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1); // start address
Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2); // start address
Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*3)); // h offset (H_STRIDE* 3) bytes
Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*3)); // h size (H_ACTIVE * 3) bytes
Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE); // v size (V_ACTIVE)
/*****************从DDR读数据设置**********************/
Xil_Out32((VDMA_BASEADDR + 0x000), 0x8B); // enable circular mode
Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address
Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); // start address
Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2); // start address
Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*3)); // h offset (H_STRIDE * 3) bytes
Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*3)); // h size (H_ACTIVE * 3) bytes
Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); // v size (V_ACTIVE)

while(1) ;
}

这里需要注意,OV5640摄像头的分辨率是720P,VDMA视频流配置的分辨率也是720P。VDMA输出的视频流经过HLS 缩放IP后,调整了输出显示的分辨率。

XHls_video_scaler_initialize()和XHls_video_scaler_setup(720,1280,1080,1920)用于HLS IP初始化和参数设置。输入图像的分辨率是720P,输出图像显示的分辨率是1080P。

1.5 验证测试

使用OV5640摄像头拍摄同一副图片,对比直接输出图像和经过HLS缩放IP的图像。

1.5.1 放大测试

(1)720P分辨率图像输入,1080P分辨率图像输出,未使用HLS IP对输入进行缩放处理,效果如下。

可以看到图像显示仅占据一部分界面,这是因为输出分辨率大于输入分辨率。输入图像仅占据输出图像的一部分。

1)未经过HLS缩放IP处理

(2)720P分辨率图像输入,采集图像经过HLS IP处理放大到1080P输出。

可以看到经过HLS 缩放IP处理后的图像被放大,但是图像整理放大后画面仍然清晰。

2)经过HLS缩放IP放大处理后的图像

LCD屏放大测试

640X480分辨率输入,1024x600分辨率输出。可以看出经过放大后的图像可以在整个界面显示。

3)未经过HLS 缩放IP处理

4)经过HLS 缩放IP处理

1.5.2 缩小测试

拍摄同一视角,720P图像输入,640X480分辨率输出。使用缩放IP,显示完整的图像,而不适用缩放IP,图像仅部分显示,这是因为输入输出分辨率不一致,仅部分输出。缩小后的图像任然清晰。

5)未经过HLS 缩放IP处理

6)经过HLS 缩放IP处理

小结:

HLS 生成的缩放IP可以在一定程度上放大或缩小图像,并且不失真,但是同时与纯FPGA编写的代码实现,HLS消耗的资源也是需要考虑的一个重要问题。这里我们会在后面进行讨论。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 视频
    +关注

    关注

    6

    文章

    1891

    浏览量

    71903
  • IP
    IP
    +关注

    关注

    5

    文章

    1404

    浏览量

    148273
  • HLS
    HLS
    +关注

    关注

    1

    文章

    126

    浏览量

    23683

原文标题:基于HLS的视频缩放方案

文章出处:【微信号:Hack电子,微信公众号:Hack电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    通过HLS封装缩放IP实现视频图像缩放技术

    放大测试:将640x480分辨率图像放大到1024x600 缩小测试:将720P分辨率图像缩小到640x480。 实现缩放IP主要用于
    的头像 发表于 11-14 12:10 3822次阅读
    通过<b class='flag-5'>HLS</b><b class='flag-5'>封装</b>的<b class='flag-5'>缩放</b><b class='flag-5'>IP</b>来<b class='flag-5'>实现</b><b class='flag-5'>视频</b><b class='flag-5'>图像</b><b class='flag-5'>缩放</b>技术

    编程实现图像缩放

    通过matlab编程实现图像缩放
    发表于 05-14 20:45

    图像处理中的插值和缩放研究

    本文围绕图像处理领域中两类重要处理手法――图像插值与图像缩放技术展开了深入的研究.在分析目前现有的插值与缩放技术的基础上,就以下方面给出了研
    发表于 09-28 14:00 38次下载
    <b class='flag-5'>图像</b>处理中的插值和<b class='flag-5'>缩放</b>研究

    基于FPGA实现固定倍率的图像缩放

    基于FPGA硬件实现固定倍率的图像缩放,将2维卷积运算分解成2次1维卷积运算,对输入原始图像像素先进行行方向的卷积,再进行列方向的卷积,从而得到输出
    发表于 05-09 15:52 35次下载
    基于FPGA<b class='flag-5'>实现</b>固定倍率的<b class='flag-5'>图像</b><b class='flag-5'>缩放</b>

    FPGA实现视频图像缩放显示

    FPGA实现视频图像缩放显示,下来看看。
    发表于 08-29 15:02 29次下载

    基于双线性插值的图像缩放在GPU上的实现

    基于双线性插值的图像缩放在GPU上的实现
    发表于 01-08 14:47 0次下载

    采用多相位插值算法实现视频图像缩放及其在FPGA硬件平台的验证

    传统的插值算法在视频图像缩放尤其是输出高分辨率的视频图像时,对细节方面的处理性能较差。采用多相位插值算法
    发表于 11-16 11:48 4661次阅读
    采用多相位插值算法<b class='flag-5'>实现</b><b class='flag-5'>视频</b><b class='flag-5'>图像</b><b class='flag-5'>缩放</b>及其在FPGA硬件平台的验证

    一种新颖的图像缩放算法进行FPGA硬件实现

    本文选择了一种新颖的图像缩放算法进行FPGA硬件实现。该算法基于奇偶分解的思想,具有复杂度低、硬件需求小和缩放效果良好等突出优点。首先利用MATLAB对该算法进行了
    发表于 12-12 14:07 2次下载
    一种新颖的<b class='flag-5'>图像</b><b class='flag-5'>缩放</b>算法进行FPGA硬件<b class='flag-5'>实现</b>

    移动终端的视频图像定点与缩放系统

    针对在移动终端自由缩放查看视频细节的需求,提出移动终端的视频图像定点与缩放系统,包含手势识别与越界纠正技术,详细给出了系统框架和系统流程。手
    发表于 02-01 16:09 1次下载
    移动终端的<b class='flag-5'>视频</b><b class='flag-5'>图像</b>定点与<b class='flag-5'>缩放</b>系统

    如何利用FPGA硬件实现固定倍率的图像缩放

    近年来,FPGA技术发展迅速,片内集成了PLL、硬件乘法器、存储器,具有了实现优秀算法的充足资源。许多航空电子嵌入式图像处理系统是由固定的视频源和显示设备组成,系统中图像
    发表于 08-18 09:36 4242次阅读

    使用FPGA实现视频图像缩放显示的设计论文说明

    对几种常用的图像缩放算法进行了比较,在权衡了算法复杂度、缩放效果和FPGA 逻辑资源等3大因素后,选择了双线性插值算法来实现图像
    发表于 01-25 14:51 6次下载
    使用FPGA<b class='flag-5'>实现</b><b class='flag-5'>视频</b><b class='flag-5'>图像</b><b class='flag-5'>缩放</b>显示的设计论文说明

    如何使用FPGA实现高分辨实时监控图像缩放的设计

    介绍了一种基于图像的双三次线性插值缩放算法的设计方法,并通过FPGA验证了设计的可行性。重点讨论了视频缩放的插值算法,对两种实现方法在硬件资
    发表于 02-05 15:54 7次下载

    如何使用FPGA实现数字X线图像的实时缩放模块

    本文介绍了一个自行设计的数字化x射线影像实时处理系统中实现图像实时缩放的子系统。重点分析了缩放涉及的插值算法,设计并实现了基于FPGA的三次
    发表于 03-18 16:39 4次下载
    如何使用FPGA<b class='flag-5'>实现</b>数字X线<b class='flag-5'>图像</b>的实时<b class='flag-5'>缩放</b>模块

    如何使用FPGA实现图像缩放算法的研究设计

    和scaler在FPD中工作过程的基础上,采用自上而下(Top.down)的设计方法,给出了scaler的设计及FPGA验证。该scaler支持不同分辨率图像缩放,且缩放模式可调,也可以以I
    发表于 04-02 11:01 29次下载
    如何使用FPGA<b class='flag-5'>实现</b><b class='flag-5'>图像</b><b class='flag-5'>缩放</b>算法的研究设计

    赛灵思FFT IP中的缩放因子说明

    赛灵思 Fast Fourier Transform (FFT) IP 具有专用于处理 FFT 输出中的位增长的缩放因子。本文旨在提供有关此 IP 中可用缩放方法的见解,并提供
    的头像 发表于 07-20 11:17 3823次阅读