Kenali tulisan tangan pengguna

Handwriting Recognition API memungkinkan Anda mengenali teks dari input tulisan tangan saat terjadi.

Apa itu Handwriting Recognition API?

API Pengenalan Tulis Tangan memungkinkan Anda mengonversi tulisan tangan (tinta) dari pengguna menjadi teks. Beberapa sistem operasi telah lama menyertakan API tersebut, dan dengan kemampuan baru ini, aplikasi web Anda akhirnya dapat menggunakan fungsi ini. Konversi terjadi langsung di perangkat pengguna, bahkan dapat berfungsi dalam mode offline, semuanya tanpa perlu menambahkan library atau layanan pihak ketiga apa pun.

API ini mengimplementasikan apa yang disebut "on-line" atau pengenalan mendekati real-time. Artinya, input tulisan tangan dikenali saat pengguna menggambarnya dengan mengambil dan menganalisis satu goresan. Berbeda dengan prosedur "off-line" seperti Pengenalan Karakter Optik (OCR), ketika hanya produk akhir yang diketahui, algoritma online dapat memberikan tingkat akurasi yang lebih tinggi karena sinyal tambahan seperti urutan temporal dan tekanan goresan tinta individual.

Kasus penggunaan yang disarankan untuk Handwriting Recognition API

Contoh penggunaannya meliputi:

  • Aplikasi pencatatan yang digunakan pengguna untuk membuat catatan tulisan tangan dan menerjemahkannya menjadi teks.
  • Aplikasi Formulir yang memungkinkan pengguna menggunakan input pena atau jari karena keterbatasan waktu.
  • Game yang mengharuskan pengisian huruf atau angka, seperti teka-teki silang, hangman, atau sudoku.

Status saat ini

API Pengenalan Tulis Tangan tersedia dari (Chromium 99).

Cara menggunakan Handwriting Recognition API

Deteksi fitur

Deteksi dukungan browser dengan memeriksa keberadaan metode createHandwritingRecognizer() pada objek navigator:

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

Konsep inti

API Pengenalan Tulis Tangan mengonversi input tulisan tangan menjadi teks, terlepas dari metode input (mouse, sentuh, pena). API ini memiliki empat entity utama:

  1. Titik mewakili tempat pointer pada waktu tertentu.
  2. Goresan terdiri dari satu atau beberapa titik. Perekaman goresan dimulai saat pengguna meletakkan kursor ke bawah (yaitu, mengklik tombol mouse utama, atau menyentuh layar dengan pena atau jari) dan berakhir saat pengguna mengangkat pointer kembali ke atas.
  3. Gambar terdiri dari satu atau beberapa goresan. Pengenalan yang sebenarnya terjadi di tingkat ini.
  4. Pengenal dikonfigurasi dengan bahasa input yang diharapkan. ID ini digunakan untuk membuat instance gambar dengan menerapkan konfigurasi pengenal.

Konsep ini diterapkan sebagai antarmuka dan kamus spesifik, yang akan saya bahas sebentar lagi.

Entitas inti dari Handwriting Recognition API: Satu atau beberapa titik membentuk goresan, satu atau beberapa goresan menyusun gambar, yang dibuat oleh pengenal. Pengenalan sebenarnya terjadi di level gambar.

Membuat pengenal

Untuk mengenali teks dari input tulisan tangan, Anda perlu mendapatkan instance HandwritingRecognizer dengan memanggil navigator.createHandwritingRecognizer() dan meneruskan batasan ke instance tersebut. Batasan menentukan model pengenalan tulis tangan yang harus digunakan. Saat ini, Anda dapat menentukan daftar bahasa sesuai urutan preferensi:

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

Metode ini menampilkan promise yang di-resolve dengan instance HandwritingRecognizer saat browser dapat memenuhi permintaan Anda. Jika tidak, metode ini akan menolak promise dengan error, dan pengenalan tulisan tangan tidak akan tersedia. Oleh karena itu, sebaiknya Anda mengkueri dukungan pengenal untuk fitur pengenalan tertentu terlebih dahulu.

Meminta dukungan pengenal

Dengan memanggil navigator.queryHandwritingRecognizerSupport(), Anda dapat memeriksa apakah platform target mendukung fitur pengenalan tulis tangan yang ingin Anda gunakan. Dalam contoh berikut, developer:

  • ingin mendeteksi teks dalam bahasa Inggris
  • mendapatkan prediksi alternatif dengan kemungkinan yang lebih kecil jika tersedia
  • mendapatkan akses ke hasil segmentasi, yaitu karakter yang dikenali, termasuk titik dan goresan yang membentuknya
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

Metode ini menampilkan promise yang diselesaikan dengan objek hasil. Jika browser mendukung fitur yang ditentukan oleh developer, nilainya akan ditetapkan ke true. Jika tidak, parameter tersebut akan ditetapkan ke false. Anda dapat menggunakan informasi ini untuk mengaktifkan atau menonaktifkan fitur tertentu dalam aplikasi, atau untuk menyesuaikan kueri dan mengirimkan kueri baru.

Mulai menggambar

Dalam aplikasi, Anda harus menawarkan area input tempat pengguna membuat entri tulisan tangan. Untuk alasan performa, sebaiknya terapkan proses ini dengan bantuan objek kanvas. Penerapan yang tepat dari bagian ini berada di luar cakupan artikel ini, tetapi Anda dapat melihat demo untuk mengetahui cara melakukannya.

Untuk memulai gambar baru, panggil metode startDrawing() pada pengenal. Metode ini mengambil objek yang berisi petunjuk berbeda untuk menyesuaikan algoritme pengenalan. Semua petunjuk bersifat opsional:

  • Jenis teks yang dimasukkan: teks, alamat email, angka, atau karakter individual (recognitionType)
  • Jenis perangkat input: input mouse, sentuh, atau pena (inputType)
  • Teks sebelumnya (textContext)
  • Jumlah prediksi alternatif yang lebih kecil kemungkinannya dan harus ditampilkan (alternatives)
  • Daftar karakter yang dapat diidentifikasi pengguna ("grafik") yang kemungkinan besar akan dimasukkan pengguna (graphemeSet)

API Pengenalan Tulis Tangan sangat cocok dengan Peristiwa Pointer yang menyediakan antarmuka abstrak untuk menggunakan input dari perangkat penunjuk apa pun. Argumen peristiwa pointer berisi jenis pointer yang digunakan. Ini berarti Anda dapat menggunakan peristiwa pointer untuk menentukan jenis input secara otomatis. Pada contoh berikut, gambar untuk pengenalan tulis tangan otomatis dibuat saat kemunculan pertama peristiwa pointerdown di area tulis tangan. Karena pointerType mungkin kosong atau disetel ke nilai eksklusif, saya memperkenalkan pemeriksaan konsistensi untuk memastikan hanya nilai yang didukung yang ditetapkan untuk jenis input gambar.

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

Menambahkan {i>stroke<i}

Peristiwa pointerdown juga merupakan tempat yang tepat untuk memulai goresan baru. Untuk melakukannya, buat instance baru HandwritingStroke. Selain itu, Anda harus menyimpan waktu saat ini sebagai titik referensi untuk titik selanjutnya yang ditambahkan:

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

Tambahkan titik

Setelah membuat {i>stroke<i}, Anda harus menambahkan titik pertama secara langsung. Karena Anda akan menambahkan lebih banyak poin nanti, sebaiknya terapkan logika pembuatan titik dalam metode terpisah. Pada contoh berikut, metode addPoint() menghitung waktu berlalu dari stempel waktu referensi. Informasi temporal bersifat opsional, tetapi dapat meningkatkan kualitas pengenalan. Kemudian, kode ini akan membaca koordinat X dan Y dari peristiwa pointer dan menambahkan titik ke goresan saat ini.

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

Pengendali peristiwa pointermove dipanggil saat pointer dipindahkan di layar. Titik-titik tersebut juga perlu ditambahkan ke goresan. Peristiwa ini juga dapat dimunculkan jika pointer tidak dalam status "turun", misalnya saat menggerakkan kursor melintasi layar tanpa menekan tombol mouse. Pengendali peristiwa dari contoh berikut memeriksa apakah ada goresan yang aktif, dan menambahkan titik baru ke sana.

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

Mengenali teks

Saat pengguna mengangkat pointer lagi, Anda dapat menambahkan goresan ke gambar dengan memanggil metode addStroke(). Contoh berikut juga mereset activeStroke, sehingga pengendali pointermove tidak akan menambahkan titik ke goresan yang telah selesai.

Selanjutnya, saatnya mengenali input pengguna dengan memanggil metode getPrediction() pada gambar. Pengenalan biasanya memerlukan waktu kurang dari beberapa ratus milidetik, sehingga Anda dapat menjalankan prediksi berulang kali jika diperlukan. Contoh berikut menjalankan prediksi baru setelah setiap goresan yang selesai.

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

Metode ini menampilkan promise yang di-resolve dengan array prediksi yang diurutkan berdasarkan kemungkinannya. Jumlah elemen bergantung pada nilai yang Anda teruskan ke petunjuk alternatives. Anda dapat menggunakan array ini untuk menampilkan pilihan yang memungkinkan kepada pengguna, dan meminta mereka memilih sebuah opsi. Atau, Anda dapat menggunakan prediksi yang paling mungkin, yaitu yang saya lakukan dalam contoh tersebut.

Objek prediksi berisi teks yang dikenali dan hasil segmentasi opsional, yang akan saya bahas di bagian berikut.

Insight terperinci dengan hasil segmentasi

Jika didukung oleh platform target, objek prediksi juga dapat berisi hasil segmentasi. Ini adalah array yang berisi semua segmen tulisan tangan yang dikenali, kombinasi dari karakter identifikasi pengguna yang dikenali (grapheme) beserta posisinya dalam teks yang dikenali (beginIndex, endIndex), serta goresan dan titik yang membuatnya.

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

Anda dapat menggunakan informasi ini untuk melacak kembali grafik yang dikenali di kanvas.

Kotak-kotak digambar di sekeliling setiap grafem yang dikenali

Pengenalan lengkap

Setelah pengenalan selesai, Anda dapat membebaskan resource dengan memanggil metode clear() pada HandwritingDrawing, dan metode finish() di HandwritingRecognizer:

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

Demo

Komponen web <handwriting-textarea> mengimplementasikan kontrol pengeditan yang ditingkatkan secara progresif dan mampu mengenali tulisan tulis. Dengan mengklik tombol di sudut kanan bawah kontrol pengeditan, Anda akan mengaktifkan mode menggambar. Setelah Anda menyelesaikan gambar, komponen web akan otomatis memulai pengenalan dan menambahkan kembali teks yang dikenali ke kontrol pengeditan. Jika Handwriting Recognition API tidak didukung sama sekali, atau platform tidak mendukung fitur yang diminta, tombol edit akan disembunyikan. Namun, kontrol pengeditan dasar tetap dapat digunakan sebagai <textarea>.

Komponen web menawarkan properti dan atribut untuk menentukan perilaku pengenalan dari luar, termasuk languages dan recognitiontype. Anda dapat menetapkan konten kontrol melalui atribut value:

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

Untuk mendapatkan informasi tentang perubahan nilai, Anda dapat memproses peristiwa input.

Anda dapat mencoba komponen tersebut menggunakan demo ini di Glitch. Pastikan juga untuk melihat kode sumber. Untuk menggunakan kontrol di aplikasi Anda, dapatkan dari npm.

Keamanan dan izin

Tim Chromium merancang dan menerapkan API Pengenalan Tulis Tangan menggunakan prinsip inti yang ditetapkan dalam Mengontrol Akses ke Fitur Platform Web yang Canggih, termasuk kontrol pengguna, transparansi, dan ergonomi.

Kontrol pengguna

Handwriting Recognition API tidak dapat dinonaktifkan oleh pengguna. Fitur ini hanya tersedia untuk situs yang dikirim melalui HTTPS, dan hanya dapat dipanggil dari konteks penjelajahan level atas.

Transparansi

Tidak ada indikasi apakah pengenalan tulis tangan aktif. Untuk mencegah pelacakan sidik jari, browser akan menerapkan tindakan pencegahan, seperti menampilkan permintaan izin kepada pengguna saat mendeteksi kemungkinan penyalahgunaan.

Persistensi izin

Handwriting Recognition API saat ini tidak menampilkan perintah izin apa pun. Dengan demikian, izin tidak perlu dipertahankan dengan cara apa pun.

Masukan

Tim Chromium ingin mengetahui pengalaman Anda saat menggunakan Handwriting Recognition API.

Ceritakan kepada kami tentang desain API

Apakah ada sesuatu pada API yang tidak berfungsi seperti yang Anda harapkan? Atau apakah ada metode atau properti yang hilang yang diperlukan untuk menerapkan ide Anda? Punya pertanyaan atau komentar tentang model keamanan? Laporkan masalah spesifikasi di repo GitHub yang sesuai, atau tambahkan pendapat Anda ke masalah yang sudah ada.

Melaporkan masalah terkait penerapan

Apakah Anda menemukan bug pada implementasi Chromium? Atau apakah implementasinya berbeda dengan spesifikasi? Laporkan bug di new.crbug.com. Pastikan untuk menyertakan detail sebanyak mungkin, petunjuk sederhana untuk mereproduksi, dan masukkan Blink>Handwriting di kotak Komponen. Glitch berfungsi dengan baik untuk berbagi repro dengan cepat dan mudah.

Menunjukkan dukungan untuk API

Apakah Anda berencana menggunakan API Pengenalan Tulis Tangan? Dukungan publik Anda membantu tim Chromium memprioritaskan fitur dan menunjukkan kepada vendor browser lain betapa pentingnya mendukung fitur tersebut.

Bagikan rencana Anda untuk menggunakannya di rangkaian pesan WiCG Discourse. Kirim tweet ke @ChromiumDev menggunakan hashtag #HandwritingRecognition dan beri tahu kami di mana dan bagaimana Anda menggunakannya.

Ucapan terima kasih

Artikel ini ditinjau oleh Joe Medley, Honglin Yu, dan Jiewei Qian. Banner besar oleh Samir Bouaked di Unsplash.