17 Mart 2009 Salı

Görüntü İşleme (C#)

Görüntü İşleme (C#): "Görüntü İşleme : Ölçülmüş veya kaydedilmiş olan elektronik (dijital) görüntü verilerini, elektronik ortamda (bilgisayar ve yazılımlar yardımı ile) amaca uygun şekilde değiştirmeye yönelik olarak yapılan bilgisayar çalışması.
Bir görüntü gözek(pixel)lerden, gözeklerde kırmızı(R)-yeşil(G)-mavi(B) renk değerlerinden oluşur. Gözeklerin rengi RGB olarak üç ana rengin birleşimi şeklinde ifade edilir. R-G-B renk değerleri 0 ila 255 arasında değişir. 0 en koyu ton iken 255 e gittikçe açılır. Örneğin mavi rengin değeri :(0,0,255) kırmızın :(255,0,0) ve yeşilin de :(0,255,0) dir. Diğer renkler bu değerlerin değişmesi ile elde edilir. Artı olarak 32bitlik bir görüntünün gözekleri 4 kısından oluşur ve 4 kısımda görüntüye saydamlık derecesini veren 'Alpha' kanalıdır.

Görüntünün bir satırda bulundurduğu gözeklerin sayısı o görüntünün genişliğini(width), satır sayısıda o resmin boyunu(height) verir.Boyutlarda (800x600), (1024x768) gibi iki değerli şeklinde yazılır. Bu değerlerden ilki görüntünün genişliğini, ikinci değer ise boyunu verir.

C# ile görüntü işlemek için bir çok yöntem mevcut olmasına rağmen daha hızlı bir yöntem olduğu için pointer kullanacağım. Kullandığım yöntemin ana kalıbı aşağıdaki gibidir.

24bitlik format için ;

public Bitmap griton(Bitmap resim)
{
unsafe
{
BitmapData bmpdata = resim.LockBits(new Rectangle(0, 0, resim.Width, resim.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

byte* p = (byte*)bmpdata.Scan0;
int atıl = bmpdata.Width*3 - bmpdata.Stride;

for (int i = 0; i < bmpdata.Height; i++)
{
for (int h = 0; h < bmpdata.Width; h++)
{
byte ort = Convert.ToByte((p[0] + p[1] + p[2]) / 3);
p[0] = p[1] = p[2] = ort;
p += 3;
}
p += atıl;
}

resim.UnlockBits(bmpdata);

return resim;
}
}

32bitlik format için ;

public Bitmap griton(Bitmap resim)
{
unsafe
{
BitmapData bmpdata = resim.LockBits(new Rectangle(0, 0, resim.Width, resim.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

byte* p = (byte*)bmpdata.Scan0;

for (int i = 0; i < bmpdata.Height; i++)
{
for (int h = 0; h < bmpdata.Width; h++)
{
byte ort = Convert.ToByte((p[0] + p[1] + p[2]) / 3);
p[0] = p[1] = p[2] = ort;
p += 4;
}
}

resim.UnlockBits(bmpdata);

return resim;
}
}

Dikkat ettiyseniz 24bitlik formatın aksine burada atıl oluşmamaktadır.

Kodları unsafe bloğunun içinde yazabileceğimiz gibi metodu aşağıdaki gibi de tanımlayabiliriz.

public unsafe Bitmap griton(Bitmap resim)
{
BitmapData bmpdata ...
....
}

Yukarıdaki kodları satır satır açıklarsak;

İlk olarak pointerlar olarak çalışacağımız için kodları 'unsafe' bloğu içinde yazmalıyız veya metodu tanımlarken 'unsafe' özlelliğini kullanmalıyız. Yalnız projemizde unsafe komutunu kullanabilmemiz için öncelikli olarak projenin ayarlarından unsafe kullanımına izin vermeliyiz. Bunun için, 'Project' menüsünden, '[Proje ismi] Properties', açılan pencerede 'Build' seçeneğine girip 'Allow unsafe code' seçeneğini aktif hale getiriyoruz.

BitmapData bmpdata = resim.LockBits(new Rectangle(0, 0, resim.Width, resim.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

Resmin bitlerini ramde kitleyerek üzerinde işlem yapabilceğimiz hale getiriyor. Aldığı parametreler ;

'new Rectangle(0, 0, resim.Width, resim.Height) ' , resmin üzerinde işlem yapılacak alanı belirtir. Yazıldığı şekilde, resmin (0,0) noktasında sonuna kadar tüm alanı kullanır.

'ImageLockMode.ReadWrite' , kilitli alan üzerinde işlem izni. '.ReadWrite' hem okumaya hem yazmaya, '.ReadOnly' adından da anlaşılacağı gibi sadece okurken, '.WriteOnly' sadece yazmaya izin verir.

'PixelFormat.Format24bppRgb' kilitli alanın kullanacağı formatı belirtir.Genel olarak '.Format32bppArgb' ve '.Format24bppRgb formatları kullanılmaktadır. 32 bit formatın 24 formata göre farkı, bir gözekin 3 (r-g-b) yerine 4 (r-g-b-a) parçası olması.

byte* p = (byte*)bmpdata.Scan0;



Ram üzerinde bir gözek ilerlemek.

Bu komut ile kilitli bellek alanının ilk noktasına ulaşılmaktadır. p=p[0] ilk noktayı verirken p[1] bir sonraki vermektedir. Eğer p yi bir artırırsak p[0] artık 2. noktayı verirken p[1] 3. noktayı verir. Gözeklerin renk değerlerine ulaşmak için, eğer p değeri gözeğin başındaysa p[0] o gözeğin mavi(b), p[1] yeşil(g) ve p[3] de kırmızı(r) bileşenini vermektedir. Dikkat ettiysenin dizilimler standart r-g-b diziliminin tersine bellekte b-g-r (mavi-yeşil-kırmızı) şeklinde dizilmiştir. Eğer 32bit formatını seçtiysenin, p[3] değeri bize o gözekin saydamlık derecesini verir. Tam görünür bir gözek için bu değer255 , hiç görünmemesi içinde bu değer 0'a ayarlanır.

Görüntü üzerinde gözek gözek yapılacak (noktasal) işlemler için (parlaklık, gri ton, negatif gibi) tüm gözekleri dolaşacak şekilde içiçe iki döngü yapıyoruz. İçteki döngü bir satırın tüm gözeklerini dolaşırken, dıştaki döngü hangi satırda olduğumuzu belirliyor. Satır içinde dolaştığımız için bir gözekle işimiz bittiğinde bir sonraki gözeke geçmek için iç döngüde p'yi 3 artırıyoruz(32bit te 4). Bir satır bittiğinde de dıştaki döngünün sonunda p'ye atılı ekliyoruz(sadece 24bit için).

resim.UnlockBits(bmpdata);


Burada ise daha önce ram üzerinde kilitleyip üzerinde işlemler yaptığımız bellek alanını resme geri atıyoruz.

Burada anlatılanları uygulamak için ufak bir uygulama ve çeşitli Gİ örnekleri Kod Kütüphanesinde yayınlanacaktır...."
kaynak :http://www.farukterzioglu.com

3 yorum:

  1. Kaynak gösterdiğiniz! için teşekkürler.
    http://www.farukterzioglu.com

    YanıtlaSil
  2. faruk sende kaynak göstersen fena olmaz hani...
    dikkat çekmek için yorum eklemişin

    YanıtlaSil
  3. kaynak ekledim kusura bakmayın. Unutulmuş.
    ana kaynağı neredeyse orayı ekleyebilirim.
    çok güzel bir yazı tşk

    YanıtlaSil