8 Aralık 2013 Pazar

Resim İşleme - Şablon tabanlı algoritmalar

Resim İşleme - Şablon tabanlı algoritmalar


Resmin kenarlarını tespit ederken belirli şablonlar kullanarak daha sağlıklı sonuçlar elde edebiliriz. Bu yazımızda Sobel kenar bulma algoritmasını kullanacağız. Bu algoritma da bir önceki yazımızda kullandığımız yöntemle aynı mantıkta çalışıyor fakat daha iyi sonuçlar vermesi için biraz değiştirilmiş.

Sobel şablonu aşağıdaki gibi tanımlanmış:





Üzerinde çalışılan resmin her pikseli için iki şablon da pikselin etrafındaki 3x3'lük bir alana uygulanıyor. Çevredeki piksellerin parlaklık değerleri matriste karşılık gelen değerlerle çarpılıp toplanıyor.







Formülde T, ya  Sx (x ekseni için) ya da Sy (y ekseni için) oluyor. Sonrasında da lx ve ly'nin mutlak değerleri toplanıyor.






En son olarak da l belirlenen eşik ile karşılaştırılıp büyük çıkarsa kenar olarak işaretleniyor.



Bunun gibi bir başka şablon metododu da Kirsch metodu, o da bununla aynı mantıkla çalışmakla beraber 2 yerine 8 adet şablon kullanıyor: sol-sağ, aşağı-yukarı, sol üst-sol alt, sağ üst-sağ alt. Resmin her pikseli için 8 şablon uygulanıyor ve aralarından en yüksek olanı eşik değeri ile karşılaştırılıyor.

Kod:

C# dilinde örnek kod:


           public Bitmap sinirbul(Bitmap resim)
            {
                Bitmap ret = new Bitmap(resim.Width, resim.Height);
                for (int i = 1; i < resim.Width - 1; i++)
                {
                    for (int j = 1; j < resim.Height - 1; j++)
                    {
                        Color cr = resim.GetPixel(i + 1, j);
                        Color cl = resim.GetPixel(i - 1, j);
                        Color cu = resim.GetPixel(i, j - 1);
                        Color cd = resim.GetPixel(i, j + 1);
                        Color cld = resim.GetPixel(i - 1, j + 1);
                        Color clu = resim.GetPixel(i - 1, j - 1);
                        Color crd = resim.GetPixel(i + 1, j + 1);
                        Color cru = resim.GetPixel(i + 1, j - 1);
                        int power = getMaxD(cr.R, cl.R, cu.R, cd.R, cld.R, clu.R, cru.R, crd.R);
                        if (power > 50)
                            ret.SetPixel(i, j, Color.Yellow);
                        else
                            ret.SetPixel(i, j, Color.Black);
                    }
                }
                return ret;
            }
            private int getD(int cr, int cl, int cu, int cd, int cld, int clu, int cru, int crd, int[,] matrix)
            {
                return Math.Abs(matrix[0, 0] * clu + matrix[0, 1] * cu + matrix[0, 2] * cru
                   + matrix[1, 0] * cl + matrix[1, 2] * cr
                      + matrix[2, 0] * cld + matrix[2, 1] * cd + matrix[2, 2] * crd);
            }
            private int getMaxD(int cr, int cl, int cu, int cd, int cld, int clu, int cru, int crd)
            {
                int max = int.MinValue;
                for (int i = 0; i < templates.Count; i++)
                {
                    int newVal = getD(cr, cl, cu, cd, cld, clu, cru, crd, templates[i]);
                    if (newVal > max)
                        max = newVal;
                }
                return max;
            }

        
        
        
        private List<int[,]> templates = new List<int[,]> 
{
   new int[,] {{ -3, -3, 5 }, { -3, 0, 5 }, { -3, -3, 5 } },
   new int[,] {{ -3, 5, 5 }, { -3, 0, 5 }, { -3, -3, -3 } },
   new int[,] {{ 5, 5, 5 }, { -3, 0, -3 }, { -3, -3, -3 } },
   new int[,] {{ 5, 5, -3 }, { 5, 0, -3 }, { -3, -3, -3 } },
   new int[,] {{ 5, -3, -3 }, { 5, 0, -3 }, { 5, -3, -3 } },
   new int[,] {{ -3, -3, -3 }, { 5, 0, -3 }, { 5, 5, -3 } },
   new int[,] {{ -3, -3, -3 }, { -3, 0, -3 }, { 5, 5, 5 } },
   new int[,] {{ -3, -3, -3 }, { -3, 0, 5 }, { -3, 5, 5 } }
};

Hazır program : http://sdrv.ms/1bQoZxX

Sonuç:




Bir başka yazıda görüşmek üzere.

11 Kasım 2013 Pazartesi

Resim işleme - Komşu pikseller yardımı ile kenar bulma algoritması

Resmin Kenarlarını Bulma Yöntemi

Merhabalar, bu gün projelerinizde kullanabileceğiniz bir kenar bulma metodunu anlatacağım.

Metodun Çalışma Mantığı

Siyah beyaz bir resimde kenar bulma işlemi piksellerdeki ani parlaklık değişimlerinden yola çıkarak yapılır. Beyaz bir arkaplan üzerinde siyah bir kare resmi hayal edelim. Karenin sol kenarının sol tarafındaki piksel beyaz, bu pikselin sağ tarafındaki piksel ise siyah olacak. Böyle bir durumda bu pikseli bir kenar olarak işaretleyebiliriz.


Resimde yukarıda anlattığımız metod ile kenarları belirlenmiş ve kenar pikselleri kırmızı olarak işaretlenmiş kareyi görüyorsunuz.


Renkli resimlerde de parlaklık farkı yerine piksellerin komşularından herhangi veya her kanaldaki (R,G,B renk kanallarından bahsediyorum) renk farklılığından yola çıkarak kenar algılama işlemini gerçekleştirebiliriz.

Matematiksel Kısım (basitleştirilmiş halde)


Kenarları tespit etmek için piksellerin komşu piksellere göre farklılık seviyesini kullanıyoruz.  (x,y) şeklinde koordinatları verilmiş olan pikselimizin parlaklığına A(x,y) dersek değişimi hesaplamak için formülümüz şöyle olur.;








Formülde pikselin dört bir tarafındaki komşularının parlaklığını baz alarak pikselin kenar olup olmadığına karar veriyoruz (x+1,y pikselin sağ komşusu, x-1,y  pikselin sol komşusu x,y+1  pikselin  alt komşusu, x,y-1  pikselin üst komşusu).


Ortaya çıkan G değeri, değişim derecemiz oluyor. Bu derece bizim belirlediğimiz belirli bir eşikten yüksekteyse söz konusu pikseli kenar olarak işaretliyoruz. Bu eşik resmin netliğine göre el ile ayarlandığında en sağlıklı sonuç elde ediliyor.


Programlama Kısmı


Aşağıda C# dilinde yazılmış, resmin RGB kanallarından red (kırmızı) kanalı üzerinde yukarıdaki yöntemi kullanarak çalışan bir fonksiyon var. Kodda eşiği 14 değerine sabitledim fakat ihtiyacınıza göre değiştirebilirsiniz.

private Bitmap sinirbul(Bitmap resim)
{
Bitmap ret = new Bitmap(resim.Width, resim.Height);
for (int i = 1; i < resim.Width - 1; i++)
{
for (int j = 1; j < resim.Height - 1; j++)
{
Color cr = resim.GetPixel(i + 1, j);
Color cl = resim.GetPixel(i - 1, j);
Color cu = resim.GetPixel(i, j - 1);
Color cd = resim.GetPixel(i, j + 1);
int dx = cr.R - cl.R;
int dy = cd.R - cu.R;
double power = Math.Sqrt(dx * dx / 4 + dy * dy / 4);
if (power > 14)
ret.SetPixel(i, j, Color.Yellow);
else
ret.SetPixel(i, j, Color.Black);
}
}
  return ret;
}

Sonuç 


Bir sonraki yazımda daha gelişmiş bir algoritma kullanarak daha etkili sonuçlar elde edeceğiz :) beklemede kalın.