Memory VHDL中的图像处理流水线

Memory VHDL中的图像处理流水线,memory,image-processing,vhdl,fpga,pipeline,Memory,Image Processing,Vhdl,Fpga,Pipeline,我目前正在尝试用VHDL开发Sobel过滤器。我使用的是存储在BRAM中的640x480图片。该算法使用图像像素的3x3矩阵来处理每个输出像素。我的问题是,我目前只知道将图像放入BRAM,其中BRAM的每个地址都保存一个像素值。这意味着我每个时钟只能读取一个像素。我的问题是,我正在尝试管道数据,因此理想情况下,我需要能够在每个时钟上获得三个像素值(图片每行一个),这样在我的初始延迟之后,我可以在每个时钟上加载三个新像素值,并在每个时钟上获得一个输出像素。我正在寻找一种方法来做到这一点,但无法找到

我目前正在尝试用VHDL开发Sobel过滤器。我使用的是存储在BRAM中的640x480图片。该算法使用图像像素的3x3矩阵来处理每个输出像素。我的问题是,我目前只知道将图像放入BRAM,其中BRAM的每个地址都保存一个像素值。这意味着我每个时钟只能读取一个像素。我的问题是,我正在尝试管道数据,因此理想情况下,我需要能够在每个时钟上获得三个像素值(图片每行一个),这样在我的初始延迟之后,我可以在每个时钟上加载三个新像素值,并在每个时钟上获得一个输出像素。我正在寻找一种方法来做到这一点,但无法找到它

我能想到的唯一解决办法是将图像用3个BRAMs处理。这样,我可以读取每个时钟周期3行的值。但是,没有足够的内存空间容纳一个甚至足够大的RAM来容纳640x480图像,更不用说三个了。我可以降低图片大小,这样做,但我真的想用我目前的640x480图像大小


任何帮助或指导都将不胜感激

一个简单的解决方案是将图像的1/4存储在4个单独的存储器中。第一个内存包含每4行一次,第二个内存包含每4行一次,从第二行开始,等等。即使需要3行,我也会使用4,因为4平均除以480和其他标准分辨率。此外,找到模4的二进制数也很简单,这是对内存进行排序所必需的

您可以使用行号的MSB来寻址RAM,并使用LSB来计算每个RAM输出的相对顺序(代码仅用于演示idea,不能按原样使用…):


address几年前我做了一个sobel过滤器。为此,我编写了一个管道,每个时钟周期提供9个像素:

architecture rtl of matrix_3x3_builder_8b is
type fifo_t is array (0 to 2*IM_WIDTH + 2) of std_logic_vector(7 downto 0);
signal fifo_int : fifo_t;

begin    

    p0_build_5x5: process(rst_i,clk_i)
    begin
        if( rst_i = '1' )then
            fifo_int <= (others => (others => '0'));
        elsif( rising_edge(clk_i) )then
             if(data_valid_i = '1')then
                for i in 1 to 2*IM_WIDTH + 2 loop
                    fifo_int(i) <= fifo_int(i-1);
                end loop;           
                fifo_int(0) <= data_i;  
            end if;
        end if;
    end process p0_build_5x5;

data_o1 <= fifo_int(0*IM_WIDTH + 0);
data_o2 <= fifo_int(0*IM_WIDTH + 1);
data_o3 <= fifo_int(0*IM_WIDTH + 2);
data_o4 <= fifo_int(1*IM_WIDTH + 0);
data_o5 <= fifo_int(1*IM_WIDTH + 1);
data_o6 <= fifo_int(1*IM_WIDTH + 2);
data_o7 <= fifo_int(2*IM_WIDTH + 0);
data_o8 <= fifo_int(2*IM_WIDTH + 1);
data_o9 <= fifo_int(2*IM_WIDTH + 2);

end rtl;
矩阵_3x3_builder_8b的体系结构rtl为 fifo类型是标准逻辑向量(7到0)的数组(0到2*IM\u宽度+2); 信号先进先出:先进先出; 开始 p0\U构建5x5:过程(rst\U i、clk\U i) 开始 如果(rst_i='1'),则 先进先出(其他=>“0”); elsif(上升沿(clk_i))然后 如果(数据有效),则 对于1到2*IM_宽度+2循环中的i
fifo_int(i)如果您想继续存储整个图像,那么我会按照Jonathan Drolet的建议,在四个RAM之间循环,同时同时写入和读取所有4个(将您关心的三个寄存器混入3个寄存器)。 这是因为RAM的深度足以使您在1/4深度(77k深度)时仍能获得完整的BRAM利用率,并且您的读操作可以预期地分段

对于这个问题的细节,Nicolas Roudel的方法在BRAM中要便宜得多,尽管你不能一次存储整个图像,所以无论你在哪里发送结果,都不能对你施加反压力,除非你能对数据源施加反压力。这对你的申请可能重要,也可能不重要


当您尝试使用非常宽但相当浅(1k深)的ram执行类似操作时,分段将使用更多的块ram(甚至开始推断分布式ram)。当读取不遵循特定模式时(在您的案例中,模式是它们都是连续的和相邻的位置),ram无法分割。保持BRAM有效使用的最佳策略通常是从本机双端口块RAM构建四端口RAM,方法是使用与正常时钟相位一致的2x时钟对其进行计时,允许您每1x时钟周期进行一次写入和三次读取。

每个块RAM字中使用了多少位?你使用RGB还是黑白?您还可以使用外部内存存储映像(QDR-SSRAM或DDR-SDRAM),并将映像的一部分复制到本地快速块RAM中。此解决方案可扩展到FullHD及以上。请注意,这是一个可分离的过滤器,因此您可以将过滤作为两个一维卷积执行。与在二维邻域中加载9个像素不同,您可以分别处理图像的行和列。照片为每像素12位,我使用RGB。此代码使用寄存器存储图像行(至少在Xilinx上),它确实应该修改为使用BRAM。实际上,如果你需要一个更大的图像或者过滤器中有更多的行,它的规模会非常大。是的,理论上这段代码使用寄存器,但是对于Quartus,你可以指定使用FPGA内存块(如M9K等)来代替寄存器。看起来这将推断出2组块RAM,其中3个寄存器在前、后和中间,全部配置为模拟一个长移位寄存器。这也特别适用于这个问题,因为它只使用块ram的2*宽度*(位/像素)位。这意味着您可能会大大提高您的最大分辨率。
architecture rtl of matrix_3x3_builder_8b is
type fifo_t is array (0 to 2*IM_WIDTH + 2) of std_logic_vector(7 downto 0);
signal fifo_int : fifo_t;

begin    

    p0_build_5x5: process(rst_i,clk_i)
    begin
        if( rst_i = '1' )then
            fifo_int <= (others => (others => '0'));
        elsif( rising_edge(clk_i) )then
             if(data_valid_i = '1')then
                for i in 1 to 2*IM_WIDTH + 2 loop
                    fifo_int(i) <= fifo_int(i-1);
                end loop;           
                fifo_int(0) <= data_i;  
            end if;
        end if;
    end process p0_build_5x5;

data_o1 <= fifo_int(0*IM_WIDTH + 0);
data_o2 <= fifo_int(0*IM_WIDTH + 1);
data_o3 <= fifo_int(0*IM_WIDTH + 2);
data_o4 <= fifo_int(1*IM_WIDTH + 0);
data_o5 <= fifo_int(1*IM_WIDTH + 1);
data_o6 <= fifo_int(1*IM_WIDTH + 2);
data_o7 <= fifo_int(2*IM_WIDTH + 0);
data_o8 <= fifo_int(2*IM_WIDTH + 1);
data_o9 <= fifo_int(2*IM_WIDTH + 2);

end rtl;