Özet
Bu makalemizde bir Windows form içindeki resme parlaklık arttırıp azaltmayı inceleyeceğiz. Bunun için .net içindeki kütüphanelerden de faydalanabiliriz veya kendimizde çözüm geliştirebiliriz. Bu makalede her ikisine de değinilecektir.
GDI+ Nedir ?
.Net içindeki gelişmiş kütüphanelerden biridir. System.Drawing sınıfını desteklemektedir. Bu sınıf aracılığıyla projelerimiz içinde görsel uygulamalar oluşturabiliriz.
GDI+ içindeki tüm sınıflar 6 tane isim uzayında toplanmıştır.
System.Drawing
System.Drawing.Desing
System.Drawing.Printing
System.Drawing.Imaging
System.Drawing.Drawing2D
System.Drawing.Text
Design

1 Adet TextBox ( Name : txtDeger )
1 Adet Buton ( Name : btnParlat , Text : parlat )
1 Adet Buton ( Name : btnEski_hali , Text : eski hali )
1 Adet PictureBox ( Name : picResim1 )
1 Adet PictureBox ( Name : picResim2 )
1 Adet ProgressBar ( Name : progressBar1 )
Burada uygulamamızı öncelikle GDI+ kütüphanesini kullanarak hazırlayacağız. Bu kısımda dikkate edeceğimiz 2 önemli fonksiyon var.
SetPixel (x,y)
GetPixel (x,y)
Şimdi basit anlamda bu iki fonksiyondan bahsedelim. GetPixel(x,y) fonksiyonu sayesinde x ve y kooridatlarındaki renge ulaşmamız mümkün. Daha sonra biz bu renk tonunun RED , BLUE ve GREEN kısımlarını çekip (tabi bunları integere çevireceğiz) bunlara bizim vereceğimiz değeri ekleyeceğiz. Bu sayede resmimize parlaklık özelliği kazandıracağız veya kullanıcının girdiği değer negatif bir sayı ise bu sefer resmimiz o ölçüde kararacaktır.
GetPixel(x,y,color) : Bu fonksiyonumuz ise bize x , y koordinatlarındaki rengimizin ?color? olarak değişmesiniz sağlıyoruz. Veya değişmesi değilde direk color olarak hazırlıyoruz.
Şimdi dilerseniz hemen kodlarımızı yazıp inceleyelim.
public void resim_isle()
{
progressBar1.Visible = true;
int sayi = Convert.ToInt16(txtDeger.Text);
int i, j;
Color renk1;
Bitmap bmp = new Bitmap(picResim1.Image);
int r, g, b;
progressBar1.Maximum = bmp.Width * bmp.Height;
for (i = 0; i < bmp.Height -1; i++)
{
for (j = 0; j < bmp.Width -1; j++)
{
renk1 = bmp.GetPixel(j, i);
r = (int)(renk1.R + (sayi ));
g = (int)(renk1.G + (sayi ));
b = (int)(renk1.B + (sayi ));
if (r > 255)
r = 255;
if (r < 0)
r = 0;
if (g > 255)
g = 255;
if (g < 0)
g = 0;
if (b > 255)
b = 255;
if (b < 0)
b = 0;
renk1 = Color.FromArgb(r, g, b);
bmp.SetPixel(j, i, renk1);
if ((i % 10) == 0)
{
progressBar1.Value = i * bmp.Height + j;
}
}
}
picResim2.Image = bmp;
progressBar1.Visible = false;
}
Gördüğünüz gibi parametre almayan bir fonksiyon hazırladık. Bu iş parçacığımız bize az öncede dediğim gibi GetPixel() fonksiyonu ile belirlediğimiz koordinatlardaki renkleri çekiyoruz ve Color renk1; bu değişkenimize atıyoruz. Bu değişkene atma amacımız ise daha sonradan bu renge ait BLUE , RED ve GREEN değerlerine ulaşacak olmamızdır. Bu değerlerede ulaşıp kullanıcıdan aldığımız değeri üzerine ekleyeceğiz. Daha sonra elimize r,g,b isminde int değişkenleri geldi. Şimdide bunları yine color veritipindeki değişkenimize şu kod satırı ile atıyoruz.
renk1 = Color.FromArgb(r, g, b);
İşte bu artık bizim yeni oluşturmuş olduğumuz renk tonudur. Yani o koordinata ait yeni rengimiz. Peki bu yeni rengimizi eskisiyle nasıl değiştirebiliri şeklinde sorabilirsiniz. Bunuda şu kod satırı ile hallediyoruz.
bmp.SetPixel(j, i, renk1);
İşte gene en baştada belirtmiş olduğum fonksiyonlardan biri olan GetPixl() fonksiyonu o koordinatlardaki rengi değiştirmiş oldu. Artık şuanda resmimizin ilk koordinatlarındaki rengi kullanıcının istediği ölçüde tonunu ayarladık. Bu döngü bitene kadar süreceği için ve resmimizin çözünürlüğüne göre uzun sürebilir. Çünkü burada direk resim üzerinden işlem yapılmaktadır. Aşağıdaki gibi sonucu görebilirsiniz.

Şimdide aynı uygulamanın çok daha hızlı şekilde gerçekleşen halini yapalım. Bu kısımda byte[] dizisi kullanacağız.
(Bu kısma ait kodların yazılıp derlenebilmesi için unsafe kod yazımını aktif duruma getirmeniz gerekmektedir. Aşağıdaki adımları inceleyin?)
Solution Explorer kısmından projenizi sein sağ tıklayın ve properties kısmına tıklayın. Açılan bölümden Build tabına geçin. Allow unsafe code checkboxın seçili olduğundan emin olun ve pencereyi kapatın.

Şimdi kodlarımızı yazalım ve manasını açıklamaya çalışalım.
public static Bitmap Brightness(Bitmap b, int nBrightness)
{
if (nBrightness < -255 || nBrightness > 255)
return b;
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
int nVal = 0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - b.Width * 3;
int nWidth = b.Width * 3;
for (int y = 0; y < b.Height; ++y)
{
for (int x = 0; x < nWidth; ++x)
{
nVal = (int)(p[0] + nBrightness);
if (nVal < 0) nVal = 0;
if (nVal > 255) nVal = 255;
p[0] = (byte)nVal;
++p;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return b;
}
Gördüğünüz gibi fonksiyonumuz Bitmap veritipinde bir değişken ve birde kullanıcının gireceği değeri alıyor. Bu parametreleri bu fonksiyona yolladığımızda bunlar işlenip bize aynı bitmapın parlatılmış hali yollanıyor. Burada dikkat edeceğiniz en önemli kısım Setpixel() ve GetPixel() fonksiyonlarının kullanılmamış olması ve bunların yerine dizilerin kullanılmış olduğudur.
p[0] = (byte)nVal;
gördüğünüz gibi GetPixel() fonksiyonunun yaptığı iş burada byte[0] dizisi ile sağlanıyor. Dizilerle yapılan bu işlem bir önceki yapılan uygulamaya göre inanılmaz derecede hız sağlıyor.
30 MB bir resim üzerinde denedim çok kısa süre içinde resmi istediğim değerde parlattı. Bunu diğer uygulama ile yapmaya çalışırsanız çok uzun sürecektir ve zaten diğer yöntemi kullanmanın pek mantıklı olduğunu düşünmüyorum. Bu her iki uygulamayı da kodlarıyla birlikte aşağıdaki linkten indirebilirsiniz. Her ikisi de aynı proje içindedir dolayısıyla fonksiyonlardan birini commentleyip ikisini de test edebilirsiniz.
Makaleye ait örnek uygulamayı indirmek için tıklayın.