我正在尝试使用 Vivado HLS 为硬件的色域映射过滤器实现图像处理算法。我从卤化物代码创建了一个可合成的版本。但是对于(256x512)的图像来说,它花费了大约 135 秒,这不应该是这种情况。我使用了一些优化技术,例如对最内层循环进行流水线化处理,通过流水线化,我为最内层循环设置了 II=1 的目标(启动间隔),但实现的 II 为 6。从编译器抛出的警告中,我明白了这是因为访问ctrl_pts 和 weights之类的权重,从教程中,我已经看到,使用数组分区和数组重塑将有助于更快地访问权重。我在下面分享了我用来合成的代码:
//header
include "hls_stream.h"
#include <ap_fixed.h>
//#include <ap_int.h>
#include "ap_int.h"
typedef ap_ufixed<24,24> bit_24;
typedef ap_fixed<11,8> fix;
typedef unsigned char uc;
typedef ap_uint<24> stream_width;
//typedef hls::stream<uc> Stream_t;
typedef hls::stream<stream_width> Stream_t;
struct pixel_f
{
float r;
float g;
float b;
};
struct pixel_8
{
uc r;
uc g;
uc b;
};
void gamut_transform(int rows,int cols,Stream_t& in,Stream_t& out, float ctrl_pts[3702][3],float weights[3702][3],float coefs[4][3],float num_ctrl_pts);
//core
//include the header
#include "gamut_header.h"
#include "hls_math.h"
void gamut_transform(int rows,int cols, Stream_t& in,Stream_t& out, float ctrl_pts[3702][3],float weights[3702][3],float coefs[4][3],float num_ctrl_pts)
{
#pragma HLS INTERFACE axis port=in
#pragma HLS INTERFACE axis port=out
//#pragma HLS INTERFACE fifo port=out
#pragma HLS dataflow
pixel_8 input;
pixel_8 new_pix;
bit_24 temp_in,temp_out;
pixel_f buff_1,buff_2,buff_3,buff_4,buff_5;
float dist;
for (int i = 0; i < 256; i++)
{
for (int j = 0; i < 512; i++)
{
temp_in = in.read();
input.r = (temp_in & 0xFF0000)>>16;
input.g = (temp_in & 0x00FF00)>>8;
input.b = (temp_in & 0x0000FF);
buff_1.r = ((float)input.r)/256.0;
buff_1.g = ((float)input.g)/256.0;
buff_1.b = ((float)input.b)/256.0;
for(int idx =0; idx < 3702; idx++)
{
buff_2.r = buff_1.r - ctrl_pts[idx][0];
buff_2.g = buff_1.g - ctrl_pts[idx][1];
buff_2.b = buff_1.b - ctrl_pts[idx][2];
dist = sqrt((buff_2.r*buff_2.r)+(buff_2.g*buff_2.g)+(buff_2.b*buff_2.b));
buff_3.r = buff_2.r + (weights[idx][0] * dist);
buff_3.g = buff_2.g + (weights[idx][1] * dist);
buff_3.b = buff_2.b + (weights[idx][2] * dist);
}
buff_4.r = buff_3.r + coefs[0][0] + buff_1.r* coefs[1][0] + buff_1.g * coefs[2][0] + buff_1.b* coefs[3][0];
buff_4.g = buff_3.g + coefs[0][1] + buff_1.r* coefs[1][1] + buff_1.g * coefs[2][1] + buff_1.b* coefs[3][1];
buff_4.b = buff_3.b + coefs[0][2] + buff_1.r* coefs[1][2] + buff_1.g * coefs[2][2] + buff_1.b* coefs[3][2];
buff_5.r = fmin(fmax((float)buff_4.r, 0.0), 255.0);
buff_5.g = fmin(fmax((float)buff_4.g, 0.0), 255.0);
buff_5.b = fmin(fmax((float)buff_4.b, 0.0), 255.0);
new_pix.r = (uc)buff_4.r;
new_pix.g = (uc)buff_4.g;
new_pix.b = (uc)buff_4.b;
temp_out = ((uc)new_pix.r << 16 | (uc)new_pix.g << 8 | (uc)new_pix.b);
out<<temp_out;
}
}
}
即使达到了 II=6,所花费的时间也只有 6 秒左右;给定的目标是以毫秒为单位的时间。我试图为第二个最内层循环进行流水线处理,但是当我这样做时,我的板上的资源已经用完了,因为第三个最内层循环正在展开。我正在使用具有相当数量资源的 zynq 超大规模板。任何有关优化代码的建议都将受到高度赞赏。
此外,任何人都可以建议哪种类型的接口最适合ctrl_pts、weights 和 coefs,为了阅读图像,我理解流接口有帮助,以及为了读取像行数和列数这样的小值,首选 Axi lite?是否有一种接口可以用于上述变量,以便它可以与数组分区和数组重塑齐头并进?
任何建议将不胜感激,
提前致谢
编辑:我知道定点表示可以进一步降低延迟,但我的第一个目标是获得具有最佳结果的浮点表示,然后使用定点表示分析性能