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

El Yazısı Tanıma API'si, elle yazılmış girişlerdeki metinleri okumanıza olanak tanır.

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

El Yazısı Tanıma API'si, kullanıcılarınızın el yazısını (mürekkebi) metne dönüştürmenizi sağlar. Bazı işletim sistemleri bu tür API'leri uzun süredir içermektedir ve bu yeni özellikle web uygulamalarınız nihayetinde 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. Bu işlemlerin tamamında herhangi bir üçüncü taraf kitaplığı veya hizmeti eklenmesi gerekmez.

Bu API, "çevrimiçi" veya neredeyse gerçek zamanlı tanıma uygular. Bu, kullanıcı tek vuruşları yakalayıp analiz ederek çizerken el yazısı girişinin tanınacağı anlamına gelir. Yalnızca son ürünün bilindiği Optik Karakter Tanıma (OCR) gibi "çevrimdışı" prosedürlerin aksine çevrimiçi algoritmalar, zamansal sıralama ve mürekkep darbelerinin basıncı gibi ek sinyaller sayesinde daha yüksek bir doğruluk seviyesi 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ı yakalayıp metne çevirmesini istedikleri not alma uygulamaları.
  • Kullanıcıların zaman kısıtlamaları nedeniyle kalem veya parmakla giriş kullanabildiği form uygulamaları.
  • Harflerin veya sayıların girilmesini gerektiren oyunlar (ör. kare bulmaca, hangman veya sudoku).

Mevcut durum

El Yazısı Tanıma API'sine (Chromium 99) ulaşabilirsiniz.

El Yazısı Recognition API'yi kullanma

Özellik algılama

Gezgin nesnesinde createHandwritingRecognizer() yönteminin mevcut 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şi metne dönüştürür. API'nin dört ana varlığı vardır:

  1. Nokta, işaretçinin belirli bir zamanda nerede olduğunu gösterir.
  2. Fırça bir veya daha fazla noktadan oluşur. Çizginin kaydı, kullanıcı işaretçiyi aşağı bıraktığında (ör. birincil fare düğmesini tıkladığında ya da kalemi veya parmağıyla ekrana dokunduğunda) başlar ve işaretçiyi tekrar yukarıya taşıdığında sona erer.
  3. Çizim, bir veya daha fazla çizgiden oluşur. Gerçek tanıma bu düzeyde gerçekleşir.
  4. Tanımlayıcı, beklenen giriş diliyle yapılandırılmıştır. Tanımlayıcı yapılandırmasının uygulandığı bir çizim örneği oluşturmak için kullanılır.

Bu kavramlar, belirli arayüzler ve sözlükler olarak uygulanır. Bunlara birazdan değineceğim.

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

Tanıyıcı oluşturma

Elle yazılmış girişlerdeki metinleri tanımak için navigator.createHandwritingRecognizer() yöntemini çağırıp kısıtlamaları ona ileterek HandwritingRecognizer örneği almanız gerekir. Kısıtlamalar, kullanılması gereken el yazısı tanıma modelini belirler. Şu anda tercih sırasına göre bir dil listesi belirtebilirsiniz:

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

Yöntem, tarayıcı isteğinizi yerine getirebildiğinde HandwritingRecognizer örneğiyle çözümlenme vaadi döndürür. Aksi takdirde sözü bir hatayla reddeder ve el yazısı tanıma özelliği kullanılamaz. Bu nedenle, ilk olarak belirli tanıma özellikleri için tanıyıcının desteğini sorgulamak isteyebilirsiniz.

Tanıyıcı desteği sorgulama

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 düşük olası tahminler alın
  • Segmentasyon sonucuna, yani tanınan karakterler, bunları oluşturan noktalar ve fırçalar gibi.
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 vaat döndürür. Tarayıcı, geliştiricinin belirttiği özelliği destekliyorsa değeri 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 ayarlayıp yeni bir sorgu göndermek için kullanabilirsiniz.

Çizim başlat

Başvurunuzda, kullanıcının el yazısıyla giriş yaptığı bir giriş alanı sunmalısınız. Performansı artırmak için bu işlemi canvas nesnesi yardımıyla uygulamanız önerilir. Bu kısmın tam olarak uygulanması bu makalenin kapsam dışındadır ancak nasıl yapılacağını görmek için demoya bakabilirsiniz.

Yeni bir çizim başlatmak 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 az olası alternatif tahminlerin sayısı (alternatives)
  • Kullanıcının büyük olasılıkla gireceği, kullanıcıyı tanımlayabilecek karakterlerin ("grafikler") bir listesi (graphemeSet)

El Yazısı Tanıma API'si, herhangi bir işaretleme cihazından gelen girişleri tüketmek için soyut bir arayüz sağlayan İşaretçi Etkinlikleri ile birlikte iyi performans gösterir. İşaretçi etkinliği bağımsız değişkenleri, kullanılan işaretçi 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 oluşumunda otomatik olarak oluşturulmuştur. pointerType boş veya özel bir değere ayarlanmış olabileceğinden, çizimin giriş türü için yalnızca desteklenen değerlerin ayarlandığından emin olmak için tutarlılık kontrolü yaptı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 çizgiye başlamak için de doğru yerdir. Bunu yapmak için yeni bir HandwritingStroke örneği oluşturun. Ayrıca, geçerli zamanı, ona daha sonra eklenecek noktalar için referans noktası olarak saklamanız gerekir:

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

Nokta ekleyin

Fırçayı oluşturduktan sonra, ilk noktayı doğrudan ona eklemeniz gerekir. Daha sonra başka noktalar ekleyeceklerinizden, nokta oluşturma mantığını ayrı bir yöntemle uygulamak mantıklıdır. Aşağıdaki örnekte addPoint() yöntemi, geçen süreyi referans zaman damgasına göre hesaplar. Geçici bilgi 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 fırçaya ekler.

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

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

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

Metni tanı

Kullanıcı işaretçiyi tekrar kaldırdığında, addStroke() yöntemini çağırarak çiziminize çizgi ekleyebilirsiniz. Aşağıdaki örnek de activeStroke öğesini sıfırlar. Böylece pointermove işleyici, tamamlanan fırçaya nokta eklemez.

Şimdi sıra, çizim üzerinde getPrediction() yöntemini çağırarak kullanıcının girişini tanımaya geliyor. Tanıma işlemi genellikle birkaç yüz milisaniyeden kısa sürer. Böylece, gerekirse tahminleri tekrar tekrar çalıştırabilirsiniz. Aşağıdaki örnekte, tamamlanan her çizgiden sonra yeni bir tahmin çalıştırılmaktadı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ıralanan bir dizi tahminle çözümlenen bir söz döndürür. Öğe sayısı, alternatives ipucuna aktardığınız değere bağlıdır. Bu diziyi, kullanıcıya olası eşleşme seçeneklerini sunmak ve bir seçenek belirlemesini sağlamak için kullanabilirsiniz. Alternatif olarak, en olası tahminden yararlanabilirsiniz. Örnekte ben bunu yapıyorum.

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

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

Hedef platform tarafından desteklenirse tahmin nesnesi, bir segmentasyon sonucu da içerebilir. Bu dizi, tanınan tüm el yazısı segmentini, tanınan kullanıcı tanımlı karakterin (grapheme) tanınan metindeki (beginIndex, endIndex) konumuyla birlikte bu segmenti oluşturan çizgi ve noktalardan oluşan bir kombinasyonudur.

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);
      });
    },
  );
}

Bu bilgileri kullanarak tuvaldeki tanınan grafemleri tekrar bulabilirsiniz.

Algılanan her bir grafemin etrafına kutular çizilir

Tam tanıma

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

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

Demo

Web bileşeni <handwriting-textarea>, el yazısı tanıma özelliğine sahip kademeli olarak iyileştirilmiş bir düzenleme kontrolü uygular. Düzenleme denetiminin 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 düzenleme denetimine tekrar ekler. El Yazısı Tanıma API'si hiç desteklenmiyorsa veya platform istenen özellikleri desteklemiyorsa düzenleme düğmesi gizlenir. Ancak temel düzenleme denetimi <textarea> olarak kullanılabilir.

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

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

Değerde yapılan değişikliklerden haberdar olmak için input etkinliğini dinleyebilirsiniz.

Glitch'teki bu demoyu kullanarak bileşeni deneyebilirsiniz. Ayrıca kaynak koda göz atmayı da unutmayın. Denetimi uygulamanızda kullanmak için npm'den edinin.

Güvenlik ve izinler

Chromium ekibi; kullanıcı denetimi, şeffaflık ve ergonomi dahil olmak üzere Güçlü Web Platformu Özelliklerine Erişimi Kontrol Etme bölümünde tanımlanan temel ilkeleri kullanarak El Yazısı Tanıma API'sini tasarladı ve uyguladı.

Kullanıcı denetimi

El Yazısı Tanıma API'si kullanıcı tarafından kapatılamaz. Sadece HTTPS üzerinden sunulan web siteleri için kullanılabilir ve sadece üst düzey göz atma bağlamından çağrılabilir.

Şeffaflık

El yazısı tanımanın etkin olup olmadığına dair herhangi bir gösterge görünmez. Tarayıcı, dijital parmak izi almayı önlemek için karşı önlemler alır. Örneğin, olası kötüye kullanım tespit edildiğinde kullanıcıya bir izin mesajı gösterilir.

İzin kalıcılığı

El Yazısı Tanıma API'si şu anda herhangi bir izin istemi göstermemektedir. Bu nedenle, iznin hiçbir şekilde kullanılması gerekmez.

Geri bildirim

Chromium ekibi, Handwriting Recognition API ile ilgili deneyimlerinizi öğrenmek istiyor.

Bize API tasarımından bahsedin

API'nin beklediğiniz gibi çalışmayan bir yönü var mı? Ya da fikrinizi uygulamak için gereken eksik yöntemler veya özellikler var mı? Güvenlik modeliyle ilgili sorunuz veya yorumunuz mu var? İlgili GitHub kod deposunda spesifikasyon sorunu oluşturun veya mevcut bir soruna düşüncelerinizi ekleyin.

Uygulamayla ilgili bir sorunu bildirin

Chromium'un uygulamasında bir hata buldunuz mu? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinden hata bildiriminde bulunun. Olabildiğince çok ayrıntı ve yeniden oluşturma ile ilgili basit talimatları eklediğinizden emin olun ve Bileşenler kutusuna Blink>Handwriting yazın. Glitch hızlı ve kolay yeniden oluşturma paylaşımı için idealdir.

API'ye desteği gösterin

El Yazısı Tanıma API'sini kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chromium ekibinin özelliklere öncelik vermesine yardımcı olur ve diğer tarayıcı satıcılarına bu özellikleri desteklemenin ne kadar kritik olduğunu gösterir.

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

Teşekkür

Bu makale Joe Medley, Honglin Yu ve Jiewei Qian tarafından incelendi. Samir Bouaked tarafından Unsplash'teki lokomotif resim.