Yazan : Şadi Evren ŞEKER
Temel olarak bir programlama dilinde resim işleme işlemleri için iki fonksiyon gerekir.
- Birinci resmi oluşturan imgecik (pixel) değerlerini okuyabilmek
- İkincisi ise resmin imgecik (pixel) değerlerini değiştirebilmek
Yani aslında resim üzerinde yapılan herşey, resmi oluşturan imgecikler üzerinde yapılmaktadır.
Bu yazıda CSharp programlama dili kullanılarak basit bir histogram çıkarma ve resme gama doğrulaması (Gamma correction, gamma encoding) uygulanması anlatılacaktır.
Öncelikle resim işleme işlemleri sırasında kullanılcak olan arayüzün tasarlanması ile başlayacağız. Basit bir picturebox (resim kutusu) ve üç düğme bu çalışma için yeterli olacaktır. (Düğmelerden birisi resmin histogramı için diğeri de gama doğrulaması için kullanılacak)
Planımız şu şekilde:
Form yüklenince, yani program ilk çalıştığı anda bir dosya açma diyaloğu (open file dialog) belirecek. Kullanıcı bu diyalog ile bir resim dosyası seçecek ve ardından birinci düğme ile histogramı çıkarabilecek ikinci düğme ile de gama doğrulaması yapabilecek.
Bu uygulamada Visual C# 2008 express sürümü kullanılacaktır.
Uygulamanın görsel tasarımı:
Uygulama tasrımı sırasında tek bir form kullanılacaktır. Formu aşağıdaki şekidle tasarlayabilirsiniz:
Yukrıda görüldüğü üzere 3 button ve bir adet picturebox nesnesi forma yerleştirilmiştir. Ayrıca bileşenlerin isimleri yukarıdaki şekilde yazılıdır. Formun görsel tasarımı aşağıda verilmiştir.
yukarıdaki şekilde butonlara isim verdikten sonra kodlamaya başlayabiliriz.
Öncelikle dosya açma diyaloğu için kodumuzu yazalım. Resim yükle isimli buton1 tıklaması için aşağıdaki kodu yazıyoruz:
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter =
“JPEG Dosyaları|*.jpg|Bütün Dosyalar (*.*)|*.*”;
dialog.InitialDirectory = “.”;
dialog.Title = “Bir resim dosyası seçiniz”;
if (dialog.ShowDialog() == DialogResult.OK)
{
pictureBox1.ImageLocation = dialog.FileName;
}
}
Yukarıdaki kodda basit bir dosya açma diyaloğu (open file dialog) kullanılmış ve jpeg dosyaları filitrelenmiştir. Ayrıca dosyanın seçilmesi ve tamam düğmesine basılması sonucunda pictureBox1 nesnesine dosya yüklenmiştir.
Yukarıda, bu kod sonucunda çalışan açma diyaloğu görüntülenmektedir. Kullanıcı bir resim dosyası seçip Aç düğmesine basınca yukarıdaki kodda bulunan if bloğu çalışacak ve açılan dosya pictureBox1 nesnesinde görüntülenecektir:
Yukarıda, örnek olarak açılmış ve görüntülenen bir resim bulunmaktadır.
Histogram çıkarımı
Yukarıdaki form tasarımını bitirdikten sonra resim işleme adımlarımızdan ilki olan histogram çıkarımına başlayabiliriz. Amacımız yukarıdaki bölümde anlatılan resim yükleme işleminin sonunda yüklenen resmin RGB (red green blue, kırmızı yeşil mavi) değerlerine göre histogramını çıkarmaktır.
Histogram çıkarımı ve resim işleme adımlarının hemen hepsinde gereken bir resme imgecik imgecik (pixel) erişmeyi sağlayan, C# altındaki bitmap sınıfıdır. Bu sınıfı kullanabilmek için öncelikle picturebox içerisinde yüklü olan resmi bitmap’e çevirmemiz gerekir.
Bu işlemler için tasarımımızdaki ikinci düğmeyi kullanıyoruz ve düğmenin arkasını aşağıdaki kodu yazıyoruz:
private void button2_Click(object sender, EventArgs e)
{
Image img = pictureBox1.Image;
Bitmap bmp = new Bitmap(img);
int[] kirmizi = new int[256];
int[] yesil = new int[256];
int[] mavi = new int[256];
for (int i = 0; i < bmp.Size.Height; i++)
for (int j = 0; j < bmp.Size.Width; j++)
{
Color renk = bmp.GetPixel(i, j);
kirmizi[renk.R]++;
yesil[renk.G]++;
mavi[renk.B]++;
}
Yukarıdaki kodda basitçe bir bitmap sınıfından (class) bmp isimli bir nesne (object) tanımlanmıştır. Bunun için öncelikle pictureBox nesnesinden Image değeri alınmış sonra bu Image değeri bir bitmap’e yüklenmiştir.
Ardından 3 adet dizi tanımlıyoruz. Bu diziler sırasıyla işleyeceğimiz imgeciklerin (pixel) kirmizi, yesil ve mavi değerlerini okuyacak dizilerdir. Yani resmimizdeki her imgeciğin sahip olduğu kırmızı değeri için, o değerin dizideki sayısını 1 arttırıyoruz. Burada bilinmesi gereken bir nokta bitmap resimlerde bir renk kodu 0 ile 255 arasında bir değerdir. Dolayısıyla dizilerimiz 256 boyutunda tanımlanmıştır ve sonuçta her imgeciğin sahip olduğu kırmızı kodu kirmizi dizisindeki ilgili değeri bir arttırmaktadır. Bu durum diğer renkler içinde geçerlidir.
Kodun devamında dosyaya kaydetme işlemlerini yazıyoruz:
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = “.”;
sfd.Title = “Histogramin kaydedilecegi dosyayi belirtin”;
if (sfd.ShowDialog() == DialogResult.OK)
{
StreamWriter fwriter =
File.CreateText(sfd.FileName);
for (int i = 0; i < 256; i++)
{
fwriter.Write(“” + kirmizi[i] + “|” + yesil[i] + ” | ” + mavi[i] + “n”);
}
fwriter.Close();
}
Yukarıdaki kod basit bir şekilde bir savefiledialog oluşturuyor yani dosyanın kaydedileceği yeri ve ismi alıyor. Kullanıcı tamam düğmesine bastıktan sonra bir StreamWriter ile dosyayı açıyor ve içerisine dizimizdeki değerleri satır satır basıyrouz.
Yukarıdaki kodun çalışması sırasında dosya işlemleri ile ilgili System.io paketinin yüklü olması gerekir bunun için kodun başına
using System.io;
satırını eklemeyi unutmayınız.
Yukarıdaki diyalogta ben “deneme.txt” dosyası ismi verdim ve histogram değerleri bu dosyanın içerisine kaydedildi. Yüklü olan resme göre aşağıdakine benzer bir sonuç çıkabilir:
Yukarıdaki dosyada 256 adet satır bulunmaktadır ve kodumuzdan da hatırlanacağı üzere her satır ilgili renk kodunun değerini tutmaktadır.
Örneğin kırmızı değerinin 0 olduğu 3297 imgecik bulunduğunu yukarıdaki dosyadan anlayabiliyoruz.
Dosyadaki bu değerleri excel programı ile çizdiğimizde yukarıdakine benzer bir grafik çıkıyor. Bu grafik ve değerler kullanılan resim için farklılık gösterebilir. Sonuçta her resimdeki renk değerlerinin dağılımı farklı olacaktır.
Programın buraya kadar olan kısmını içeren csharp projesini yukarıdaki bağlantıya tıklayarak indirebilirsiniz.
Öncelikle güzel anlatımın için tşkrlr.. mükemmel bi şekilde hem çok güzel ve açıklayıcı, hemde çok sade bi şekilde konuyu kavratan bir örnek vermişsin..
ama siteye yazdığın
Color renk = bmp.GetPixel(i, j);
kod satırında hata verior program. Doğrusu
Color renk = bmp.GetPixel(j, i); şeklinde olmalı. Yanlışı debug ile çalışırken buldum ama kodun doğrusunu senin indirmek için linkini verdiğin proje dosyasından karşılaştırırken buldum.. proje dosyasını indirmeden projeyi sitedeki kodlardan yapan arkadaşlar bu hatayı düzelterek yaparlarsa sorunsuz çalışıor program..
Acaba piksel değerlerini ayrı ayrı dizinin içerisine nasıl atabiliriz.Yardımcı olabilir misiniz?
Sorunun cevabı zaten yukarıdaki bulunuyor.
Color renk = bmp.GetPixel(i, j);
şeklindeki satırda geçen komut ile ilgili pikselin (i,j koordinatlarındaki) değerini renk olarak okursunuz. Daha sonra bunu istediğiniz bir diziye atabilirsiniz. Örnek kodu aşağıda veriyorum:
Color dizi[][] = new Color[bmp.Size.Height][bmp.Size.Width];
for(int i = 0;i
hocam form arka planda kalınca çalışmıyor bu konuda bir öneriniz var mı
saygılarımla
iyi gunler kolay gelsın..bırsey sorablıır mıyım acaba pıksel pıksel alıp o pıksellerı karsılastırma ımkanımız var mı ? varsa nasıl yapılıyor bıraaz yardımcı olabılırmısınız rıca etsem..bırde java bılgısı olan benımle ıletısıme gecerse sevınırım..rcpszn1001@gmail.com maıl adresım bana yardımcı olabılecek varsa cok ama cok sevınırım sımdıden kolay gelsın tekrar ıyı aksamlar..