在vivado_hls中发送浮点数的问题



我正在尝试做一个简单的图像处理过滤器,其中像素值将除以一半以减少强度,我正在尝试开发相同的硬件。因此,我使用vivado hls生成IP。如本文https://forums.xilinx.com/t5/High-Level-Synthesis-HLS/Float-numbers-with-hls-stream/m-p/942747所述,要在hls流中发送浮点数,需要使用union,我也这样做了。然而,结果似乎与图像的红色和绿色成分不匹配,而与图像的蓝色成分匹配。这是一个非常简单的算法,将像素值除以一半。

我一直在努力解决它,但我不能看到问题在哪里。我附上了下面所有的文件,有人可以帮我解决吗??

////header file
#include "ap_fixed.h"
#include "hls_stream.h"
typedef union {
unsigned int i;
float r;
float g;
float b;
} conv;
typedef hls::stream <unsigned int> Stream_t;
void ftest(Stream_t& Sin,Stream_t& Sout);

////testbench
#include "stream_check_h.hpp"

int main()
{
Mat img_rev = imread("C:/Users/20181217/Desktop/images/imgs/output_fwd_v3.png");//(256x512)
Mat final_img(img_rev.rows,img_rev.cols,CV_8UC3);
Mat ref_img(img_rev.rows,img_rev.cols,CV_8UC3);
Stream_t S1,S2;
int err_r = 0;
int err_g = 0;
int err_b = 0;
for(int i=0;i<256;i++)
{
for(int j=0;j<512;j++)
{
conv c;
c.r = (float)img_rev.at<Vec3b>(i,j)[0];
c.g = (float)img_rev.at<Vec3b>(i,j)[1];
c.b = (float)img_rev.at<Vec3b>(i,j)[2];
S1 << c.i;
}
}

ftest(S1,S2);
conv c;
for(int i=0;i<256;i++)
{
for(int j=0;j<512;j++)
{
S2 >> c.i;
final_img.at<Vec3b>(i,j)[0]=(unsigned char)c.r;
final_img.at<Vec3b>(i,j)[1]=(unsigned char)c.g;
final_img.at<Vec3b>(i,j)[2]=(unsigned char)c.b;
ref_img.at<Vec3b>(i,j)[0] = (unsigned char)(((float)img_rev.at<Vec3b>(i,j)[0])/2.0);
ref_img.at<Vec3b>(i,j)[1] = (unsigned char)(((float)img_rev.at<Vec3b>(i,j)[1])/2.0);
ref_img.at<Vec3b>(i,j)[2] = (unsigned char)(((float)img_rev.at<Vec3b>(i,j)[2])/2.0);
}
}
Mat diff;
cout<<diff;
diff= abs(final_img-ref_img);
for(int i=0;i<256;i++)
{
for(int j=0;j<512;j++)
{
if((int)diff.at<Vec3b>(i,j)[0] > 0)
{
err_r++;
cout<<"expected value: "<<(int)ref_img.at<Vec3b>(i,j)[0]<<", final_value: "<<(int)final_img.at<Vec3b>(i,j)[0]<<", actual value:"<<(int)img_rev.at<Vec3b>(i,j)[0]<<endl;
}
if((int)diff.at<Vec3b>(i,j)[1] > 0)
err_g++;
if((int)diff.at<Vec3b>(i,j)[2] > 0)
err_b++;
}
}
cout<<"number of errors: "<<err_r<<", "<<err_g<<", "<<err_b;
return 0;
}
////core
#include "stream_check_h.hpp"

void ftest(Stream_t& Sin,Stream_t& Sout)
{
conv cin,cout;

for(int i=0;i<256;i++)
{
for(int j=0;j<512;j++)
{
Sin >> cin.i;
cout.r = cin.r/2.0 ;
cout.g = cin.g/2.0 ;
cout.b = cin.b/2.0 ;
Sout << cout.i;
}
}
}

当我调试时,它显示像素的蓝色组件是匹配的。对于一个红色像素,它显示了以下内容:

expected value: 22, final_value: 14, actual value:45

,红色、绿色和蓝色的总误差为:

number of errors: 126773, 131072, 0

我不明白为什么红色和绿色会出错。我在这里发帖,希望有人能帮我解决这个问题。

Thanks in advance

我假设您使用的是32位宽的流,具有3 RGB像素8位无符号(CV_8U3)。我认为在您的情况下,联合类型的问题是重叠三个成员(不像你引用的例子中的一个浮点值)。这意味着,通过除法,实际上是对接收到的整个32位数据进行除法。

我很快想到的可能的解决方案是将您从流中获得的unsigned int转换为ap_uint<32>类型,然后将其切割为R, G, B块(使用range()方法)并除法。最后,组装返回结果并将其流返回。

unsigned int packet;
Sin >> packet;
ap_uint<32> packet_uint32 = *((ap_uint<32>*)&packet); // casting (not elegant, but works)
ap_int<8> b = packet_uint32.range(7, 0);
ap_int<8> g = packet_uint32.range(15, 8);
ap_int<8> r = packet_uint32.range(23, 16); // In case they are in the wrong bit range/order, just flip the r, g, b assignements
b /= 2;
g /= 2;
r /= 2;
packet_uint32.range(7, 0) = b;
packet_uint32.range(15, 8) = g;
packet_uint32.range(23, 16) = r;
packet = packet_uint32.to_int();
Sout << packet;

注意:我在上面的代码中重用了相同的变量:HLS不应该抱怨它,并且无论如何都会产生一个好的RTL。如果不需要,就创建新的。

最新更新