Kullanıcılarınızın el yazısını tanıma

El Yazısı Tanıma API'si, el yazısı girişlerinden gelen metinleri daha anında tanımanıza olanak tanır.

El Yazısı Tanıma API'si nedir?

El Yazısı Recognition API, kullanıcılarınızın el yazılarını (mürekkep) metne dönüştürmenizi sağlar. Bazı işletim sistemlerinde bu tür API'ler uzun süredir bulunmaktadır ve bu yeni özellikle, web uygulamalarınız nihayet bu işlevi kullanabilir. Dönüştürme işlemi doğrudan kullanıcının cihazında gerçekleşir, çevrimdışı modda bile çalışır ve üçüncü taraf kitaplıkları ya da hizmetleri eklenmeden çalışır.

Bu API, "çevrimiçi" veya neredeyse gerçek zamanlı tanıma uygular. Bu, el yazısı girişin kullanıcı tarafından çizildiği sırada, tek vuruşları kaydedip analiz edilerek algılandığı anlamına gelir. Yalnızca son ürünün bilindiği Optik Karakter Tanıma (OCR) gibi "çevrimdışı" prosedürlerin aksine, çevrimiçi algoritmalar, tek tek mürekkep darbelerinin zamansal sırası ve basıncı gibi ek sinyaller nedeniyle daha yüksek doğruluk düzeyi sağlayabilir.

El Yazısı Tanıma API'si için önerilen kullanım alanları

Örnek kullanımlar şunları içerir:

  • Kullanıcıların elle yazılmış notları kaydedip metne çevirmek istediği not alma uygulamaları.
  • Kullanıcıların zaman kısıtlamaları nedeniyle kalem veya parmakla giriş yapabileceği form uygulamaları.
  • Kare bulmaca, hangman veya sudoku gibi harf veya rakam girilmesini gerektiren oyunlar.

Mevcut durum

El Yazısı Recognition API'yi (Chromium 99) bulabilirsiniz.

El Yazısı Tanıma API'sini kullanma

Özellik algılama

Gezinme nesnesinde createHandwritingRecognizer() yönteminin olup olmadığını kontrol ederek tarayıcı desteğini tespit edin:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

Temel kavramlar

El Yazısı Tanıma API'si, giriş yönteminden (fare, dokunma, kalem) bağımsız olarak elle yazılmış girişleri metne dönüştürür. API'nin dört ana varlığı vardır:

  1. Nokta, işaretçinin belirli bir zamanda bulunduğu yeri temsil eder.
  2. Çizgi bir veya daha fazla noktadan oluşur. Bir çizgi kaydı, kullanıcı işaretçiyi aşağı koyduğunda (ör. birincil fare düğmesini tıkladığında veya ekrana kalemi ya da parmağıyla dokunduğunda) başlar ve işaretçi tekrar yukarı kaldırdığında sona erer.
  3. Çizim bir veya daha fazla çizgiden oluşur. Asıl tanıma işlemi bu düzeyde gerçekleşir.
  4. Tanımlayıcı, beklenen giriş diliyle yapılandırılır. Tanıyıcı yapılandırması uygulanmış bir çizimin örneğini oluşturmak için kullanılır.

Bu kavramlar, özel arayüzler ve sözlükler olarak uygulanmıştır. Kısa süre içinde bu konuya değineceğim.

El Yazısı Recognition API'nin temel öğeleri: Bir veya daha fazla nokta bir çizgi oluşturur, bir veya daha fazla çizgi ise tanıyıcının oluşturduğu bir çizimi oluşturur. Asıl tanıma işlemi çizim düzeyinde gerçekleşir.

Tanıyıcı oluşturma

El yazısıyla yazılmış girişlerdeki metni tanımak için navigator.createHandwritingRecognizer() yöntemini çağırıp kısıtlamaları geçirerek HandwritingRecognizer örneği almanız gerekir. Kısıtlamalar, kullanılması gereken el yazısı tanıma modelini belirler. Şu anda tercihinize göre bir dil listesi belirtebilirsiniz:

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

Bu yöntem, tarayıcı isteğinizi yerine getirebildiğinde HandwritingRecognizer örneğiyle çözümlenen bir söz döndürür. Aksi takdirde, hata mesajıyla birlikte verilen taahhüt reddedilir ve el yazısı tanıma özelliği kullanılamaz. Bu nedenle, ilk olarak tanıyıcının belirli tanıma özellikleri için desteğini sorgulamak isteyebilirsiniz.

Sorgu tanıyıcı desteği

navigator.queryHandwritingRecognizerSupport() numaralı telefonu arayarak hedef platformun, kullanmayı düşündüğünüz el yazısı tanıma özelliklerini destekleyip desteklemediğini kontrol edebilirsiniz. Aşağıdaki örnekte, geliştirici:

  • İngilizce metinleri algılamak istiyor
  • mevcut olduğunda alternatif, daha az olası tahminler alma
  • segmentasyon sonucuna, yani bu karakterleri oluşturan noktalar ve vuruşlar da dahil tanınan karakterlere erişim elde edebilir.
const { languages, alternatives, segmentationResults } =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en'],
    alternatives: true,
    segmentationResult: true,
  });

console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false

Yöntem, bir sonuç nesnesiyle çözümlenen taahhüt döndürür. Tarayıcı, geliştiricinin belirttiği özelliği destekliyorsa true olarak ayarlanır. Aksi takdirde false olarak ayarlanır. Bu bilgileri, uygulamanızdaki belirli özellikleri etkinleştirmek veya devre dışı bırakmak ya da sorgunuzu ayarlamak ve yeni bir tane göndermek için kullanabilirsiniz.

Çizim başlat

Uygulamanızda, kullanıcının el yazısı girişlerini yaptığı bir giriş alanı sunmalısınız. Performansı artırmak için bunu bir kanvas nesnesi yardımıyla uygulamanız önerilir. Bu bölümün tam olarak uygulanması bu makalenin kapsamı dışındadır, ancak bunun nasıl yapılabileceğini görmek için demoya bakabilirsiniz.

Yeni bir çizime başlamak için tanıyıcıda startDrawing() yöntemini çağırın. Bu yöntemde, tanıma algoritmasında ince ayar yapmak için farklı ipuçları içeren bir nesne kullanılır. Tüm ipuçları isteğe bağlıdır:

  • Girilen metnin türü: metin, e-posta adresleri, sayılar veya tek bir karakter (recognitionType)
  • Giriş cihazının türü: fare, dokunma veya kalem girişi (inputType)
  • Önceki metin (textContext)
  • Döndürülmesi gereken daha düşük olasılıklı alternatif tahminlerin sayısı (alternatives)
  • Kullanıcının büyük olasılıkla gireceği, kullanıcının kimliğini tanımlayabilecek karakterlerin ("grafikler") listesi (graphemeSet)

El Yazısı Recognition API, herhangi bir işaretleme cihazından giriş tüketimi için soyut bir arayüz sağlayan İşaretçi Etkinlikleri ile uyumlu bir şekilde çalışır. İşaretçi etkinliği bağımsız değişkenleri, kullanılan işaretçinin türünü içerir. Bu, giriş türünü otomatik olarak belirlemek için işaretçi etkinliklerini kullanabileceğiniz anlamına gelir. Aşağıdaki örnekte, el yazısı tanıma çizimi, el yazısı alanında bir pointerdown etkinliğinin ilk gerçekleştiğinde otomatik olarak oluşturulur. pointerType boş olabileceği veya özel bir değere ayarlanmış olabileceğinden, çizimin giriş türü için yalnızca desteklenen değerlerin ayarlandığından emin olmak amacıyla tutarlılık kontrolü başlattım.

let drawing;
let activeStroke;

canvas.addEventListener('pointerdown', (event) => {
  if (!drawing) {
    drawing = recognizer.startDrawing({
      recognitionType: 'text', // email, number, per-character
      inputType: ['mouse', 'touch', 'pen'].find((type) => type === event.pointerType),
      textContext: 'Hello, ',
      alternatives: 2,
      graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
    });
  }
  startStroke(event);
});

Çizgi ekle

pointerdown etkinliği yeni bir çizgi başlatmak için de doğru yerdir. Bunun için yeni bir HandwritingStroke örneği oluşturun. Ayrıca, geçerli zamanı ona eklenecek sonraki noktalar için referans noktası olarak kaydetmelisiniz:

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

Nokta ekleyin

Fırçayı oluşturduktan sonra ilk noktayı doğrudan eklemelisiniz. İleride başka noktalar ekleyeceğimizden, puan oluşturma mantığını ayrı bir yöntemle uygulamak mantıklı olacaktır. Aşağıdaki örnekte addPoint() yöntemi, geçen süreyi referans zaman damgasından hesaplar. Zaman bilgisi isteğe bağlıdır ancak tanıma kalitesini iyileştirebilir. Ardından, işaretçi etkinliğinden X ve Y koordinatlarını okur ve noktayı mevcut çizgiye ekler.

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

pointermove etkinlik işleyicisi, işaretçi ekran boyunca hareket ettirildiğinde çağrılır. Bu noktaların da fırçaya eklenmesi gerekir. Etkinlik, işaretçi "aşağı" durumda değilse de yükseltilebilir (örneğin, fare düğmesine basmadan imleci ekranda hareket ettirdiğinizde). Aşağıdaki örnekte yer alan etkinlik işleyici, etkin bir fırçanın olup olmadığını kontrol eder ve yeni noktayı buna ekler.

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

Metni tanı

Kullanıcı işaretçiyi tekrar kaldırdığında, addStroke() yöntemini kullanarak fırçayı çiziminize ekleyebilirsiniz. Aşağıdaki örnek, activeStroke değerini de sıfırlar. Bu nedenle, pointermove işleyici tamamlanan çizgiye nokta eklemez.

Şimdi sıra, çizimde getPrediction() yöntemini çağırarak kullanıcının girişini tanımaya geldi. Tanıma işlemi genellikle birkaç yüz milisaniyeden kısa sürer. Bu nedenle, gerekirse tahminleri tekrar tekrar çalıştırabilirsiniz. Aşağıdaki örnekte tamamlanan her çizgiden sonra yeni bir tahmin çalıştırılır.

canvas.addEventListener('pointerup', async (event) => {
  drawing.addStroke(activeStroke.stroke);
  activeStroke = null;

  const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
  if (mostLikelyPrediction) {
    console.log(mostLikelyPrediction.text);
  }
  lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});

Bu yöntem, olasılıklarına göre sıralanmış bir dizi tahminle sonuçlanan bir vaat döndürür. Öğe sayısı, alternatives ipucuna ilettiğiniz değere bağlıdır. Bu diziyi, kullanıcıya olası eşleşmeler sunmak ve bir seçenek belirlemesini sağlamak için kullanabilirsiniz. Alternatif olarak, örnekte benim yaptığım gibi en olası tahmine geçebilirsiniz.

Tahmin nesnesi, tanınan metni ve isteğe bağlı bir segmentasyon sonucunu içerir. Bu sonuçları aşağıdaki bölümde ele alacağız.

Segmentasyon sonuçlarıyla ayrıntılı analizler

Hedef platform tarafından destekleniyorsa tahmin nesnesi, segmentasyon sonucu da içerebilir. Bu dizi, tüm tanınan el yazısı segmentini, tanınan kullanıcı tanınabilir karakterin (grapheme), tanınan metindeki (beginIndex, endIndex) konumu ile onu oluşturan çizgi ve noktaların bir kombinasyonunu içerir.

if (mostLikelyPrediction.segmentationResult) {
  mostLikelyPrediction.segmentationResult.forEach(
    ({ grapheme, beginIndex, endIndex, drawingSegments }) => {
      console.log(grapheme, beginIndex, endIndex);
      drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
        console.log(strokeIndex, beginPointIndex, endPointIndex);
      });
    },
  );
}

Zemindeki tanınan grafikleri tekrar bulmak için bu bilgileri kullanabilirsiniz.

Kutular, tanınan her bir grafiğin etrafına çizilir

Tanıma işlemini tamamla

Tanıma işlemi tamamlandıktan sonra HandwritingDrawing üzerinde clear() yöntemini, HandwritingRecognizer üzerinde ise finish() yöntemini çağırarak kaynakları serbest bırakabilirsiniz:

drawing.clear();
recognizer.finish();

Demo

<handwriting-textarea> web bileşeni, el yazısı tanıma özelliğine sahip, aşamalı olarak iyileştirilmiş bir düzenleme kontrolü uygular. Düzenleme kontrolünün sağ alt köşesindeki düğmeyi tıklayarak çizim modunu etkinleştirirsiniz. Çizimi tamamladığınızda, web bileşeni otomatik olarak tanımayı başlatır ve tanınan metni tekrar düzenleme denetimine ekler. El Yazısı Tanıma API'si hiç desteklenmiyorsa veya platform istenen özellikleri desteklemiyorsa düzenleme düğmesi gizlenir. Ancak temel düzenleme kontrolü, <textarea> olarak kullanılabilir olmaya devam eder.

Web bileşeni, dışarıdan tanıma davranışını tanımlayan languages ve recognitiontype gibi özellikler ve özellikler sunar. Kontrolün içeriğini value özelliğiyle ayarlayabilirsiniz:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

Değerdeki herhangi bir değişiklikten haberdar olmak için input etkinliğini dinleyebilirsiniz.

Glitch'teki bu demoyu kullanarak bileşeni deneyebilirsiniz. Ayrıca kaynak koda göz attığınızdan emin olun. Denetimi uygulamanızda kullanmak için npm'den alın.

Güvenlik ve izinler

Chromium ekibi, El Yazısı Tanıma API'sini Güçlü Web Platformu Özelliklerine Erişimi Kontrol Etme konusunda tanımlanan temel ilkeleri (kullanıcı kontrolü, şeffaflık ve ergonomi dahil) kullanarak tasarlamış ve uygulamıştır.

Kullanıcı denetimi

El Yazısı Recognition API, kullanıcı tarafından devre dışı bırakılamaz. Yalnızca HTTPS aracılığıyla yayınlanan web siteleri için kullanılabilir ve sadece üst düzey tarama bağlamından çağrılabilir.

Şeffaflık

El yazısı tanımanın etkin olup olmadığına dair herhangi bir bilgi yoktur. Tarayıcı, dijital parmak izini önlemek için kötüye kullanım olasılığı tespit ettiğinde kullanıcıya bir izin istemi göstermek gibi karşı önlemler alır.

İzin kalıcılığı

El Yazısı Tanıma API'si şu anda herhangi bir izin istemi göstermiyor. Bu nedenle, iznin herhangi bir şekilde tutulması gerekmez.

Geri bildirim

Chromium ekibi, El Yazısı Recognition API ile ilgili deneyimleriniz hakkında bilgi almak istiyor.

Bize API tasarımı hakkında bilgi verin

API'de beklediğiniz gibi çalışmayan bir şey mi var? Yoksa fikrinizi uygulamak için ihtiyacınız olan yöntemler veya özellikler mi var? Güvenlik modeliyle ilgili sorunuz veya yorumunuz mu var? İlgili GitHub deposunda bir spesifikasyon sorunu bildirin veya mevcut bir soruna düşüncelerinizi ekleyin.

Uygulamayla ilgili bir sorunu bildirin

Chromium'un uygulanmasıyla ilgili bir hata buldunuz mu? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinde bir hata bildiriminde bulunun. Mümkün olduğunca çok ayrıntıyı ve yeniden oluşturma için basit talimatları eklediğinizden emin olun ve Bileşenler kutusuna Blink>Handwriting yazın. Glitch, hızlı ve kolay yeniden oluşturmalar paylaşmak için idealdir.

API'ye desteğinizi gösterin

El Yazısı Tanıma API'sini kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chromium ekibinin özellikleri önceliklendirmesine yardımcı olur ve diğer tarayıcı tedarikçilerine bunları desteklemenin ne kadar kritik olduğunu gösterir.

Bu özelliği nasıl kullanmayı planladığınızı WICG Discourse ileti dizisinde paylaşın. #HandwritingRecognition hashtag'ini kullanarak @ChromiumDev'e bir tweet gönderin ve etiketi nerede ve nasıl kullandığınızı bize bildirin.

Teşekkür

Bu makale Joe Medley, Honglin Yu ve Jiewei Qian tarafından incelenmiştir. Samir Bouaked'in Unsplash'teki hero resim.