İmge İşlemede Konvolüsyonun VHDL ile Gerçeklenmesi

volisyon kerneli olarak adlandırılan bir matris ile çarpımıyla elde edilir. Konvolisyon işlemine ilişkin denklem aşağıda verilmiştir.

Şekil 1 Konvolüsyon işlemi

Şekil 1’de verilen örnek piksel değeri ve konvolüsyon kerneline ilişkin hesaplama aşağıdaki gibi yapılmatakdır.

Örnek : Aşağıda imge de konvolüsyon işleminin gerçekleştirildiği konvolusyon_imge.vhd VHDL kodu verilmiştir. Kodda RAM üzerinden okunan datalar 3×3 matriste saklanmaktadır. Matriste bulunan datalar konvolusyon işlemine tabi tutularak işlem sonucu elde edilmektedir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.konvolusyon_imge_paket.all;
entity konvolusyon_imge is
  port(
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_en  : in std_logic;
    in_basla : in std_logic;
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    in_data_vld : in std_logic;
    in_kernel : in std_logic_vector(2 downto 0);
    out_addr : out std_logic_vector(log2_int(IMGE_SATIR * IMGE_SUTUN) - 1 downto 0);
    out_addr_vld : out std_logic;
    out_data : out std_logic_vector(7 downto 0);
    out_data_vld : out std_logic;
    out_tamam : out std_logic               
  );
end konvolusyon_imge;

architecture Behavioral of konvolusyon_imge is

  type t_Konvolusyon_Imge is (BOSTA, RAMDAN_OKU, OKUMA_BEKLE, MATRIS_KAYDIR, KONV_HESAPLA, SAYAC_KONT, TAMAM ); 
  signal r_Konvolusyon_Imge : t_Konvolusyon_Imge := RAMDAN_OKU;
  signal VERI : m_VERI_MATRISI := (others => (others => (others => '0')));  
  signal Tek_Sutun : v_VERI_DIZISI := (others => (others => '0'));      
  signal n_i : integer := 0;
  signal n_j : integer := 0;
  signal n_k : integer := 0;
  signal n_s : integer := 0;
  signal r_addr : std_logic_vector(log2_int(IMGE_SATIR * IMGE_SUTUN) - 1 downto 0) := (others => '0');   
  signal r_addr_vld : std_logic := '0';
  signal r_data : std_logic_vector(7 downto 0) := (others => '0');  
  signal r_data_vld : std_logic := '0';
  signal r_bayrak_oku : std_logic := '0';
  signal r_kenar_bulma_tmm : std_logic := '0';  
  signal r_tamam : std_logic := '0';

begin

  out_addr <= r_addr;
  out_addr_vld <= r_addr_vld;
  out_data <= r_data;
  out_data_vld <= r_data_vld;
  out_tamam <= r_tamam;
  process(in_clk, in_rst, in_en)
  begin

    if in_rst = '1' then
      Tek_Sutun <= (others => (others => '0')); 
      n_s <= 0;
      r_bayrak_oku <= '0';

   elsif rising_edge(in_clk) then
      if in_en = '1' then
        if in_data_vld = '1' then
          Tek_Sutun(n_s) <= in_data;
          n_s <= n_s + 1;
          if n_s = 2 then
            n_s <= 0;
            r_bayrak_oku <= '1';
          end if;
        else
          r_bayrak_oku <= '0';
        end if;
      end if;
    end if;
  end process;

  process(in_clk, in_rst)
  begin
    if in_rst = '1' then
      VERI <= (others => (others => (others => '0')));
      r_Konvolusyon_Imge <= BOSTA;
      n_i <= 0;
      n_j <= 0; 
      r_addr <= (others => '0');
      r_addr_vld <= '0';
      r_data <= (others => '0');
      r_data_vld <= '0';
      r_tamam <= '0'; 
      n_k <= 0; 

    elsif rising_edge(in_clk) then
      if in_en = '1' then
        r_addr_vld <= '0';
        r_data_vld <= '0';
        r_tamam <= '0';  
        case r_Konvolusyon_Imge is
          when BOSTA =>
            if in_basla = '1' then
              r_Konvolusyon_Imge <= RAMDAN_OKU;
            end if;

          when RAMDAN_OKU =>
            r_addr <= conv_std_logic_vector((n_i + n_k) * IMGE_SUTUN + n_j,  r_addr'length);
            r_addr_vld <= '1';
            n_k <= n_k + 1;
            if n_k = 2 then
              r_Konvolusyon_Imge <= OKUMA_BEKLE; 
            end if;

          when OKUMA_BEKLE => 
            n_k <= 0;
            if r_bayrak_oku = '1' then
              r_Konvolusyon_Imge <= MATRIS_KAYDIR; 
            end if;

          when MATRIS_KAYDIR =>
            n_j <= n_j + 1;
            VERI <= f_Matris_Kaydır(VERI, Tek_Sutun);
            if n_j < 2 then
              r_Konvolusyon_Imge <= RAMDAN_OKU;   
            else
              r_Konvolusyon_Imge <= KONV_HESAPLA; 
            end if;

          when KONV_HESAPLA =>
            r_data <=  f_Konvolusyon_Imge(VERI, r_KERNEL_LISTE(conv_integer(in_kernel)));
            r_data_vld <= '1';
            r_Konvolusyon_Imge <= SAYAC_KONT;
            if n_j = IMGE_SUTUN then
              n_i <= n_i + 1;
              n_j <= 0;
            end if;

          when SAYAC_KONT =>
            r_data_vld <= '0';
            if n_i < IMGE_SATIR - 2 then
              r_Konvolusyon_Imge <= RAMDAN_OKU;
            else
              n_i <= 0;
              r_Konvolusyon_Imge <= TAMAM;                              
            end if;

          when TAMAM =>
            r_tamam <= '1'; 
            r_Konvolusyon_Imge <= BOSTA;

          when others => NULL;               
        end case;
      end if;
    end if;       
  end process;
end Behavioral;

Bu örnekte tip, fonksiyon, sabit vb tanımlama işlemleri konvolusyon_imge_paket.vhd paketi içerisinde yapılmıştır. Aşağıda bu pakete ilişkin kod verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
package konvolusyon_imge_paket is
  constant IMGE_SATIR : integer := 256;
  constant IMGE_SUTUN : integer := 256;
  constant VERI_UZUNLUGU : integer := 8;
  type v_VERI_DIZISI is array (0 to 2) of std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
  type m_VERI_MATRISI is array (0 to 2) of v_VERI_DIZISI;
  type v_KERNEL_DIZISI is array (0 to 2) of integer;
  type m_KERNEL_MATRISI is array (0 to 2) of v_KERNEL_DIZISI;  
  type t_KERNEL_LISTE is array (0 to 7) of m_KERNEL_MATRISI;
  constant r_KERNEL_LISTE : t_KERNEL_LISTE :=
          (((1, 2, 1), (0, 0, 0), (-1, -2, -1)),
           ((1, 0, -1), (2, 0, -2), (1, 0, -1)),
           ((1, 1, 1), (0, 0, 0), (-1, -1, -1)),
           ((1, 0, -1), (2, 0, -2), (1, 0, -1)),
           ((0, 0, 0), (0, 1, 0), (0, 0, -1)),
           ((0, 1, 0), (1, 0, 1), (0, 1, 0)),
           ((-1, -1, -1), (-1, 8, -1), (-1, -1, -1)),
           ((1, 2, 1), (2, 4, 2), (1, 2, 1)));                                            

  constant YATAY_SOBEL : std_logic_vector(2 downto 0) := "000";   
  constant DIKEY_SOBEL : std_logic_vector(2 downto 0) := "001";
  constant YATAY_PREWIT : std_logic_vector(2 downto 0) := "010";
  constant DIKEY_PREWIT : std_logic_vector(2 downto 0) := "011"; 
  constant KAYDIR_CIKART : std_logic_vector(2 downto 0) := "100";  
  constant ALCAK_GECIREN : std_logic_vector(2 downto 0) := "101";    
  constant YUKSEK_GECIREN : std_logic_vector(2 downto 0) := "110"; 
  constant GAUSS : std_logic_vector(2 downto 0) := "111"; 

  function log2_int(in_giris : integer) return integer;
  function f_Matris_Kaydır(Kernel : m_VERI_MATRISI; Tek_Sutun : v_VERI_DIZISI) return m_VERI_MATRISI;
  function f_Konvolusyon_Imge(VERI : m_VERI_MATRISI; KERNEL : m_KERNEL_MATRISI) return std_logic_vector;

end konvolusyon_imge_paket;

package body konvolusyon_imge_paket is
  function f_Konvolusyon_Imge(VERI : m_VERI_MATRISI; KERNEL : m_KERNEL_MATRISI) return std_logic_vector is
    variable Toplam : integer;
  begin
    Toplam := 0;
    for n_i in 0 to 2 loop
      for n_j in 0 to 2 loop
        Toplam := Toplam +  conv_integer(VERI(n_i)(n_j)) * KERNEL(2 - n_i)(2 - n_j); 
      end loop;
    end loop;
    if Toplam > 255 then
      Toplam := 255;
    elsif Toplam < 0 then
      Toplam := 0;
    end if;
    return conv_std_logic_vector(Toplam, 8);       
  end f_Konvolusyon_Imge;

  function f_Matris_Kaydir(Kernel : m_VERI_MATRISI; Tek_Sutun : v_VERI_DIZISI) return m_VERI_MATRISI is
    variable Kernel_v : m_VERI_MATRISI;
    variable Tek_Sutun_v : v_VERI_DIZISI;
  begin
    Kernel_v := Kernel;
    Tek_Sutun_v := Tek_Sutun;       
    for n_j in 0 to 1 loop
      for n_i in 0 to 2 loop
        Kernel_v(n_i)(n_j) := Kernel_v(n_i)(n_j + 1);
      end loop;
    end loop;
    for n_j in 0 to 2 loop
      Kernel_v(n_j)(2) := Tek_Sutun_v(n_j);
    end loop;
    return Kernel_v;       
  end f_Matris_Kaydir;  
  function log2_int(in_giris : integer) return integer is
    variable sonuc : integer;
  begin
    for n_i in 0 to 31 loop
      if (in_giris <= (2 ** n_i)) then
        sonuc := n_i;
        exit;
      end if;
    end loop;
    return sonuc;
  end function;
end package body;

konvolusyon_imge varlığının benzetiminin yapılabilmesi için aşağıda tb_konvolusyon_imge.vhd VHDL sınama kodu verilmiştir. Kodda dosyadan okunan imge dataları RAM bloğuna yazılmaktadır. Benzetim işlemleri sonuçları Şekil 2’de gösterilmiştir.

  • Şekil 2.a’da orijinal imge,
  • Şekil 2.b’de yatay Sobel kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.c’de dikey Sobel kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.d’de yatay Prewit kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.e’de dikey Prewit kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.f’de kaydır ve çıkart kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.g’de alçak geçiren süzgeç kerneli ile konvolüsyon sonucunda elde edilen yeni imge,
  • Şekil 2.h’de yüksek geçiren süzgeç kerneli ile konvolüsyon sonucunda elde edilen yeni imge ve
  • Şekil 2.i’de gauss kerneli ile konvolüsyon sonucunda elde edilen yeni imge gösterilmiştir.

(a)

(b)

(c)

(d)

(e)

(f)

(g)

(h)

(i)
Şekil 2 İmge işlemede farklı kerneller için çıktılar (a) Orijinal imge, (b)Yatay Sobel, (c)Dikey Sobel, (d) Yatay Prewit, (e) Dikey Prewit, (f)Kaydır ve Çıkart, (g) Alçak Geçiren, (h) Yüksek Geçiren, (i) Gauss

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use std.textio.ALL;
use work.konvolusyon_imge_paket.all;

entity tb_konvolusyon_imge is
end tb_konvolusyon_imge;

architecture Behavioral of tb_konvolusyon_imge is

  component konvolusyon_imge
  port(
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_en  : in std_logic;
    in_basla : in std_logic;
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    in_data_vld : in std_logic;
    in_kernel : in std_logic_vector(2 downto 0);
    out_addr : out std_logic_vector(log2_int(IMGE_SATIR * IMGE_SUTUN) - 1 downto 0);
    out_addr_vld : out std_logic;
    out_data : out std_logic_vector(7 downto 0);
    out_data_vld : out std_logic;
    out_tamam : out std_logic               
  );       
  end component;

  component block_ram
  generic(
    VERI_UZUNLUGU : integer := 8;
    RAM_DERINLIGI : integer := 110
  );
  port(
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_ram_aktif : in std_logic;
    in_yaz_en : in std_logic;
    in_oku_en : in std_logic;
    in_data_addr : in std_logic_vector(log2_int(RAM_DERINLIGI) - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data_vld : out std_logic
    );
  end component;

  constant CLK_PERIOD : time := 20 ns;
  constant VERI_YOLU_OKUMA : string := "C:\cameraman.txt";
  constant VERI_YOLU_YAZMA : string := "D:\cameraman_sonuc.txt";
  type t_Konvolusyon_Imge  is (RAM_OKUMA, RAM_YAZMA, TAMAM);
  signal r_Konvolusyon_Imge : t_Konvolusyon_Imge := RAM_YAZMA;
  signal in_clk : std_logic := '0';
  signal in_rst : std_logic := '0';
  signal in_basla : std_logic := '0';
  signal in_ram_aktif : std_logic := '1';
  signal out_data_vld : std_logic := '0';
  signal out_data : std_logic_vector(7 downto 0) := (others => '0');
  signal in_ram_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal in_ram_data_addr : std_logic_vector(log2_int(IMGE_SATIR * IMGE_SUTUN) - 1 downto 0) := (others => '0');
  signal out_ram_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal out_data_addr : std_logic_vector(log2_int(IMGE_SATIR * IMGE_SUTUN) - 1 downto 0) := (others => '0');
  signal out_ram_data_vld : std_logic := '0';       
  signal in_en : std_logic := '0';
  signal in_yaz_en : std_logic := '0';
  signal in_oku_en : std_logic := '0';       
  signal data_sayac : integer := 0;
  signal out_data_addr_vld : std_logic := '0'; 
  signal r_imge_isleme_tamam : std_logic := '0'; 

begin

  process
  begin
    in_clk <= '1';
    wait for CLK_PERIOD / 2;
    in_clk <= '0';
    wait for CLK_PERIOD / 2;
  end process; 

  process
    begin
    in_basla <= '1';
    wait for CLK_PERIOD;
    in_basla <= '0'; wait;
  end process;    

  process(in_clk)
    file dosya_okuma : text open read_mode is VERI_YOLU_OKUMA;
    file dosya_yazma : text open write_mode is VERI_YOLU_YAZMA;
    variable satir_okuma : line;
    variable satir_yazma : line;
    variable data_okuma : integer;     
  begin
    if rising_edge(in_clk) then
      if out_data_vld = '1' then
        write(satir_yazma, conv_integer(out_data));
        writeline(dosya_yazma, satir_yazma);               
      end if;
      case r_Konvolusyon_Imge is
        when RAM_YAZMA =>
          if not endfile(dosya_okuma) then
            readline(dosya_okuma, satir_okuma);
            read(satir_okuma, data_okuma);
            in_ram_data <= conv_std_logic_vector(data_okuma, VERI_UZUNLUGU);
            in_ram_data_addr <= conv_std_logic_vector(data_sayac, in_ram_data_addr'length);
            in_en <= '0';
            in_yaz_en <= '1';
            data_sayac <= data_sayac + 1;
          else
            r_Konvolusyon_Imge <= RAM_OKUMA;
            in_yaz_en <= '0'; 
          end if;

        when RAM_OKUMA =>
          in_en <= '1';
          in_ram_data_addr <= out_data_addr;
          in_oku_en <= out_data_addr_vld ;
          if r_imge_isleme_tamam = '1' then
            r_Konvolusyon_Imge <= TAMAM;
          end if;

        when TAMAM => null;
        when others => NULL;
      end case;
    end if;
  end process;    

  konvolusyon_imge_map : konvolusyon_imge
  port map(
    in_clk => in_clk,
    in_rst => in_rst,
    in_en => in_en,
    in_basla => in_basla,
    in_data => out_ram_data,
    in_data_vld => out_ram_data_vld,
    in_kernel => GAUSS,
    out_addr => out_data_addr,
    out_addr_vld => out_data_addr_vld, 
    out_data => out_data,
    out_data_vld => out_data_vld,
    out_tamam => r_imge_isleme_tamam               
  );  

  block_ram_map : block_ram
  generic map(
    VERI_UZUNLUGU => VERI_UZUNLUGU,
    RAM_DERINLIGI => IMGE_SATIR * IMGE_SUTUN
  )
  port map(
    in_clk => in_clk,
    in_rst => in_rst,
    in_ram_aktif => in_ram_aktif,
    in_yaz_en => in_yaz_en,
    in_oku_en => in_oku_en,
    in_data_addr => in_ram_data_addr,
    in_data => in_ram_data,
    out_data => out_ram_data,
    out_data_vld => out_ram_data_vld
  );
end Behavioral;

Blok RAM yazımızda verilen block_ram.vhd VHDL dosyasında 4. satırda bulunan paket tanımlama ifadesi aşğıda verilen ifade ile değiştirilmelidir.

use work.konvolusyon_imge_paket.all;

Aşağıda dosyadan imge okuma işleminin yapıldığı MATLAB kodu verilmiştir.

clc, clear all, close all;

imge = imread('cameraman.tif');

imshow(imge)

[satir sutun] = size(imge);

dosya = fopen('D:\cameraman_sonuc.txt', 'r');

imge_okunan = fscanf(dosya, '%d')';

COEF = [-1 -2 -1; 0 0 0; 1 2 1];

for n_i = 1 : satir - 2

    for n_j = 1 : sutun - 2

        yeni_imge(n_i, n_j) = imge_okunan((n_i - 1) * (sutun - 2) + n_j);

    end

end

fclose(dosya);

figure, imshow(uint8(yeni_imge))

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir