【HLS】图像旋转实现

接上篇文章,接着更新,本次任务是使用HLS实现图像旋转功能:
设计任务

模块实现

图像旋转

对于输入图像坐标(X0,Y0),顺时针旋转角度a后坐标计算公式如下图所示。显然,旋转后的图像尺寸会变大。
图像旋转坐标计算公式
在本次实验中,先预设好输出图像大小,将输入图像与输出图像的像素中心点设为坐标原点。对输出图像进行遍历,计算出输入图像对应的坐标点,如果该坐标值属于输入图像范围内,则取输入图像该点周围的四个像素点的值进行计算得到输出像素值。

模块综合结果——实现1

第一种实现方法在每一次输出计算中通过AXI接口依次访问所需的四个像素点(假设图像数据存储在片外存储器)。综合结果如下图。
模块综合结果1
可以看到在最内层循环中无法达到II=1,这是因为需要同时取出4个数进行运算,而接口无法同时对4个地址进行访存读取。

模块综合结果——实现2

因为在本次实验任务中,输入图像的尺寸为64×64,即使将其全部读入也不会使用过多的资源。因此,可以先将图像全部读入缓存,在进行图像旋转计算。而且在将顶层接口设置为AXI4-Master总线时,这种连续读入操作可以通过总线的连续突发等特性大大减少读入周期。
读入图像
综合结果如下图。
模块综合结果2可以看到,实现2方案可以实现II=1,模块整体Latency也大幅下降,但是BRAM资源的使用提升明显,这就是典型的空间换时间。
当然这里只是举例了两种最简单的实现方法,实际上也可以通过一些缓存设计方法达到II=1且片内存储占用较少的设计目的。

模块优化

在本实验中,HLS编译器自动对模块的流水、存储进行了优化或展开,并没有添加除接口指定以外的优化指令。
接口优化指令

模块仿真实现

测试图像

打开画图随便画一个64×64的箭头图像作为测试图像。
测试图像

仿真结果

与上一次图像平滑实验类似,使用opencv库编写测试激励。经过仿真,上述两种实现方式仿真结果一致。
旋转15度图像
旋转45度图像

联合仿真波形——实现1

联合仿真波形——实现1
如上图,红框中分别是一次图像旋转函数的执行过程,读写通道同时进行。

联合仿真波形——实现2

联合仿真波形——实现2
如上图,红框中分别是一次图像旋转函数的执行过程,可以看到读通道先执行了输入图像的读入流程,随后过了一段时间,写通道开始输出结果。

对比

对比实现1与实现2的联合仿真结果,实现2所用时间仅为实现1的三分之一,对于64*64的图像输入情况,实现2方法有着更小小的处理延时。

实现代码

HLS实现

下面是实现1方法的代码,实现2只需要稍作修改即可。

#include "rotate.h"

const ap_int<8> img_row = 96;
const ap_int<8> img_col = 96;
const ap_int<8> img_m = img_row >> 1;
const ap_int<8> img_n = img_col >> 1;
const ap_int<8> img_size = 64;
const ap_int<8> img_size2 = 32;

void Rotate(ap_uint<8> *img_in, ap_uint<8> *img_out, ap_fixed<16, 4> rad)
{
	#pragma HLS INTERFACE mode=m_axi depth=4096 port=img_in
	#pragma HLS INTERFACE mode=m_axi depth=9216 port=img_out

//	ap_uint<8> img_buf[4096];
	ap_fixed<8, 2> sina, cosa;
	ap_fixed<16, 8, AP_RND, AP_SAT> xr, yr;
	ap_int<8> xrr, yrr;
	sina = hls::sin(rad);
	cosa = hls::cos(rad);

//	memcpy(img_buf, img_in, 4096);

	for(ap_int<8> i = -img_m; i < img_m; i++)
	{
		for(ap_int<8> j = -img_n; j < img_n; j++)
		{
			xr = cosa * j + sina * i + img_size2;
			yr = cosa * i - sina * j + img_size2;
			if(xr >= 0 && xr < img_size && yr >= 0 && yr < img_size)
			{
				xrr = xr.to_ap_int();
				yrr = yr.to_ap_int();
				ap_uint<8> idx1 = img_in[yrr * img_size + xrr];
				ap_uint<8> idx2 = img_in[yrr * img_size + xrr + 1];
				ap_uint<8> idx3 = img_in[yrr * img_size + xrr + img_size];
				ap_uint<8> idx4 = img_in[yrr * img_size + xrr + img_size + 1];
				img_out[(i + img_m) * img_col + j + img_n] = (idx1 >> 2) + (idx2 >> 2) + (idx3 >> 2) + (idx4 >> 2);
			}
		}
	}
}

仿真实现

#include "rotate.h"
#include "opencv2/opencv.hpp"

int main(void)
{
	cv::Mat input = cv::imread("in.bmp", 0);
	cv::Mat output15 = cv::Mat::zeros(96, 96, CV_8U);
	cv::Mat output45 = cv::Mat::zeros(96, 96, CV_8U);

	ap_fixed<16, 4> rad15 = 0.2618;//(15/180)*pi
	ap_fixed<16, 4> rad45 = 0.7854;//(45/180)*pi

	Rotate((ap_uint<8> *)input.data, (ap_uint<8> *)output15.data, rad15);
	Rotate((ap_uint<8> *)input.data, (ap_uint<8> *)output45.data, rad45);

	cv::imwrite("out15.jpg", output15);
	cv::imwrite("out45.jpg", output45);

	return 0;
}

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值