0

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

我一直在尝试解决它,但我无法看到问题出在哪里。我已附上以下所有文件,有人可以帮我解决吗?

////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

我不明白为什么红色和绿色会出错。我在这里发帖希望新的眼睛能帮助我解决问题。

提前致谢

4

1 回答 1

0

我假设您正在使用具有 3 个 RGB 像素 8 位无符号 (CV_8U3) 的 32 位宽流。我相信在你的情况下联合类型的问题是它的三个成员的重叠(不仅仅是你引用的例子中的一个浮点值)。这意味着通过进行除法,您实际上是在对您接收的整个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。如果不应该,只需创建新的。

于 2021-03-07T23:49:28.977 回答