C++ ile Gabor Filtre Uygulaması

Adını Dennis Gabor' dan alan Gabor Filtresi, görüntü üzerinde belirli yönlerde uzanan ayrıtları tespit etmek için  kullanılan bir görüntü işleme filtresidir. Yön temelli bir filtre olduğundan Gabor filtresi plaka tanıma, karakter tanıma, yüz tanıma gibi işlemlerde sıklıkla kullanılır. İşlem çekirdek matris adı verilen bir filtre matrisinin filtrelenecek resim ile konvolüsyonundan ibarettir. Filtreleme işlemini nasıl yapacağımızı daha önceki yazılarımda anlattığımdan burada çekirdek matrisin oluşturulmasını anlatmaya çalışacağım. İki boyutlu Gabor filtresi çekirdek matrisi aşağıdaki formüle göre hesaplanır.





Burada ilk üstel ifade (Gaussian Fonksiyon) x' ve y' ne bağlı olarak azalan bir ifade iken ikinci üstel ifade karmaşık sayı içeren periyodik bir ifadedir. Bu ifade Euler formülünden yararlanılarak
düzenlenirse g fonksiyonu gerçel ve sanal bileşenleri cinsinden şu şekilde de ifade edilebilir.




İşlem bu iki çekirdek matrisinin hesaplanıp görüntü üzerine uygulanması ve iki görüntünün karelerinin toplamının karekökleri alınarak gerçekleştirilebileceği gibi sadece gerçel kısmın hesaplanması ile de gerçekleştirilebilir. Çekirdek matrise ait parametreler aşağıda tek tek incelenmiştir.

Lambda : Kosinüs çarpanının dalga boyunu belirleyen katsayıdır. Katsayının 1 olması durumunda kosinüs ifadesi sürekli 1 olacağından ( cos(2.pi.x') =1) katsayı 2 veya daha büyük bir tamsayı seçilmelidir.

Teta: Teta doğrudan formül içerisinde görünmese de Gabor filtresinin aslında en önemli değişkenlerinden biridir. Bu değişken x' ve y' değerlerinin hesaplanmasında kullanılır ve oluşturulmak istenen Gabor çekirdeğinin yönelim açısıdır.  x' ve y' değişkenleri verilen bir teta değeri için aşağıdaki formül ile hesaplanır.




Fi : Fi açısı oluşturulacak çekirdek matrisinin faz açısıdır. Bu değer değiştirilerek filtre x ekseninde ötelenebilir.

Sigma : Sigma değeri Gaussian fonksiyonun standart sapmasını belirleyen katsayıdır. Bu parametre Gaussian fonksiyonun açıklığını belirlediğinden bu değerin küçük seçilmesi ile Gabor dalgacıkları bir birlerine yaklaşacaktır.

Gamma : Bu değer de verilen standart sapma değerinin y' için belirlenmesinin sağlar. Bu değerin 1 olması durumunda oluşacak çekirdek matris x ve y için eşit standart sapmaya sahip olduklarından eşit uzunlukta olacakken, farklı bir oran seçildiğinde çekirdek matris dikdörtgenimsi bir şekilde oluşacaktır.

x,y : Bu iki değer oluşturulacak 2 boyutlu çekirdek matrisin koordinatlarını temsil eder. NxN büyüklükte bir çekirdek matris için x ve y değerleri [-(N-1)/2,(N-1)/2] aralığında gezilerek çekirdek matris hesaplanır.

Verilen parametreler ile hesaplanan Gabor çekirdeği doğrudan konvolüsyon almaya uygun değildir. Çünkü hesaplanan değerler ile doğrudan yapılacak bir konvolüsyon işlemi sonucunda çıkacak değerler 0-255 değeri arasında yüksek ihtimalle bulunmayacaktır. Bu nedenle çekirdek matris integrali 0 olacak şekilde normalize edilir. Bu işlem sonrasında hesaplanacak yeni değerlerin pek çoğu 0-255 arasında kalacaktır.

Normalizasyon işlemi çekirdek üzerinde şu adımlarla yapılır.
  1. Pozitif ve Negatif değerlerin toplamlarını hesapla
  2. Bu iki değerin genliklerinin ortalamasını hesapla
  3. px=Pozitif Toplam / Ortalama ve nx=-Negatif Toplam / Ortalama çarpanlarını hesapla
  4. Pozitif değerleri nx, Negatif değerleri ise px katsayısı ile çarp
Aşağıda verilen parametrelere karşılık bir gabor çekirdek vektörü döndüren fonksiyon C++ dili ile yazılmıştır.


double*  gabor_fil(double lamda,double sigma,double gama,double fi,double theta,short int normalize,short int size) {
     
      double sx,sy;
      int x,y;
      short int indis=0;
            
      if(size==1) {gama<1 & gama>0 ? size=(short int) (8*sigma/gama) : size=(short int) (8*sigma);}
      if(size%2==0) {size=size+1;}
            
      double *gb;
      gb=new double [size*size];
                        
      for(x=(int)-(size-1)/2;x < (int)(size+1)/2;x++) { 
            for(y=(int)-(size-1)/2;y < (int)(size+1)/2;y++) {
                                                          
                  sx=x*cos(theta)+y*sin(theta);
                  sy=-x*sin(theta)+y*cos(theta);
       
                  *(gb+indis) = exp(-(sx*sx+gama*gama*sy*sy)/(2*sigma*sigma))*cos(2*pi*sx/lamda +fi);
                  indis++;
             }
       }
       if(normalize==1) {                                                    
            /*Normalization*/                                                    
            double norm=0;
            double possum=0,negsum=0;
            
            for(int i=0;i <  size;i++) { 
                for(int j=0;j  < size;j++) {
                    if(gb[i*size+j] <  0) {
                     possum+=gb[i*size+j];}
                    else {
                     negsum+=gb[i*size+j];}
                 }
             }
            norm=0.5*(possum-negsum);

            for(int i=0;i <  size;i++) { 
                for(int j=0;j <  size;j++) {
                    
                    if(gb[i*size+j]  > 0) {
                       gb[i*size+j]=-1*gb[i*size+j]*negsum/norm;
                    }
                    else if(gb[i*size+j] < 0) {
                     gb[i*size+j]=gb[i*size+j]*possum/norm;
                    }
                 }
             }
              
       /*Normalization*/
       }
       return gb;
}

Oluşturulan bu programı kullanarak plaka aday bölgelerini çıkaran bir örnek yazalım. Plaka aday bölgeleri belirlemek için girdi resminin 0,45 ve 90° için Gabor filtre yanıtlarının ortalaması alındıktan sonra görüntü ikili tonlanır. Ardından morfolojik işlemlerle görüntü genişletilip aşındırıldıktan sonra plaka aday bölgeler bulunur. İşlem süresinin kısa olması için Gabor filtre boyutları 7x7 seçilmiştir. Hesaplama için yazılan kod ve uygulama sonuçları aşağıdadır.


giren=resim_acm("bmp_car\\th_test_083.bmp");
yeni=yenim_bmp(giren.bminfo.width,giren.bminfo.height);

double *gabor;
double teta=0;

for(teta=0;teta < =pi/2;teta+=pi/4) {
      gabor=gabor_fil(8,2,1,0,teta,1,7);//lamda,sigma,gama,fi,teta,normalize,size

      resim=resim_kon(giren,gabor,7);
            
      for(int i=0;i < resim.bminfo.width; i++) {
            for(int j=0;j < resim.bminfo.height; j++) {
               yeni.pixels[i][j].red+=(byte)(resim.pixels[i][j].red/3);
               yeni.pixels[i][j].green+=(byte)(resim.pixels[i][j].green/3);
               yeni.pixels[i][j].blue+=(byte)(resim.pixels[i][j].blue/3);   
            }
      }       
}

resim_yaz(yeni,"araba_ort.bmp");
            
yeni=resim_iki(yeni,otsus_esi(yeni)+20);
            
resim=resim_dil(yeni,strel,5);
resim=resim_dil(resim,strel,5);
            
resim=resim_ero(resim,strel,5);
resim=resim_ero(resim,strel,5);
            
resim=resim_ero(resim,strel,5);
resim=resim_ero(resim,strel,5);
resim=resim_dil(resim,strel,5);
            
resim_yaz(resim,"araba_plaka.bmp");

Bulunan aday plaka bölgeleri en/boy oranı ve genişlik bilgilerine de bakarak plaka olarak adlandırılabilecek bölgeler büyük doğrulukla tespit edilebilir.

araç resmi gabor filtre ortalaması plaka bölgeleri

araç resmi gabor filtre ortalaması plaka bölgeleri

2 yorum:

  1. Plaka analizi için gabor filtreyi c# da kullanmak istiyorum yardımcı olabılırmısınız.
    srl_fatih@hotmail.com

    YanıtlaSil
  2. Aracımı nasıl bulabilirim plakadan

    YanıtlaSil

Görüntü işleme ile ilgili yeni yazıları ve bu sitede yer alan yazıların güncellenmiş sürümlerini www.imlab.io veya cescript.github.io adreslerinden takip edebilirsiniz.

X