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

El Yazısı Tanıma API'si, el yazısıyla girilen metinleri anında tanımanıza olanak tanır.

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

El Yazısı Tanıma API'si, kullanıcılarınızın el yazısını (mürekkep) metne dönüştürmenize olanak tanır. Bazı işletim sistemleri bu tür API'leri uzun süredir içeriyor ve bu yeni özellik sayesinde web uygulamalarınız nihayet bu işlevden yararlanabilir. Dönüşüm doğrudan kullanıcının cihazında gerçekleşir, çevrimdışı modda bile çalışır ve üçüncü taraf kitaplıkları veya hizmetleri eklenmeden tamamlanır.

Bu API, "çevrimiçi" veya neredeyse gerçek zamanlı tanımayı uygular. Bu, tek vuruşları yakalayıp analiz ederek kullanıcı çizerken el yazısı girişinin tanındığı anlamına gelir. Yalnızca nihai ürünün bilindiği Optik Karakter Tanıma (OCR) gibi "çevrimdışı" prosedürlerin aksine, çevrimiçi algoritmalar, mürekkep vuruşlarının zamansal sırası ve basıncı gibi ek sinyaller nedeniyle daha yüksek bir doğruluk düzeyi sağlayabilir.

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

Örnek kullanımlar:

  • Kullanıcıların elle yazılmış notları yakalayıp metne dönüştürmek istediği not alma uygulamaları.
  • Zaman kısıtlamaları nedeniyle kullanıcıların kalem veya parmakla giriş yapabileceği form uygulamaları.
  • Bulmaca, adam asmaca veya sudoku gibi harf ya da sayı doldurmayı gerektiren oyunlar

Mevcut durum

El Yazısı Tanıma API'si (Chromium 99) sürümünden itibaren kullanılabilir.

El Yazısı Tanıma API'si nasıl kullanılır?

Özellik algılama

Tarayıcı desteğini, navigator nesnesinde createHandwritingRecognizer() yönteminin olup olmadığını kontrol ederek algılayın:

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

Temel kavramlar

El Yazısı Tanıma API'si, giriş yönteminden (fare, dokunma, ekran kalemi) bağımsız olarak el yazısı girişini metne dönüştürür. API'nin dört ana öğesi vardır:

  1. Nokta, işaretçinin belirli bir zamandaki konumunu gösterir.
  2. Kontur, bir veya daha fazla noktadan oluşur. Bir vuruşun kaydı, kullanıcı işaretçiyi aşağı indirdiğinde (ör. birincil fare düğmesini tıkladığında veya ekranı kalemi ya da parmağıyla dokunduğunda) başlar ve işaretçiyi tekrar yukarı kaldırdığında sona erer.
  3. Çizimler bir veya daha fazla fırça darbesinden oluşur. Gerçek tanıma bu düzeyde gerçekleşir.
  4. Tanıyıcı, beklenen giriş diliyle yapılandırılır. Tanıyıcı yapılandırması uygulanmış bir çizim örneği oluşturmak için kullanılır.

Bu kavramlar, kısa süre içinde ele alacağım belirli arayüzler ve sözlükler olarak uygulanır.

El Yazısı Tanıma API'sinin temel varlıkları: Bir veya daha fazla nokta bir vuruşu, bir veya daha fazla vuruş 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ımlayıcı oluşturma

Elle yazılmış girişlerden metin tanımak için navigator.createHandwritingRecognizer() işlevini çağırıp kısıtlamaları 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'],
});

Tarayıcı isteğinizi karşılayabildiğinde yöntem, HandwritingRecognizer örneğiyle çözümlenen bir söz döndürür. Aksi takdirde, söz reddedilir ve hata mesajı gösterilir. El yazısı tanıma kullanılamaz. Bu nedenle, önce tanıyıcının belirli tanıma özelliklerini destekleyip desteklemediğini sorgulamak isteyebilirsiniz.

Tanıyıcı desteği sorgulama

navigator.queryHandwritingRecognizer() numaralı telefonu arayarak hedef platformun, kullanmayı planladığınız el yazısı tanıma özelliklerini destekleyip desteklemediğini kontrol edebilirsiniz. Bu yöntem, istenen dillerin listesini içeren navigator.createHandwritingRecognizer() yöntemiyle aynı kısıtlama nesnesini alır. Yöntem, uyumlu bir tanıyıcı bulunursa sonuç nesnesiyle çözümlenen bir söz döndürür. Aksi takdirde, söz null olarak çözümlenir. Aşağıdaki örnekte geliştirici:

  • İngilizce metinleri algılamak istiyor
  • Mümkün olduğunda alternatif ve daha az olası tahminler alma
  • segmentasyon sonucuna (yani noktalar ve çizgiler dahil olmak üzere tanınan karakterler) erişim elde etme
const result =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en']
  });

console.log(result?.textAlternatives); // true if alternatives are supported
console.log(result?.textSegmentation); // true if segmentation is supported

Tarayıcı, geliştiricinin ihtiyaç duyduğu özelliği destekliyorsa sonuç nesnesinde 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 farklı bir dil grubu için yeni bir sorgu göndermek üzere kullanabilirsiniz.

Çizim başlatma

Uygulamanızda, kullanıcının el yazısıyla giriş yapacağı bir giriş alanı sunmanız gerekir. Performans nedeniyle, bu işlevin bir tuval nesnesi yardımıyla uygulanması önerilir. Bu bölümün tam olarak nasıl uygulanacağı bu makalenin kapsamı dışındadır ancak nasıl yapılabileceğini 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ını hassaslaştırmak 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 ekran kalemi 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ı tarafından tanımlanabilir karakterlerin ("grafemler") listesi (graphemeSet)

El Yazısı Tanıma API, herhangi bir işaretleme cihazından gelen girişi kullanmak için soyut bir arayüz sağlayan Pointer Events ile iyi ç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 için çizim, el yazısı alanında pointerdown etkinliğinin ilk oluşumunda otomatik olarak oluşturulur. pointerType boş olabileceği veya tescilli bir değere ayarlanabileceği için, çizimin giriş türü için yalnızca desteklenen değerlerin ayarlandığından emin olmak üzere bir tutarlılık kontrolü ekledim.

let drawing;
let activeStroke;

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

Kontur ekleme

pointerdown etkinliği, yeni bir vuruş başlatmak için de doğru yerdir. Bunu yapmak için HandwritingStroke'nın yeni bir örneğini oluşturun. Ayrıca, geçerli saati, daha sonra eklenen noktalar için referans noktası olarak saklamanız gerekir:

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

Nokta ekleyin

Konturu oluşturduktan sonra ilk noktayı doğrudan eklemeniz gerekir. Daha sonra başka noktalar ekleyeceğiniz için nokta oluşturma mantığını ayrı bir yöntemde uygulamak mantıklıdır. Aşağıdaki örnekte, addPoint() yöntemi, referans zaman damgasından itibaren geçen süreyi hesaplar. Zaman bilgisi isteğe bağlıdır ancak tanıma kalitesini artırabilir. Ardından, işaretçi etkinliğinden X ve Y koordinatlarını okur ve noktayı mevcut vuruşa ekler.

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

İşaretçi ekranda hareket ettirildiğinde pointermove etkinlik işleyicisi çağrılır. Bu noktalar da kontura eklenmelidir. İşaretçi "aşağı" durumunda değilse de (ör. fare düğmesine basmadan imleci ekranda hareket ettirirken) olay tetiklenebilir. Aşağıdaki örnekteki etkinlik işleyici, etkin bir kontur olup olmadığını kontrol eder ve yeni noktayı bu kontura ekler.

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

Metin tanıma

Kullanıcı işaretçiyi tekrar kaldırdığında, addStroke() yöntemini çağırarak konturu çiziminize ekleyebilirsiniz. Aşağıdaki örnekte de activeStroke sıfırlanır. Bu nedenle, pointermove işleyici, tamamlanan vuruşa puan eklemez.

Ardından, çizimde getPrediction() yöntemini çağırarak kullanıcının girişini tanıma zamanı gelir. 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 örnek, tamamlanan her vuruştan sonra yeni bir tahmin yürütü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 tahmin dizisiyle çözümlenen bir söz döndürür. Öğe sayısı, alternatives ipucuna ilettiğiniz değere bağlıdır. Bu diziyi kullanarak kullanıcıya olası eşleşmeler arasından seçim yapma imkanı sunabilir ve bir seçenek belirlemesini sağlayabilirsiniz. Alternatif olarak, en olası tahmini de kullanabilirsiniz. Ben de örnekte bu yolu izledim.

Tahmin nesnesi, tanınan metni ve isteğe bağlı bir segmentasyon sonucunu içerir. Segmentasyon sonucunu sonraki bölümde ele alacağım.

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

Hedef platform tarafından destekleniyorsa tahmin nesnesi bir segmentasyon sonucu da içerebilir. Bu, tanınan tüm el yazısı segmentini içeren bir dizidir. Tanınan kullanıcı tarafından tanımlanabilir karakter (grapheme), tanınan metindeki konumu (beginIndex, endIndex) ve bunu oluşturan vuruşlar ve noktalar bu dizide yer alır.

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, tuvalde tanınan grafemleri tekrar bulmak için kullanabilirsiniz.

Tanınan her grafemin etrafına kutular çizilir.

Tam tanıma

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

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

Demo

Web bileşeni <handwriting-textarea>, el yazısı tanıma özelliğine sahip aşamalı olarak geliş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 tanıma işlemini otomatik olarak başlatır ve tanınan metni düzenleme kontrolüne geri 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ılmaya devam eder.

Web bileşeni, languages ve recognitiontype dahil olmak üzere tanıma davranışını dışarıdan tanımlamak için özellikler ve nitelikler 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şiklikler hakkında bilgi edinmek için input etkinliğini dinleyebilirsiniz.

Bileşeni GitHub'daki bu demoyu kullanarak deneyebilirsiniz. Ayrıca kaynak koduna da göz atmayı unutmayın. Kontrolü uygulamanızda kullanmak için npm'den edinin.

Güvenlik ve izinler

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

Kullanıcı denetimi

El Yazısı Tanıma API'si kullanıcı tarafından devre dışı bırakılamaz. Yalnızca HTTPS üzerinden sunulan web sitelerinde kullanılabilir ve yalnızca üst düzey tarama bağlamından çağrılabilir.

Şeffaflık

El yazısı tanıma özelliğinin etkin olup olmadığı belirtilmez. Tarayıcı, parmak izi oluşturmayı önlemek için olası kötüye kullanım tespit ettiğinde kullanıcıya izin istemi gösterme gibi karşı önlemler uygular.

İzin kalıcılığı

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

Geri bildirim

Chromium Ekibi, El Yazısı Tanıma API'si ile ilgili deneyimlerinizi öğrenmek istiyor.

API tasarımı hakkında bilgi verin

API'nin beklentilerinizi karşılamayan bir özelliği var mı? Yoksa fikrinizi uygulamak için eksik yöntemler veya özellikler mi var? Güvenlik modeliyle ilgili sorunuz veya yorumunuz mu var? İlgili GitHub deposunda bir spesifikasyon sorunu bildirin veya düşüncelerinizi mevcut bir soruna ekleyin.

Uygulamayla ilgili sorun bildirme

Chromium'un uygulanmasıyla ilgili bir hata mı buldunuz? Yoksa uygulama, spesifikasyondan farklı mı? new.crbug.com adresinden hata bildirin. Mümkün olduğunca fazla ayrıntı ve hatayı yeniden oluşturmayla ilgili basit talimatlar eklediğinizden emin olun. Ayrıca Bileşenler kutusuna Blink>Handwriting girin.

API'ye desteğinizi gösterme

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ı satıcılarına bu özellikleri desteklemenin ne kadar önemli olduğunu gösterir.

Bu özelliği nasıl kullanmayı planladığınızı WICG Discourse iş parçacığında paylaşın. #HandwritingRecognition hashtag'ini kullanarak @ChromiumDev hesabına tweet gönderin ve nerede, nasıl kullandığınızı bize bildirin.

Teşekkür

Bu belge Joe Medley, Honglin Yu ve Jiewei Qian tarafından incelenmiştir.