Dengan pengenalan tinta digital ML Kit, Anda dapat mengenali teks tulisan tangan pada platform digital dalam ratusan bahasa, serta mengklasifikasikan sketsa.
Cobalah
- Coba aplikasi contoh untuk melihat contoh penggunaan API ini.
Sebelum memulai
- Dalam file
build.gradlelevel project, pastikan Anda memasukkan repositori Maven Google di bagianbuildscriptdanallprojects. - 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:19.0.0'
}
Kini Anda siap untuk mulai mengenali teks dalam objek Ink.
Membuat objek Ink
Cara utama untuk membuat objek Ink adalah dengan menggambarnya di layar sentuh. Di
Android, Anda dapat menggunakan
Canvas untuk
tujuan ini. Pengendali
peristiwa sentuh
Anda harus memanggil metode addNewTouchEvent()
yang ditampilkan dalam cuplikan kode berikut untuk menyimpan titik dalam goresan yang
digambar pengguna ke dalam objek Ink.
Pola umum ini ditunjukkan dalam cuplikan kode berikut. Lihat contoh panduan memulai ML Kit untuk mengetahui 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 DigitalInkRecognizer
Untuk melakukan pengenalan, kirim instance Ink ke objek DigitalInkRecognizer. Kode di bawah menunjukkan cara membuat instance pengenal tersebut 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 didownload, seperti yang dijelaskan di bagian berikutnya.
Mengelola download model
Meskipun API pengenalan tinta digital mendukung ratusan bahasa, setiap
bahasa memerlukan beberapa data untuk didownload sebelum pengenalan apa pun. Diperlukan penyimpanan sekitar 20 MB per bahasa. Proses ini ditangani oleh objek RemoteModelManager.
Mendownload 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
Akurasi pengenalan teks dapat bervariasi di berbagai bahasa. Akurasi juga bergantung pada gaya penulisan. Meskipun 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 ini tidak berlaku untuk pengklasifikasi gambar untuk emoji, autodraw, dan bentuk.
Area penulisan
Banyak aplikasi memiliki area penulisan yang ditentukan dengan baik untuk input pengguna. Arti simbol sebagian ditentukan oleh ukurannya yang relatif terhadap ukuran area penulisan yang memuatnya. Misalnya, perbedaan antara huruf kecil atau besar "o" atau "c", dan koma versus garis miring.
Memberi tahu pengenal lebar dan tinggi area penulisan dapat meningkatkan akurasi. Namun, pengenal mengasumsikan bahwa area penulisan hanya berisi satu baris teks. Jika area penulisan fisik cukup besar untuk memungkinkan pengguna menulis dua baris atau lebih, Anda mungkin mendapatkan hasil yang lebih baik dengan meneruskan WritingArea dengan tinggi yang merupakan perkiraan terbaik Anda untuk tinggi satu baris teks. Objek WritingArea yang Anda teruskan ke pengenal tidak harus sama persis dengan area penulisan fisik di layar. Mengubah tinggi WritingArea dengan cara ini berfungsi lebih baik dalam beberapa bahasa daripada bahasa lainnya.
Saat Anda menentukan area penulisan, tentukan lebar dan tingginya dalam unit yang sama dengan koordinat goresan. Argumen koordinat x,y tidak memiliki persyaratan unit - API menormalisasi semua unit, sehingga yang penting hanyalah ukuran dan posisi relatif goresan. Anda bebas meneruskan koordinat dalam skala apa pun yang sesuai untuk sistem Anda.
Pra-konteks
Pra-konteks adalah teks yang langsung mendahului goresan di Ink yang Anda
coba kenali. Anda dapat membantu pengenal dengan memberitahunya tentang pra-konteks.
Misalnya, huruf kursif "n" dan "u" sering kali salah diidentifikasi satu sama lain. Jika pengguna telah memasukkan kata parsial "arg", mereka dapat melanjutkan dengan goresan yang dapat dikenali sebagai "ument" atau "nment". Menentukan pra-konteks "arg" akan mengatasi ambiguitas, karena kata "argument" lebih mungkin muncul daripada "argnment".
Pra-konteks juga dapat membantu pengenal mengidentifikasi jeda kata, yaitu spasi di antara kata. Anda dapat mengetik karakter spasi, tetapi Anda tidak dapat menggambarnya. Jadi, bagaimana pengenal dapat menentukan kapan satu kata berakhir dan kata berikutnya dimulai? Jika pengguna telah menulis "halo" dan melanjutkan dengan kata tertulis "dunia", tanpa pra-konteks, pengenal akan menampilkan string "dunia". Namun, jika Anda menentukan pra-konteks "hello", model akan menampilkan string " world", dengan spasi di awal, karena "hello world" lebih masuk akal daripada "helloword".
Anda harus memberikan string pra-konteks sepanjang mungkin, hingga 20 karakter, termasuk spasi. Jika string lebih panjang, pengenal hanya akan menggunakan 20 karakter terakhir.
Contoh kode di bawah menunjukkan cara menentukan area penulisan dan menggunakan
objek RecognitionContext untuk menentukan pra-konteks.
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);
Urutan goresan
Akurasi pengenalan sensitif terhadap urutan goresan. Alat pengenal mengharapkan goresan terjadi dalam urutan yang biasa ditulis orang; misalnya dari kiri ke kanan untuk bahasa Inggris. Setiap kasus yang menyimpang dari pola ini, seperti menulis kalimat bahasa Inggris yang dimulai dengan kata terakhir, akan memberikan hasil yang kurang akurat.
Contoh lainnya adalah saat sebuah kata di tengah Ink dihapus dan diganti dengan
kata lain. Revisi mungkin berada di tengah kalimat, tetapi goresan untuk revisi
berada di akhir urutan goresan.
Dalam hal ini, sebaiknya kirim kata yang baru ditulis secara terpisah ke API dan gabungkan hasilnya dengan pengenalan sebelumnya menggunakan logika Anda sendiri.
Menangani bentuk yang ambigu
Ada kasus saat arti bentuk yang diberikan ke pengenal bersifat ambigu. Misalnya, persegi panjang dengan tepi yang sangat bulat dapat dilihat sebagai persegi panjang atau elips.
Kasus yang tidak jelas ini dapat ditangani dengan menggunakan skor pengenalan jika tersedia. Hanya pengklasifikasi bentuk yang memberikan skor. Jika model sangat yakin, skor hasil teratas akan jauh lebih baik daripada hasil terbaik kedua. Jika ada ketidakpastian, skor untuk dua hasil teratas akan
berdekatan. Selain itu, perlu diingat bahwa pengklasifikasi bentuk menafsirkan seluruh Ink sebagai
satu bentuk. Misalnya, jika Ink berisi persegi panjang dan elips yang bersebelahan, pengenal dapat menampilkan salah satunya (atau sesuatu yang sama sekali berbeda) sebagai hasilnya, karena satu kandidat pengenalan tidak dapat mewakili dua bentuk.