2015-04-08 169 views
2

我目前正在嘗試開發VHDL中的Sobel濾波器。我正在使用存儲在BRAM中的640x480圖片。該算法使用圖像的3×3像素矩陣來處理每個輸出像素。我的問題是,我目前只知道將圖像放入BRAM中,BRAM的每個地址都有一個像素值。這意味着我每個時鐘只能讀取一個像素。我的問題是我正在嘗試傳輸數據,所以我希望能夠獲得每個時鐘三個像素值(每個圖像的每行一個像素值),因此在初始延遲之後,我可以每載入三個新像素值時鐘並在每個時鐘上獲得一個輸出像素。我正在尋找一種方法來做到這一點,但無法弄清楚。VHDL中的圖像處理流水線

我能想到解決這個問題的唯一方法就是在3個BRAM中有圖像。這樣我可以讀取每個時鐘週期3行的值。但是,沒有足夠的內存空間來容納足夠大的RAM以適應640x480的圖像,更不用說三個了。我可以通過這種方式降低圖片尺寸,但我真的想用我當前的640x480圖片尺寸來實現。

任何幫助或指導將不勝感激。

+0

每個BlockRAM字中使用了多少位?你使用RGB還是黑白?您也可以使用外部存儲器來存儲圖像(QDR-SSRAM或DDR-SDRAM),並將圖像的一部分複製到本地快速BlockRAM中。該解決方案可擴展至FullHD及以上版本。 – Paebbels

+0

請注意,[Sobel](http://en.wikipedia.org/wiki/Sobel_operator)是一個可分離的過濾器,因此您可以將過濾作爲兩個一維卷積進行。您可以分別處理圖像的行和列,而不是在二維鄰域中加載9個像素。 – dhanushka

+0

該照片是每像素12位,我使用RGB –

回答

2

一個簡單的解決方案是將圖像的四分之一存儲在4個獨立的存儲器中。第一個內存包含每4行,每4行第二行,從第二行開始,等等。即使您需要3行,我也會使用4,因爲4會均勻分配480和其他所有標準分辨率。另外,找到一個模4的二進制數是微不足道的,這是訂購記憶所需要的。

你可以使用行號的MSB來尋址你的RAM,LSB去計算出每個RAM輸出的相對順序(代碼僅僅是爲了展示想法,它不能用於......):

address <= line(line'left downto 2) & col; -- Or something more efficent on packing 
data0 <= ram0(address); 
data1 <= ram1(address); 
data2 <= ram2(address); 
data3 <= ram3(address); 

case line(1 downto 0) is 
    when "00" => 
     line0 <= data0; 
     line1 <= data1; 
     line2 <= data2; 
    when "01" => 
     line0 <= data1; 
     line1 <= data2; 
     line2 <= data3; 
    when "10" => 
     line0 <= data2; 
     line1 <= data3; 
     line2 <= data0; 
    when "11" => 
     line0 <= data3; 
     line1 <= data0; 
     line2 <= data1; 
    when others => null; 
end case; 
2

幾年前我做了一個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矩陣。管道填​​充時間較長,但一旦完成,每個時鐘脈衝都有一個新的矩陣。

+1

此代碼使用**寄存器**來存儲圖像行(至少在Xilinx上),它確實應該修改爲使用BRAM。因爲如果你需要更大的圖像或更多的線條在濾鏡中,它會變得非常可怕。 –

+1

是的,理論上這個代碼使用寄存器,但使用Quartus,您可以指定使用FPGA存儲器模塊(如M9K等),而不是寄存器。 –

+0

看起來像這樣會推斷出2組塊ram,其中之前,之後和之間有3個寄存器,所有這些都被配置爲模擬一個長移位寄存器。這也適用於這個問題,因爲它只使用塊內存的2 *寬*(比特/像素)比特。這意味着你可以大幅度提高你的最大分辨率。 – QuantumRipple

1

如果你想繼續存儲整個圖像,那麼我會按照Jonathan Drolet的建議在四個RAM之間循環,同時一次寫入並讀取所有4個數據(將你關心的三個數據複製到3個寄存器中)。 這是有效的,因爲你的公羊將會足夠深,以至於你仍然能夠在1/4深度(77k深)仍然能夠獲得完整的BRAM利用率,並且你的讀取可以被預測地分割。

對於這個問題的細節,雖然你不能一次存儲整個圖像,但是對於BRAM來說,Nicolas Roudel的方法要便宜得多,所以無論你發送結果如何,除非你能夠反壓你的數據資源。這對你的應用程序來說可能並不重要。

當你試圖用極寬,但相當淺的(1k深)來做這樣的事情時,公羊會使用更多的塊RAM(甚至開始推斷分佈式RAM)。當讀數不遵循特定模式(您的情況中的模式是它們都是連續的和相鄰的位置)時,內存不能被分段。保持高效BRAM使用的最佳策略通常是通過使用與您的正常時鐘相位對齊的2x時鐘爲它們提供時鐘,從本地雙端口塊RAM製作四端口RAM,從而允許您每寫1個時鐘進行一次寫操作和3次讀取週期。