msHOWTO

21 Şubat 2017 Salı

IIS Server Üzerinde WCF Service Yayınlamak İçin (The remote server returned an unexpected response: (405) Method Not Allowed.)

Merhabalar ,

Wcf service'inizi web site a dönüştürdükten sonra eğer server üzerinde daha önceden wcf service yayınlanmadıysa aşağıdaki konutu command prompt üzerinde çalıştırmanız gerekmektedir.

c:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe -i

22 Eylül 2016 Perşembe

Windows Form Application System Security Exception

Merhaba değerli okurlar,

Bu makalemde sizlere bir hafta öncesinde karşılaştığım bir sorunun senaryosunu ve çözümünü anlatacağım. Dilerim böyle bir senaryo ile karşılaştığınızda bu makaleye kolay ulaşmış ve sorunu hızlı bir şekilde çözmüş olursunuz.

Senaryomuz şu şekilde ;

Bir tane windows form uygulaması yazdınız ve bu uygulama gerek server makinada gerekse herhangi bir pc üzerinde kurulu çalışmaya hazır olsun. Fakat bu uygulamayı bir çok sağladığı avantajlardan dolayı bu pc/server üzerinden paylaşıma açıyorsunuz ve client pc ler paylaşımda olan exe yi kendi makinaları üzerinde kısayol olarak ayarlayıp çalıştırıyorlar. Buraya kadar herşey çok güzel. Ne var ki bunda çalıştıramazlar mı yani ? Elbette ki çalıştırabilirler. Fakat eğer bu uygulama üzerinde reflection kullanarak başka bir uygulamayı (gene kendi yazdığınız uygulamayı) ayağa kaldırmaya çalıştığınız zaman bizim karşılaştığımız hatayı "System security exception" alabilirsiniz. Böyle bir durumda iki farklı yoldan çözüme ulaşabilirsiniz.

Çözümler ise şu şekildedir ;

1-) AppDomain kavramını çok iyi anlamanız gerekiyor. Malesef bu makalede bu konuyu anlatmayacağım. Bir çok kaynaktan bu bilgiye rahatlıkla ulaşabilirsiniz. AppDomain'i iyi bir şekilde öğrendikten sonra  reflection kullanarak açtığını uygulamayı yeni bir appDomain oluşturup onun üzerinden açabilir ve o oluşturulan appDomain'e istediğiniz şekilde Permission'lar set edebilirsiniz. Bu yöntem biraz sancılı ve çok iyi bir şekilde tasarlanıp kodlanması gerekmektedir. Diğer yöntem daha kolay olduğu için ben aşağıda anlatacağım çözüm yoluna gittim.

2-) Bu senaryo da daha önceden çözüm olarak Yönetimsel Araçlar da bulunan .Net Configuration Tool u üzerinden Intranet,Computer ve diğer sekmelerde Full Trust yetkisi veriyorduk. Windows 10 üzerinde bu tool (.net 3.5 için) bulunmamaktadır. Bu yüzden tool kullanarak Full Trust veremedik. Yaptığım araştırmalar sonucunda Command Promt kullanarak da bu işlemi yapabildiğimizi öğrendim. Yapılması gerekenler sırasıyla şu şekildedir ;


  • Command Promt'u yönetici olarak çalıştırın ve aşağıdaki kodları sırasıyla yazıp çalıştırın.
  • cd %windows un kurulu olduğu disk adı %:\Windows\Microsoft.NET\Framework\v2.0.50727
  •  caspol.exe -m -ag 1 -url "file://\\%Belediyenet klasorunun bulunduğu serverın ip si%\BelediyeNet\*" FullTrust
  • Eğer windows 64 bit ise aşağıdaki kodları da çalıştırmanız gerekiyor
  • cd %windows un kurulu olduğu disk adı %:\Windows\Microsoft.NET\Framework64\v2.0.50727
  •  caspol.exe -m -ag 1 -url "file://\\%Belediyenet klasorunun bulunduğu serverın ip si%\BelediyeNet\*" FullTrust
Bu işlemlerden sonra uygulamayı yeniden çalıştırdığımızda sorun ortadan kalktı. Umarım sizin sorununuza da çözüm olur.

Bir sonraki makalede görüşmek dileğiyle.

22 Şubat 2016 Pazartesi

Central Authentication Service Entegrasyonu (CAS)


Central Authentication Service Entegrasyonu (CAS)
·         CAS Nedir ?
CAS Single Sign-On hizmetini sağlayan open source bir sistemdir.Birden fazla sistemi CAS ile entegre edip merkezi bir authentication sağlayabilirsiniz. Böylelikle n tane sistem tek bir yerden authentication işlemi yapar ve n tane sistemi tek bir kez authentication işleminden sonra kullanabilirsiniz.
·         CAS Mimarisi

Aşağıdaki Şekil 1 resminde de detaylı incelendiğinde CAS mimarisinin adımları aşağıdaki maddelerde anlatıldığı gibi olduğu görülebilir.
o   Uygulama Get olarak server dan user tarafından çağırılır,
o   Sunucu response olarak CAS ın bulunduğu linkin login sayfasını service parametresi ile birlikte çağırır. Bu service parametresinde kullanıcı CAS üzerinden login olduktan sonra CAS’ın gelen isteği hangi sayfaya yönlendireceğinin bilgisi olmalıdır,
o   Kullanıcının karşısına CAS login ekranı gelir ve kullanıcı login olur,
o   Login işleminden sonra CAS authentication işlemini yapar ,
o   Bir sonraki adım olarak service parametresi olarak verilen linke GET olarak sonuna ticket queryString ini ekleyerek yönlendirme yapar. Bu yonlendırmeden once yapılacak olan isteğin içerisine CASTGC cookie’sini ekler,
o   Daha sonra CAS’ın yönlendirme yaptığı sayfa içerisinde istek ile gelen ticket querystring i ile birlikte CAS’a Get olarak “casserverlink/serviceValidate?ticket=…&service=…”  istek yapılır ve CAS üzerinden gelen ticket bilgisinin validation işlemi yapılır.
o   Bu işlemden sonra CAS’dan xml olarak gelen kullanıcı bilgileri içerisindeki bilgiler alınır ve Cookie lere JSESSIONID olarak asp sessionID atılır,
o   Bu aşamadan sonra artık kullanıcının authentication işlemi tamamlanır.
o   Bir başka uygulamaya ilk erişiminde ise 5.aşamada cookie’ye atılan CASTGC bilgisi request’in cookie bilgisine eklenerek CAS uzerınde validate yapılır ve CAS yeni bir ticket üretir ve querystring ile bizim querystring olarak verdiğimiz service bilgisindeki linke yönlendirme yapar,
o   Yeni oluşan ticket bu şekilde alındıktan sonra 6. Aşama tekrarlanır,



Şekil 1


Asp.Net web form projelerinde CAS 2.0 entegrasyonu çok sıkıntılı bir süreçtir. Asp.Net web form uygulamalarında bulunan page life cycle nedeni ile kullanıcının ilk yaptığı istek CAS'a yapılan yönlendirmeden sonra kaybolmaktadır. Bu durum CAS'ın hazırladığı .Net Library kullanıldığında oluşur. Bu nedenle eğer Asp.Net web form uygulaması ile CAS entegrasyonu yapıyorsanız malesef yapamayacaksınız. İnternet üzerinde CASP.cs class'ına rahatlıkla erişip onun üzerinden işlemlerinizi yapabilirsiniz. Bu class içerisindeki Authenticate methodunu kullanarak authentication işlemini gerçekleştirebilirsiniz. Fakat CAS'ın resmi sitesindeki dökümanları incelediğinizde de göreceksiniz ki CAS tarafından oluşturulan ticket sadece 1 kez validate ettirilir. Bu nedenle bir kez validate işlemi yapıldıktan sonra asp.net uygulamnızda kullanıcı bilgilerini session üzerinde tutarsanız CAS üzerinden kullanıcı login ve validation işlemini yapmış olursunuz. Fakat Bu senaryoda ise kullanıcı CAS uzerınden logout olduğunda , sizin uygulama üzerinde kullanıcı bilgileri session da tutulduğu için single sign out olarak ayarlayamacaksınız. Malesef bu durumu göze almak zorundasınız. 

Uygulamanız üzerinden logout olunduğunda CAS üzerinde de logout olması için tek yapmanız aşağıdaki link'e redirect yapmanız yetecektir.

casserverlinki/logout 

Umarım faydalı olmuştur. Bir sonraki makalemizde görüşmek üzere. 

12 Şubat 2015 Perşembe

NHiberNate ile EmptyInterceptor ve IInterceptor Kullanarak Loglama Nasıl Yapılır ?

Merhabalar değerli okurlar, 
Bugün sizlere NHibernate kullanarak Logging işlemini nasıl yapılabileceğini anlatacağım. Senaryomuzdan hemen bahsetmek istiyorum. Var olan herhangi bir database içerisinde dilediğimiz bir tablo üzerinde yapılan işlemi ve işlemdeki verileri loglamak istediğimizi düşünelim. Alacağımız log bilgilerinde hangi kullanıcının hangi tablo içindeki hangi veri üzerinde hangi işlemi yaptını ve işlem sonucundaki verinin kaydını tuttuğumuzu düşünelim. Oluşturduğumuz senaryo loglama sistemi için şuan yeterli görünmekte. Dilerseniz siz log kayıt bilgilerine istediğiniz bilgiyi ekleyebilirsiniz. 
İlk olarak eğer yapılan işlemi database üzerine yansıtılmadan yakalamak ve ona göre işlem yapmak istiyorsak , ki senaryomuz gereği bunu yapmamız gerekir. Çünkü yapılan işlemi application katmanında her işlemde parametre olarak almaktansa bu şekilde işlem database üzerine yansıtılmadan araya girip yapılan işlemi ve veriyi yakalamak çok daha mantıklı ve profesyonelce durmaktadır. 
Eğer orm olarak NHibernate kullanıyorsak ve yukarıda tanımladığım işlemi yapmak istiyorsak, NHibernate içerisinde bulunan IInterceptor inteface ini incelemek ve bu interface i kendine implemente etmiş olan EmptyInterceptor class ını iyi anlamamız gerekmektedir. IInterceptor interface i içerisindeki methodları incelecek olursak , 

void AfterTransactionBegin(ITransaction tx); // Kullanılan session içerisindeki transaction başladıktan sonra tetiklenen method
void AfterTransactionCompletion(ITransaction tx); // Kullanılan session içerisindeki transaction tamamlandıktan sonra tetiklenen method
void BeforeTransactionCompletion(ITransaction tx); //Kullanılan session içerisindeki transaction tamamlanmadan önce tetiklenen method

....
....
....

Methodların isimlerinden ne zaman tetiklendiği zaten belli olmaktadır. Bizim senaryomuz gereği kullanacağımız methodlar ise ;

void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types); // Entity nin silinmeden önce tetiklenen method
bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types); // Entity nin güncellenmeden önce tetiklenen method
bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types); // Entity nin eklenmeden önce tetiklenen method

EmptyInterceptor class'ına bakacak olursak, IInterceptor interface ini implemente ettiğini ve bu interface içerisindeki methodları virtual olarak hazırladığını görmekteyiz. Bu şu anlama gelmektedir. Eğer ben bu class üzerinden miras alarak kendi class'ımı oluşturursam, OOP mantığı ile hem IInterceptor interface indeki tüm methodları yapabilir hale gelmiş oluyorum, hem de minimum istekleri karşılayıp sadece kendi özel olarak kodlamak istediğim methodları ezerek, yapmak istediğim işleri yapabilir hale geliyorum. OOP'ın bu güzel nimetlerini kullanarak kendi Interceptor class'ımı oluşturup onu adeta bir log class'ı haline sokabilirim. Aynen şu şekilde , 

[Serializable]
public class MyInterceptor : EmptyInterceptor
{
public string _databaseName = "";
public string _kullaniciAdi = "";
public string _sifre = "";
public MyInterceptor(string databaseName,string kullaniciAdi,string sifre)
{
_databaseName = databaseName;
_kullaniciAdi = kullaniciAdi;
_sifre = sifre;
}
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
//  yapılan işlem insert işlemidir ve insert yapılan nesne, property isimleri, tipleri gelmektedir. Bu bilgilerden faydalanarak şu tablo üzerinde şu veri üzerinde şu işlem yapıldı. diyebiliyoruz. Constructure methodunda da kullanıcı adı ve şifre bilgisini alıyorum. İsterseniz sadece kullanıcı bilgisini alabilirsiniz. Tamamen size kalmış bir durum. Tüm bilgileri aldıktan sonra loglama işlemini dilediğimiz gibi yapabiliriz. 

return true;

}

public override void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
//  yapılan işlem delete işlemidir ve delete yapılan nesne, property isimleri, tipleri gelmektedir. Bu bilgilerden faydalanarak şu tablo üzerinde şu veri üzerinde şu işlem yapıldı. diyebiliyoruz. Constructure methodunda da kullanıcı adı ve şifre bilgisini alıyorum. İsterseniz sadece kullanıcı bilgisini alabilirsiniz. Tamamen size kalmış bir durum. Tüm bilgileri aldıktan sonra loglama işlemini dilediğimiz gibi yapabiliriz.
}
public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
{
//  yapılan işlem update işlemidir ve update yapılan nesnenin güncellenmek istenen değerleri ve veri tabanında kayıtlı olan değerleri, property isimleri, tipleri gelmektedir. Bu bilgilerden faydalanarak şu tablo üzerinde şu veri üzerinde şu işlem yapıldı. diyebiliyoruz. Constructure methodunda da kullanıcı adı ve şifre bilgisini alıyorum. İsterseniz sadece kullanıcı bilgisini alabilirsiniz. Tamamen size kalmış bir durum. Tüm bilgileri aldıktan sonra loglama işlemini dilediğimiz gibi yapabiliriz.
return true;
}

}

Evet değerli okurlar, artık Interceptor class'ımız hazır. Tek yapmamız gereken Interceptor class'ımızı session üzerinde tutturmak ve configuration bilgilerine eklemek. Bunun için aşağıdaki kodları yazmamız yeterli olacaktır. 

Configuration cfg = new Configuration();
public MyInterceptor ins = new MyInterceptor ("myLogDatabaseName");
cfg.SetInterceptor(ins);
ISessionFactory factory ;
ISession session;
factory = cfg.BuildSessionFactory();
session = factory.OpenSession(ins);

kodlar yeterli olacaktır. Umarım faydalı olmuştur değerli okurlar.

Bir sonraki makalemde görüşmek üzere. 

Koray Düzgün. MCTS

27 Ocak 2015 Salı

MSSQL Kurulumunda Hata ( code 29506 sql )

Merhabalar arkadaşlar ,

Mssql expres sürümlerinden kurulum yaparken "code 29506" hatası alıyorsanı yapmanız gereken adımlar şunlar olmalıdır ;


  • C:\Windows\System32 içerisinde bulunan cmd.exe yi yönetici olarak çalıştırın ,
  • Sonrasında cd\"kurulum dosyasının bulunduğu dizin" yazıp Enter'a basın
  • Daha sonra kurulum dosyasının tam adını yazın ve Enter'a basın.


Tekrardan kurulum ekranı açılacaktır. Sonrasındaki standart kurulum aşamalarını yaparak kurulumu başarılı bir şekilde tamamlayabilirsiniz.

Umarım faydalı olmuştur.

Bir sonraki makalede görüşmek üzere.

2 Ocak 2015 Cuma

C# ile Captcha Decoding - Mean ve Median Filtre Kullanımı

Merhabalar değerli okurlar ,

bugün sizlerle birlikte biraz resim işleme durumlarını inceleyeceğiz. Senaryomuz, hepimizin bildiği captcha yani resim doğrulama kodlarını otomatik olarak çözümleyip içerisindeki karakterlerin neler olduğunu bize veren bir uygulama hazırlamak olacak. İlk olarak sonuca ulaşmamız için captcha resmindeki kirliliği temizlememiz gerekecek. Kirlilik derken aslında resim içerisindeki karakterlerin zor okunması için hazırlanan desenlerden bahsediyorum. Desen dediğim için gözünüz korkmasın sakın, çünkü aslında desen dediğimiz şey temelinde pixel. Peki aslında her şey resim üzerinde pixel ise, harfler de pixeldir. Harf ve desenleri nasıl ayıracağız ? Bu sorunun çözümü aslında kişiden kişiye değişir. Bunun sebebi de bu soruna çözüm algoritmik olarak verilmektedir. Belirli hazır olan algoritmalar var elbet, fakat her captcha için geçerli değil. Peki bizim yapacağımız da her captcha için geçerli olacak mı ? Ağırlıklı olarak evet geçerli olacak. Çünkü zor bir captcha üzerinde çalıştım. Ama çözümlemeye çalıştığımız captcha'dan daha zor bir captcha verirseniz çözemeyebilir. Baştan söyleyim hazırlıklı olun :) 

Gelelim resim üzerindeki deseni nasıl temizleyeceğiz ? Bu duruma çözüm olarak benim kurmuş olduğum algoritma şu şekildedir. 

1-) Resmi siyah beyaz yap
2-) Resmin 0,0 noktasından başlayarak 3*3 pixel (yani her bir zıplamada 9 pixel) tara.
3-) Alınan 3*3 pixellerin ortalaması belirli bir ortalamadan küçük ise tüm hepsini beyaz yap
4-) Büyük ise orjinal pixel değerlerini koru. 

Bu algoritmada şu sonuç ortaya çıkıyor. Resmi tamamen tarıyorum ve aslında benim için önemli olarak bir mean belirliyorum. Eğer pixellerin ortalama değeri benim belirlediğim ortalama değerden düşük ise o bölgeyi beyaza çevirerek temizlemiş oluyorum. Bu yönteme Image Processing alanı içerisinde Mean Filtering deniliyor. Farklı filtreleme yöntemleri de mevcut. Siz farklı şekilde uygulayabilirsiniz. 

Peki gelelim kod kısmına. Resmi siyah beyaz yapan kod parçacıklarını rahatlıkla bulabilirsiniz. Fakat ben gene de sizinle paylaşıyorum .

     using (var original = new Bitmap(pb1.Image))
            {
                using (var resized = new Bitmap(original/*, new Size(pb1.Image.Width * 8, pb1.Image.Height * 8)*/))
                {
                    original.Dispose();

                    using (var bmp = new Bitmap(resized))
                    {

                        for (int y = 0; y < bmp.Height; y++)
                        {

                            for (int x = 0; x < bmp.Width; x++)
                            {
                                Color eski = bmp.GetPixel(x, y);
                                int ortalama = (eski.R + eski.G + eski.B) / 3;
                                Color yeni = eski;

                                if (ortalama > 213)
                                    yeni = Color.White;
                                else
                                    yeni = Color.Black;
                                bmp.SetPixel(x, y, yeni);

                            }

                        }

                    }


                }

            }

Resmi siyah beyaz yaptıktan sonra sıra geldi kurmuş olduğumuz algoritmanın kodlarına. İşte bu kodlar ,

 private void Maskeleme(Image image, string filename, int size, int ortalama)
        {


            using (var bmp = new Bitmap(image))
            {
                using (var yenibmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb))
                {
                    

                    for (int y = 0; y < bmp.Height; y++)
                    {
                        var baslangicy = y;
                        var bitisy = y + size;
                        if (bmp.Height < bitisy)
                        {
                            bitisy = bmp.Height;
                        }
                        for (int x = 0; x < bmp.Width; x++)
                        {

                            var baslangicx = x;
                            var bitisx = x + size;
                            if (bmp.Width < bitisx)
                            {
                                bitisx = bmp.Width;
                            }

                            var kucukbmp = bmp.Clone(new Rectangle(baslangicx, baslangicy, bitisx - baslangicx, bitisy - baslangicy), System.Drawing.Imaging.PixelFormat.Format32bppRgb);
                            int ortalamaKucuk = 0, toplamRenk = 0;

                            for (int i = 0; i < kucukbmp.Width; i++)
                            {
                                for (int j = 0; j < kucukbmp.Height; j++)
                                {
                                    toplamRenk += (kucukbmp.GetPixel(i, j).R + kucukbmp.GetPixel(i, j).G + kucukbmp.GetPixel(i, j).B) / 3;

                                }
                            }

                            ortalamaKucuk = toplamRenk / (kucukbmp.Height * kucukbmp.Width);

                            if (ortalamaKucuk > ortalama)
                            {
                                for (int i = 0; i < kucukbmp.Width; i++)
                                {
                                    for (int j = 0; j < kucukbmp.Height; j++)
                                    {
                                        yenibmp.SetPixel(baslangicx + i, baslangicy + j, Color.White);
                                    }
                                }
                            }
                            else
                            {
                                for (int i = 0; i < kucukbmp.Width; i++)
                                {
                                    for (int j = 0; j < kucukbmp.Height; j++)
                                    {
                                        yenibmp.SetPixel(baslangicx + i, baslangicy + j, kucukbmp.GetPixel(i, j));
                                    }
                                }
                            }

                            x += (size - 1);
                            if (bitisx == bmp.Width)
                            {
                                break;
                            }
                            //renkler.Add(bmp.GetPixel(x, y));
                        }

                        y += (size - 1);

                        if (bitisy == bmp.Height)
                        {
                            break;
                        }

                    }

                    yenibmp.Save(Application.StartupPath + "\\" + filename); 
                }
                
            }


        }

Maskeleme methodumuzu uyguladıktan sonra bir de Median Filtre uygularsak eğer daha temiz sonuç alırız. Bunun için Aforge kütüphanesi içerisinde bulunan Median filtresini uygulayacağız. Kodlar ;

 private void MedianFilterUygula(string sourceFile, string destinationFile)
        {
            System.Drawing.Bitmap imageX = new Bitmap(Image.FromFile(sourceFile));
            System.Drawing.Bitmap image = AForge.Imaging.Image.Clone(imageX, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            AForge.Imaging.Filters.Median filter = new Median();
            Bitmap newImage = filter.Apply(image);
            newImage.Save(destinationFile);
            pb1.Image = newImage;
            
        }

Peki şimdi resmi siyah beyaz yaptık, maskeleme methodumuz ile desenleri de temizledik. Peki harfleri resim içerisinden nasıl tanıyacağız ? Bu durumda kullanılan en yaygın yöntem her bir karakterin 1 ve 0 olarak haritası ile resim içerisinde eşleştirme yapmak. Fakat bu yöntem ile resim içerisinde karakterler yatay oldukça, sonuç alma ihtimali de azalıyor. Fakat bir çok hazır kütüphane bu yöntemi kullandığı için ve Amerika'yı yeniden keşfetmemek için biz de bu yöntemi kullanacağız.Bu yöntemi kullanan hazır kütüphaneler ise , Aforge , Microsoft Office Document Imaging (MODI) , tesseract , ... Daha gelişmiş olarak ise EmguCV'yi kullanabilirsiniz. 

Biz bu kütüphaneler içerisinden tesseract' ı kullanacağız. Bunun için kodlar aşağıdaki şekilde olmalıdır. 

public Form1()
        {
            InitializeComponent();
            // aşağıdaki kod ile indirmiş olduğumuz tessdata klasörü ile tesseract engine i başlatıyoruz.
            _ocr.Init("tessdata", "eng", Tesseract.OcrEngineMode.OEM_DEFAULT);
            _ocr.SetVariable("tessedit_char_whitelist", "0123456789");

        }

 private void DoOcr(string file)
        {
            var result = "";
            try
            {
                Image<Bgr, Byte> image = new Image<Bgr, byte>(file);

                _ocr.Recognize(image);
                
                var characters = _ocr.GetCharactors();
                foreach (var c in characters)
                {
                    result += c.Text;
                }
                image.Dispose();
                result = Regex.Replace(result, "[^0-9]+", "").Replace('o', '0');

            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            label1.Text = result;
        }

Yukarıdaki DoOcr fonksiyonumuz , verilen captcha resim yolundaki resim içerisindeki harfler detect edip sonuç olarak verir.

Tüm işlemler tamamlandıktan sonra kırmaya çalıştığımız captcha resmi ; 



Siyah beyaz yaptıktan ve maskeleme methodunu uyguladıktan sonra ki hali 



Median filtre uyguladıktan sonraki hali ,



Programın çalışmış ve sonucu vermiş hali ise ,




Referans etmeniz gereken kütüphaneler ise ;



Umarım faydalı olmuştur değerli okurlar. Bir sonraki makalede görüşmek dileğiyle esen kalın, teknoloji ile kalın.

Koray Düzgün 

MCTS