目录
- 一、三种图像缩放算法介绍
- 线性插值
- 双线性插值
- 双三次插值
- 二、HLS实现线性插值图像缩放
- 三、HLS实现双线性插值图像缩放
- 四、HLS实现双三次插值图像缩放
- 五、HLS在线仿真并导出IP
- 六、其他FPGA型号HLS在线仿真并导出IP
- 七、zynq7100开发板vivado工程
- 八、上板调试验证
- 九、福利:工程源码获取
一、三种图像缩放算法介绍
线性插值
线性插值是针对一维数据的插值方法。它根据一维数据序列中需要插值的点的左右临近两个数据来进行数值估计。当然了它不是求这两个点数据大小的平均值(在中心点的时候就等于平均值)。而是根据到这两个点的距离来分配比重的。
已知点(x0,y0)、(x1,y1)求取插值点x处的y.推导过程如下:
由于( y-y0)/(x-x0)=(y1-y0)/(x1-x0)
所以变换一下:(x-x0)/(x1-x0)=(y-y0)/(y1-y0)=k
那么:y=(1-k)y0+ky1
比较方便记忆
双线性插值
在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值(即从X方向进行两次线性插值,得到R1、R2,再对Y方向进行一次线性插值,就可以得到P)。见下图:
假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。最常见的情况,f就是一个像素点的像素值。首先在 x 方向进行线性插值,得到
然后在 y 方向进行线性插值,得到
综合起来就是双线性插值最后的结果:
双三次插值
双三次插值,英文是Bicubic interpolation。双三次插值是一种更加复杂的插值方式,它能创造出比双线性插值更平滑的图像边缘。双三次插值方法通常运用在一部分图像处理软件、打印机驱动程序和数码相机中,对原图像或原图像的某些区域进行放大。Adobe Photoshop CS 更为用户提供了两种不同的双三次插值方法:双三次插值平滑化和双三次插值锐化。
在数值分析这个数学分支中,双三次插值(英语:Bicubic interpolation)是二维空间中最常用的插值方法。在这种方法中,函数f在点 (x,y) 的值可以通过矩形网格中最近的十六个采样点的加权平均得到,在这里需要使用两个多项式插值三次函数,每个方向使用一个。
双三次插值又叫双立方插值,用于在图像中“插值”(Interpolating)或增加“像素”(Pixel)数量/密度的一种方法。通常利用插值技术增加图形数据,以便在它打印或其他形式输出的时候,能够增大打印面积以及(或者)分辨率。
目前有不同的插值技术可供选用。双立方插值通常能产生效果最好,最精确的插补图形,但它速度也几乎是最慢的。“双线性插值”(Bilinear interpolation)的速度则要快一些,但没有前者精确。在商业性图像编辑软件中,经常采用的是速度最快,但也是最不准确的“最近相邻”(Nearest Neighbor)插值。其他一些插值技术通常只在高档或单独应用的程序中出现。
通过双三次插值可以得到一个连续的插值函数,它的一阶偏导数连续,并且交叉导数处处连续。
如上图所示,我们在新生成的图像中,像素点是f(x,y),先映射到源图像中的坐标为f(i+u,j+v)需要找到对应的原图像中离最近的16个点。
和前面介绍的双线性插值的分析方法类似(http://blog.chinaaet.com/justlxy/p/5100052604),我们可以分别对行和列进行依次处理。则有,
则有,
而s(*)表示的则是权值,有多种计算方法(模型),常用的有Bicubic、Mitchell和Lanczos等,这里简单介绍一下Bicubic函数:
该函数,波形如下图所示:
Lanczos函数为:
波形也是类似的:
二、HLS实现线性插值图像缩放
在前面的详细介绍了三种图像缩放算法,看起来很复杂很NB对吧?
然并卵!!!!!!!
然并卵!!!!!!!
然并卵!!!!!!!
因为对于HLS来说,干这活儿只需要一句话一行代码即可实现;
因为Xilinx早就帮你做好了三种图像缩放算法的库,并且可以综合,既然如此,我还需要去管他怎么实现的,算法公式是怎样的吗?这就是HLS的NB之处。。。
线性插值图像缩放HLS工程如下:
线性插值图像缩放综合后的延时、资源占用等性能参数如下:
头文件如下:
#ifndef _HELAI_HLS_RESIZE_H_
#define _HELAI_HLS_RESIZE_H_
#include "hls_video.h"
#define MAX_HEIGHT 1080 //图像最大高度
#define MAX_WIDTH 1920 //图像最大宽度
#define INPUT_IMAGE "luoli.jpg"
#define OUTPUT_IMAGE "luoli_out.jpg"
typedef hls::stream<ap_axiu<24,1,1,1> > AXI_STREAM;
typedef hls::Mat<MAX_HEIGHT,MAX_WIDTH,HLS_8UC3> RGB_IMAGE;
void helai_hls_resize(AXI_STREAM&INPUT_STREAM,AXI_STREAM&OUTPUT_STREAM,int s_rows,int s_cols,int t_rows,int t_cols);
#endif
源文件的核心代码如下:三种算法共用一个工程,用注释选择使用哪一种
这里选择线性插值:
hls::Resize_opr_linear(img_0,img_1); //线性插值
//hls::Resize(img_0,img_1,HLS_INTER_LINEAR); //双线性插值
//hls::Resize_opr_bicubic(img_0,img_1); //双三次插值
核心代码就一句话,BN吧?呵呵。。。。。。
三、HLS实现双线性插值图像缩放
双线性插值图像缩放综合后的延时、资源占用等性能参数如下:
源文件的核心代码如下:三种算法共用一个工程,用注释选择使用哪一种
这里选择双线性插值:
//hls::Resize_opr_linear(img_0,img_1); //线性插值
hls::Resize(img_0,img_1,HLS_INTER_LINEAR); //双线性插值
//hls::Resize_opr_bicubic(img_0,img_1); //双三次插值
核心代码就一句话,BN吧?呵呵。。。。。。
四、HLS实现双三次插值图像缩放
双三次插值图像缩放综合后的延时、资源占用等性能参数如下:
源文件的核心代码如下:三种算法共用一个工程,用注释选择使用哪一种
这里选择双三次插值:
//hls::Resize_opr_linear(img_0,img_1); //线性插值
//hls::Resize(img_0,img_1,HLS_INTER_LINEAR); //双线性插值
hls::Resize_opr_bicubic(img_0,img_1); //双三次插值
核心代码就一句话,BN吧?呵呵。。。。。。
五、HLS在线仿真并导出IP
线性插值原图缩小到320X320的HLS在线仿真结果如下:
线性插值原图放大到800X800的HLS在线仿真结果如下:
双线性插值原图缩小到320X320的HLS在线仿真结果如下:
双线性插值原图放大到800X800的HLS在线仿真结果如下:
双三次插值原图缩小到320X320的HLS在线仿真结果如下:
双三次插值原图放大到800X800的HLS在线仿真结果如下:
从仿真效果来看,三种图像缩放算法效果貌似一样,看不出有啥区别。。。。或许我外行了
六、其他FPGA型号HLS在线仿真并导出IP
HLS工程的FPGA型号选的是zynq7100,可在zynq系列上用,若需要在其他FPGA型号上运行,则仅需修改FPGA型号,然后重新综合导出IP即可,HLS工程需修改FPGA型号方法如下:
综合如下:
导出IP如下:
生成的IP位置如下:
在我提供的网盘资料中,已经包好了zynq7100的HLS工程,生成的IP对于zynq系列FPGA都适用;
七、zynq7100开发板vivado工程
开发板:Xilinx zynq7100开发板;
开发环境:HLS2019.1;vivado2019.1;
输入:OV5640摄像头,输入分辨率1280x720;
输出1:1280x720输入,1920x1080分辨率HDMI输出;
输出2:1280x720输入,放大到1920x1080分辨率HDMI输出;
输出3:1280x720输入,缩小到640x480分辨率HDMI输出;
本例程使用的是双线性插值算法的IP,需要使用其他算法IP的兄弟,需自行将HLS工程改下,选择需要的算法,然后综合导出IP;
工程BD如下:
生成顶层RTL如下:
SDK主函数源码如下:
#include "I2C_16bit.h"
#include "xiicps.h"
#include "xil_io.h"
#include "xparameters.h"
#include "helai_vdma.h"
#include "helai_hls_resize.h"
void main()
{
// Initialize OV5640 regesiter
I2C_config_init();
helai_hls_resize(720,1280,1080,1920); //放大到1920x1080
//helai_hls_resize(720,1280,480,640); //缩小到640x480
helai_vdma();
while (1) ;
}
放大或者缩小,直接由helai_hls_resize()函数灵活配置即可,所以这里的放大和缩小共用一个工程即可;
八、上板调试验证
zynq开发板实物连接如下:
下载程序后的演示:
输出1:1280x720输入,1920x1080分辨率HDMI输出如下原图大小:
输出2:1280x720输入,放大到1920x1080分辨率HDMI输出;
输出3:1280x720输入,缩小到640x480分辨率HDMI输出;
九、福利:工程源码获取
福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料如下:获取方式:私。
网盘资料如下: