Makale Özeti

Tüm yazılımcı arkadaşlara selamlar, C# ile el yazısını tanımakla ilgili bu ikinci makalemde ilk önce algoritmanın geliştirilmiş sürümünü ardından bu algoritmayı kullanarak diger Windows uygulamalarıyla entegre çalışacak bir Windows uygulamasını nasıl geliştirileceğimizden bahsedeceğim.

Makale

Tüm yazılımcı arkadaşlara selamlar,

C# ile el yazısını tanımakla ilgili bu ikinci makalemde ilk önce algoritmanın geliştirilmiş sürümünü ardından bu algoritmayı kullanarak diger Windows uygulamalarıyla entegre çalışacak bir Windows uygulamasını nasıl geliştirileceğimizden bahsedeceğim.

Algoritma (sürüm 2.0)
Hatırlarsanız algoritmanın ilk sürümünde çevrimiçi el yazısını, kullanıcının gittiği yönleri saptayarak tanıyorduk.Fakat bu algoritma D ve P gibi harflerde hatalı tanımaya yol açabiliyordu.
 


Bu gibi hatalı tanımlamaları engellemek için "bağlantı haritası" adı altında bir tanımlama elemanı daha geliştirdik.Bu yöntemde çizilen bütün çizgilerin başlangıç ve bitiş noktalarını numaralandırarak bir bağlantı haritası elde ediyoruz.
 

D harfini çizmek için ilk önce dikey bir çizgi çiziyoruz.İlk çizginin başlangıç noktasına 1, bitiş noktasına 2 değerini veriyoruz ve çizeceğimiz diğer noktalar için bu işlemi tekrarlıyoruz.

Bağlantı Haritasını Hesaplamak
D harfi 2 çizgiden oluşmaktadır.Bağlantı haritasını oluştururken ilk çizginin başlangıç noktasını es geçiyoruz(İlk nokta olduğundan dolayı herhangi bir çizgiyle bağlantısı olamaz), bitiş noktası diğer başlangıç ve bitiş noktalarına belli bir oranda yakın ise o noktaların numaraları bağlantı haritasına eklenir.D harfinin ilk çizgisinin bitiş noktası, diğer bir başlangıç ve bitiş noktasına yakın olmadığı için bağlantı haritasına 0 değerini ekliyoruz.
 


D harfinin ikinci çizgisini çizelim.Dikkat ederseniz ikinci çizginin başlangıç noktası ilk çizginin başlangıç noktasına yakın.Dolayısı ile bağlantı haritasına 1 değerini ekliyoruz.İkinci çizginin bitiş noktası ise, ilk çizginin bitiş noktasına yakın olduğundan bağlantı haritasına 2 değerini ekliyoruz.

Sonuç olarak D harfinin bağlantı noktası 0|1|2 değerini alıyor.

P harfinin yön değeri D harfiyle aynı  olmasına rağmen (2324) bu iki harfi bağlantı haritası değerlerini kullanarak ayırabiliriz.P harfinde ikinci çizgi bitiş noktası herhangi bir başlangıç veya bitiş noktasına yakınlık göstermediğinden dolayı P harfinin bağlantı haritasının son hanesi 0 değerini alır.Böylece P harfinin bağlantı haritası 0|1|0 değerini alır.

Kullanıcı Arayüzü
Kullanıcı arayüzü olarak kullanıcının harfi yazabileceği bir pictureBox kontrolü, tanınan harfin yazılacağı bir textBox kontrolü, tanınan harfin işletim sisteminde çalışan başka bir prosese gönderilmesi için bir checkBox,comboBox ve bir Button kontrolü, kullanıcı yazı yazarken seçilen diğer prosesin görüntülenmesi için şeffaflık ayarı için trackbar kontrolü kullanacağız.
 


Herzaman uygulamamıza erişebilmek için notifyIcon kontrolü kullanarak uygulamamızı SystemTray uygulaması olarak geliştireceğiz.
 


Kişiselleştirilebilir Tanıma Sistemi
Geliştirdiğimiz ilk sürümde harfleri temsil eden yön değerlerini kod içerisinde ifade etmiştik.Bu sürümde ise tanıma değerleri olan yön ve bağlantı haritası bilgilerini bir metin dosyasindan okuyacağız.Ayrıca bu sayede uygulamanın tanıyamadığı harfleri kullanıcının tanımlayabilmesini sağayarak, kullanıcıya özel bir tanıma dosyası geliştirebileceğiz.

Format aşağıdaki gibi olacaktır.

Yön bilgisi#Bağlantı Haritası#Tanınacak Harf
2324
#0|1|2|#D

 

Kullanacağımız Yapılar ve Değişkenler
HWOCRCharRecognition : Daha önceden kaydettiğimiz bir harf tanımlama dosyasını bu yapıyı kullanarak saklayıp, tanımlama esnasında karşılaştırmada kullanacağız.
 

public struct HWOCRCharRecognition
{
    public string Directions;
    public string Connections;
    public string RecognizeAs;
    public HWOCRCharRecognition(string d, string c, string r)
    {
        Directions = d;
        Connections = c;
        RecognizeAs = r;
    }
}


HWOCRConnections : Bu yapıda, bağlantı noktalarının birbirleriyle olan yakınlıklarını hesaplayarak bağlantı haritasını çıkartmak için gerekli olan X ve Y değerlerini saklayacağız.
 

public struct HWOCRConnections
{
    public int X;
    public int Y;
    public HWOCRConnections(int x, int y)
    {
        X = x;
        Y = y;
    }
}


WritingTimeout : Bu sürümde çizilen harfin tanımlanması için mouse'un sağ tuşuna basmak yerine belli bir zaman çizim yapılmaması yeterli olacaktır.Bu işlevi kazandırmak için WritingTimeout değişkenini ve bir Timer nesnesini kullanacağız.Varsayılan değer olarak 180 atayacağız.(Kullanıcının 180milisaniye çizim yapmaması durumunda harfi tanıma işlemine geçilecektir.)

ConnectionRange : Int32 türünden bu değişkende çizgilerin başlangıç veya bitiş noktalarının birbirleriyle bağlantılı olarak kabul edilmesi için gereken pixel türünden minimum yakınlık değerini saklayacağız.Varsayılan değer olarak 10 atanmıştır.

C : ArrayList türünden bu nesnede kullanıcının çizdiği harfin detay bilgisini HWOCRConnections türünden kaydedeceğiz.

R : ArrayList türünden bu nesnede kullanıcıya özel harf tanıma dosyasındaki bağlantı haritası bilgilerini HWOCRConnections türünden kaydedeceğiz.

Kullanılacak API ler
Kullanıcının seçimi üzerine tanınan harfin, işletim sisteminde çalışan diğer bir uygulamaya gönderilmesi için SetForeGroundWindow (klavye ve mouse kontrolünün hwnd numaralı pencereye odaklanması), keybd_event ve VkKeyScan (aktif pencereye istenilen klavye harfinin gönderilmesi) apilerini kullanacağız.
 

[DllImport("user32.dll")]
static extern short VkKeyScan(char ch);
[DllImport("user32.dll")]
static extern void keybd_event(short bVk, byte bScan, uint dwFlags, long dwExtraInfo);
[DllImport("user32")]
private static extern Int32 SetForegroundWindow(int hWnd);


Derleme ve Çalıştırma
Örnek harf tanımlama dosyasını indirin.
Projeyi indirip derleyin ve çalıştırın.
İlk olarak yapmanız gereken araççubuğundan Aç butonuna basmak olacaktır.Karşınıza harf tanıma dosyasını seçmeniz için bir OpenFileDialog penceresi gelecektir.
 

Dosyayı seçtiğinizde içerik ArrayList türünden R değişkenine HWOCRCharReconition yapısında aktarılacaktır.
 

private void LoadCharRecognitionTable()
{
R.Clear();
FileStream fs = new FileStream(PCRFPath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
while (sr.Peek() > 0)
{
string Temp = sr.ReadLine();
string[] Temps = Temp.Split('#');
HWOCRCharRecognition CR = new HWOCRCharRecognition(Temps[0].ToString(), Temps[1].ToString(), Temps[2].ToString());
R.Add(CR);
}
sr.Close();
fs.Close();
}

Eğer tanınan karakterin işletim sisteminde başka bir uygulamaya gönderilmesini istiyorsanız "Tanımlanan harfi başka bir uygulamaya gönder" etiketli checkbox'ı tıklayın ardından (R) etiketli butona tıklayın.Sistemde çalışan uygulamalar combobox'a yüklenecektir.
 

Sistemde çalışan uygulamalar combobox'a LoadRunningProcesses isimli metodla yüklenir.System.Diagnostics isimalanında bulunan Process sınıfı kullanılır.
 

private void LoadRunningProcesses()
{
comboBox1.Items.Clear();
comboBox2.Items.Clear();
Process[] procs = Process.GetProcesses();
for (int i = 0; i < procs.Length; i++)
{
if (procs[i].MainWindowTitle != "")
{
comboBox1.Items.Add(procs[i].ProcessName);
comboBox2.Items.Add(procs[i].Id);
}
}
}


Listeden bir uygulama seçin.Böylece tanımlanan harf o uygulamaya gönderilecektir.

Harf Tanımlama
PictureBox üzerine harfi çizin.
 


Eğer çizdiğiniz harf tanımlanırsa seçtiğiniz uygulamaya gönderilecektir.
 


Bu SendTextToProcess metodu ile gerçekleştirilir.
 

private void SendTextToProcess(string lettertosend)
{
Process p = Process.GetProcessById( Convert.ToInt32(comboBox2.Items[comboBox1.SelectedIndex]) );
SetForegroundWindow(p.MainWindowHandle.ToInt32());

switch (lettertosend)
{
case "BACKSPACE":
keybd_event(VkKeyScan(Convert.ToChar(Keys.Back)), 0, 0, 0);
keybd_event(VkKeyScan(Convert.ToChar(Keys.Back)), 0, 0x2, 0);
break;
default:
keybd_event(VkKeyScan(Convert.ToChar(lettertosend)), 0, 0, 0);
keybd_event(VkKeyScan(Convert.ToChar(lettertosend)), 0, 0x2, 0);
break;
}
//0x2 KEYUP
}


Eğer harf tanınmamışsa sizden çizdiğiniz harfi seçmeniz istenecektir.
 

Harfi seçtiğiniz taktirde gerekli bilgiler tanımlama dosyasına kaydedilir.

AnalyseThis() & ComputeConnections()
AnalyseThis metodu bir önceki sürüm ile pek farklılık göstermez.Sadece tanımlama karar aşamasına ComputeConnections metodu eklenmiştir.Bu metod kullanıcının çizdiği çizgilerin başlangıç ve bitiş noktalarını HWOCRConnections türüne çevirerek birbirlerine olan yakınlıklarını hesaplar ve Bağlantı haritasını çıkartır.
 

private string ComputeConnections()
{
HWOCRConnections CP;
HWOCRConnections CN;
string CC = "";
for (int i = 1; i < C.Count; i++)
{
bool found = false;
CN = (HWOCRConnections)C[i];
for (int p = 0; p < i; p++)
{
CP = (HWOCRConnections)C[p];
if (((CP.X + ConnectionRange) >= CN.X && CN.X >= (CP.X - ConnectionRange)) &&
((CP.Y + ConnectionRange) >= CN.Y && CN.Y >= (CP.Y - ConnectionRange)))
{
int r = p + 1;
CC += r.ToString();
found = true;
}
}
if (!found)
CC += "0";
CC += "|";
}
C.Clear();
return CC;
}


Böylece D ve P arasındaki farkı algılamış olup diğer harflerin de doğru olarak algılanmasını kuvvetlendirmiş olduk.

 


Evet bir makalenin daha sonuna geldik.Umarım yararlı olmuştur.
Hepinize mutlu günler dilerim. 

Levent YILDIZ
Gulf Agency Company - TURKEY
IT Manager
MCP
msmoracle@hotmail.com 
levent.yildiz@gacworld.com 
http://www.gacworld.com

Kaynaklar
http://msdn.microsoft.com/
proje