Dengan pengenalan tinta digital ML Kit, Anda dapat mengenali teks yang ditulis tangan pada tampilan digital dalam ratusan bahasa, serta mengklasifikasikan sketsa.
Cobalah
- Cobalah aplikasi contoh untuk melihat contoh penggunaan API ini.
Sebelum memulai
- Dalam file
build.gradle
level project, pastikan Anda menyertakan repositori Maven Google di bagianbuildscript
danallprojects
. - Tambahkan dependensi untuk library Android ML Kit ke file Gradle level aplikasi modul Anda, biasanya
app/build.gradle
:
dependencies {
// ...
implementation 'com.google.mlkit:digital-ink-recognition:18.1.0'
}
Sekarang Anda siap untuk mulai mengenali teks dalam objek Ink
.
Membuat objek Ink
Cara utama untuk membuat objek Ink
adalah dengan menggambarnya di layar sentuh. Aktif
Android, Anda dapat menggunakan
Kanvas untuk
tujuan ini. Nama
Pengendali peristiwa sentuh
harus memanggil addNewTouchEvent()
menampilkan cuplikan kode berikut untuk menyimpan titik-titik dalam goresan
gambar pengguna ke dalam objek Ink
.
Pola umum ini ditunjukkan dalam cuplikan kode berikut. Lihat Contoh panduan memulai ML Kit untuk contoh yang lebih lengkap.
Kotlin
var inkBuilder = Ink.builder() lateinit var strokeBuilder: Ink.Stroke.Builder // Call this each time there is a new event. fun addNewTouchEvent(event: MotionEvent) { val action = event.actionMasked val x = event.x val y = event.y var t = System.currentTimeMillis() // If your setup does not provide timing information, you can omit the // third paramater (t) in the calls to Ink.Point.create when (action) { MotionEvent.ACTION_DOWN -> { strokeBuilder = Ink.Stroke.builder() strokeBuilder.addPoint(Ink.Point.create(x, y, t)) } MotionEvent.ACTION_MOVE -> strokeBuilder!!.addPoint(Ink.Point.create(x, y, t)) MotionEvent.ACTION_UP -> { strokeBuilder.addPoint(Ink.Point.create(x, y, t)) inkBuilder.addStroke(strokeBuilder.build()) } else -> { // Action not relevant for ink construction } } } ... // This is what to send to the recognizer. val ink = inkBuilder.build()
Java
Ink.Builder inkBuilder = Ink.builder(); Ink.Stroke.Builder strokeBuilder; // Call this each time there is a new event. public void addNewTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); long t = System.currentTimeMillis(); // If your setup does not provide timing information, you can omit the // third paramater (t) in the calls to Ink.Point.create int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: strokeBuilder = Ink.Stroke.builder(); strokeBuilder.addPoint(Ink.Point.create(x, y, t)); break; case MotionEvent.ACTION_MOVE: strokeBuilder.addPoint(Ink.Point.create(x, y, t)); break; case MotionEvent.ACTION_UP: strokeBuilder.addPoint(Ink.Point.create(x, y, t)); inkBuilder.addStroke(strokeBuilder.build()); strokeBuilder = null; break; } } ... // This is what to send to the recognizer. Ink ink = inkBuilder.build();
Mendapatkan instance DigitalInkKenalir
Untuk melakukan pengenalan, kirim instance Ink
ke
Objek DigitalInkRecognizer
. Kode di bawah ini menunjukkan cara membuat instance
pengenal dari tag BCP-47.
Kotlin
// Specify the recognition model for a language var modelIdentifier: DigitalInkRecognitionModelIdentifier try { modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US") } catch (e: MlKitException) { // language tag failed to parse, handle error. } if (modelIdentifier == null) { // no model was found, handle error. } var model: DigitalInkRecognitionModel = DigitalInkRecognitionModel.builder(modelIdentifier).build() // Get a recognizer for the language var recognizer: DigitalInkRecognizer = DigitalInkRecognition.getClient( DigitalInkRecognizerOptions.builder(model).build())
Java
// Specify the recognition model for a language DigitalInkRecognitionModelIdentifier modelIdentifier; try { modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US"); } catch (MlKitException e) { // language tag failed to parse, handle error. } if (modelIdentifier == null) { // no model was found, handle error. } DigitalInkRecognitionModel model = DigitalInkRecognitionModel.builder(modelIdentifier).build(); // Get a recognizer for the language DigitalInkRecognizer recognizer = DigitalInkRecognition.getClient( DigitalInkRecognizerOptions.builder(model).build());
Memproses objek Ink
Kotlin
recognizer.recognize(ink) .addOnSuccessListener { result: RecognitionResult -> // `result` contains the recognizer's answers as a RecognitionResult. // Logs the text from the top candidate. Log.i(TAG, result.candidates[0].text) } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error during recognition: $e") }
Java
recognizer.recognize(ink) .addOnSuccessListener( // `result` contains the recognizer's answers as a RecognitionResult. // Logs the text from the top candidate. result -> Log.i(TAG, result.getCandidates().get(0).getText())) .addOnFailureListener( e -> Log.e(TAG, "Error during recognition: " + e));
Kode contoh di atas mengasumsikan bahwa model pengenalan telah diunduh, seperti yang dijelaskan di bagian berikutnya.
Mengelola download model
Sementara API pengenalan tinta digital
mendukung ratusan bahasa, masing-masing
bahasa mengharuskan beberapa data didownload sebelum pengenalan apa pun. Sekitar
Diperlukan penyimpanan sebesar 20 MB per bahasa. Hal ini ditangani oleh
Objek RemoteModelManager
.
Download model baru
Kotlin
import com.google.mlkit.common.model.DownloadConditions import com.google.mlkit.common.model.RemoteModelManager var model: DigitalInkRecognitionModel = ... val remoteModelManager = RemoteModelManager.getInstance() remoteModelManager.download(model, DownloadConditions.Builder().build()) .addOnSuccessListener { Log.i(TAG, "Model downloaded") } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error while downloading a model: $e") }
Java
import com.google.mlkit.common.model.DownloadConditions; import com.google.mlkit.common.model.RemoteModelManager; DigitalInkRecognitionModel model = ...; RemoteModelManager remoteModelManager = RemoteModelManager.getInstance(); remoteModelManager .download(model, new DownloadConditions.Builder().build()) .addOnSuccessListener(aVoid -> Log.i(TAG, "Model downloaded")) .addOnFailureListener( e -> Log.e(TAG, "Error while downloading a model: " + e));
Memeriksa apakah model sudah didownload
Kotlin
var model: DigitalInkRecognitionModel = ... remoteModelManager.isModelDownloaded(model)
Java
DigitalInkRecognitionModel model = ...; remoteModelManager.isModelDownloaded(model);
Menghapus model yang didownload
Menghapus model dari penyimpanan perangkat akan mengosongkan ruang penyimpanan.
Kotlin
var model: DigitalInkRecognitionModel = ... remoteModelManager.deleteDownloadedModel(model) .addOnSuccessListener { Log.i(TAG, "Model successfully deleted") } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error while deleting a model: $e") }
Java
DigitalInkRecognitionModel model = ...; remoteModelManager.deleteDownloadedModel(model) .addOnSuccessListener( aVoid -> Log.i(TAG, "Model successfully deleted")) .addOnFailureListener( e -> Log.e(TAG, "Error while deleting a model: " + e));
Tips untuk meningkatkan akurasi pengenalan teks
Keakuratan pengenalan teks dapat bervariasi di berbagai bahasa. Akurasi juga bergantung tentang gaya penulisan. Pengenalan Tinta Digital dilatih untuk menangani berbagai jenis gaya penulisan, hasilnya dapat bervariasi dari satu pengguna ke pengguna lainnya.
Berikut beberapa cara untuk meningkatkan akurasi pengenal teks. Perhatikan bahwa teknik-teknik ini melakukan tidak berlaku untuk pengklasifikasi gambar untuk emoji, gambar otomatis, dan bentuk.
Area menulis
Banyak aplikasi memiliki area penulisan yang didefinisikan dengan baik untuk input pengguna. Arti dari suatu simbol adalah sebagian ditentukan oleh ukurannya yang relatif terhadap ukuran area tulisan yang memuatnya. Misalnya, perbedaan antara huruf "o" kecil atau besar atau "c", dan koma versus garis miring.
Memberi tahu pengenal tentang lebar dan tinggi area tulisan dapat meningkatkan akurasi. Namun, pengenal mengasumsikan bahwa area penulisan hanya berisi satu baris teks. Jika fisik area tulisannya cukup besar sehingga pengguna dapat menulis dua baris atau lebih, Anda mungkin akan lebih hasil dengan meneruskan WritingArea dengan ketinggian yang merupakan perkiraan terbaik Anda mengenai tinggi satu baris teks. Objek WritingArea yang Anda teruskan ke pengenal tidak harus sesuai persis dengan area tulisan fisik di layar. Mengubah tinggi WritingArea dengan cara ini berfungsi lebih baik di beberapa bahasa dibandingkan bahasa lainnya.
Saat menetapkan area penulisan, tentukan lebar dan tingginya dalam unit yang sama dengan goresan. pada koordinat tertentu. Argumen koordinat x,y tidak memiliki persyaratan satuan - API menormalisasi semua satu-satunya hal yang penting adalah ukuran relatif dan posisi goresan. Anda bebas untuk meneruskan koordinat dalam skala apa pun yang masuk akal untuk sistem Anda.
Pra-konteks
Pra-konteks adalah teks yang tepat mendahului goresan dalam Ink
yang Anda
oleh orang lain. Anda dapat membantu pengenal dengan memberi tahu tentang prakonteks.
Misalnya, huruf tulis tangan "n" dan "u" sering disalahartikan. Jika pengguna memiliki sudah memasukkan sebagian kata "arg", mereka mungkin melanjutkan dengan goresan yang dapat dikenali sebagai "umen" atau "nment". Menentukan "arg" pra-konteks menyelesaikan ambiguitas ini, karena kata "argumen" kemungkinannya lebih besar daripada "argnment".
Pra-konteks juga dapat membantu pengenal untuk mengidentifikasi jeda kata, spasi antar-kata. Anda dapat mengetik karakter spasi, tetapi Anda tidak dapat menggambarnya, jadi bagaimana pengenal dapat menentukan kapan satu kata berakhir yang berikutnya dimulai? Jika pengguna sudah menulis "halo" dan dilanjutkan dengan kata "world", tanpa pra-konteks, pengenal akan menampilkan string "world". Namun, jika Anda menentukan pra-konteks "hello", model akan menampilkan string " dunia", dengan spasi di awal, karena dunia" lebih masuk akal daripada "helloword".
Anda harus menyediakan string pra-konteks sepanjang mungkin, hingga 20 karakter, termasuk spasi. Jika string lebih panjang, pengenal hanya menggunakan 20 karakter terakhir.
Contoh kode di bawah ini memperlihatkan cara menentukan area penulisan dan menggunakan
RecognitionContext
untuk menentukan prakonteks.
Kotlin
var preContext : String = ...; var width : Float = ...; var height : Float = ...; val recognitionContext : RecognitionContext = RecognitionContext.builder() .setPreContext(preContext) .setWritingArea(WritingArea(width, height)) .build() recognizer.recognize(ink, recognitionContext)
Java
String preContext = ...; float width = ...; float height = ...; RecognitionContext recognitionContext = RecognitionContext.builder() .setPreContext(preContext) .setWritingArea(new WritingArea(width, height)) .build(); recognizer.recognize(ink, recognitionContext);
Pengurutan goresan
Akurasi pengenalan sensitif terhadap urutan goresan. Pengenal mengharapkan {i>stroke<i} untuk terjadi dalam urutan yang secara alami akan ditulis orang; misalnya kiri-ke-kanan untuk bahasa Inggris. Semua kasus yang menyimpang dari pola ini, seperti menulis kalimat bahasa Inggris yang dimulai dengan kata terakhir, memberikan hasil yang kurang akurat.
Contoh lain adalah saat sebuah kata di tengah Ink
dihapus dan diganti dengan
kata lain. Revisi mungkin ada di tengah kalimat, tetapi {i>stroke<i} untuk revisi
berada di akhir urutan {i>stroke<i}.
Dalam hal ini, sebaiknya kirimkan kata yang baru ditulis secara terpisah ke API dan gabungkan
hasil dengan pengenalan sebelumnya menggunakan logika Anda sendiri.
Menangani bentuk yang ambigu
Ada kasus saat arti bentuk yang diberikan kepada pengenal tidak jelas. Sebagai contoh, persegi panjang dengan tepi yang sangat membulat dapat dilihat sebagai persegi panjang atau elips.
Kasus yang tidak jelas ini dapat ditangani menggunakan skor pengenalan jika tersedia. Hanya
pengklasifikasi bentuk akan memberikan skor. Jika model sangat yakin, skor hasil teratas akan
jauh lebih baik dari yang terbaik kedua. Jika ada ketidakpastian, skor untuk dua hasil teratas akan
menjadi dekat. Selain itu, perlu diingat bahwa pengklasifikasi bentuk menafsirkan seluruh Ink
sebagai
bentuk tunggal. Misalnya, jika Ink
berisi persegi panjang dan elips di samping masing-masing
lainnya, pengenal dapat mengembalikan salah satunya (atau sesuatu yang sama sekali berbeda) sebagai
karena satu kandidat pengenalan tidak dapat merepresentasikan dua bentuk.