Anda dapat menggunakan ML Kit untuk mengenali teks dalam gambar atau video, seperti teks rambu jalan. Karakteristik utama dari fitur ini adalah:
Fitur | Tidak Dipaketkan | Paket |
---|---|---|
Nama perpustakaan | com.google.android.gms:play-services-mlkit-text-recognition
com.google.android.gms:play-services-mlkit-text-recognition-chinese com.google.android.gms:play-services-mlkit-text-recognition-devanagari com.google.android.gms:play-services-mlkit-text-recognition-japanese com.google.android.gms:play-services-mlkit-text-recognition-korean |
com.google.mlkit:text-recognition
com.google.mlkit:text-recognition-chinese com.google.mlkit:text-recognition-devanagari com.google.mlkit:text-recognition-japanese com.google.mlkit:text-recognition-korean |
Penerapan | Model didownload secara dinamis melalui Layanan Google Play. | Model ditautkan secara statis ke aplikasi Anda pada waktu build. |
Ukuran aplikasi | Peningkatan ukuran sekitar 260 KB per arsitektur skrip. | Peningkatan ukuran sekitar 4 MB per skrip per arsitektur. |
Waktu inisialisasi | Mungkin harus menunggu model didownload sebelum digunakan pertama kali. | Model akan segera tersedia. |
Performa | Secara real-time di sebagian besar perangkat untuk library skrip Latin, lebih lambat untuk yang lain. | Secara real-time di sebagian besar perangkat untuk library skrip Latin, lebih lambat untuk yang lain. |
Cobalah
- Cobalah aplikasi contoh untuk melihat contoh penggunaan API ini.
- Coba kode sendiri dengan codelab 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
:Untuk memaketkan model dengan aplikasi Anda:
dependencies { // To recognize Latin script implementation 'com.google.mlkit:text-recognition:16.0.1' // To recognize Chinese script implementation 'com.google.mlkit:text-recognition-chinese:16.0.1' // To recognize Devanagari script implementation 'com.google.mlkit:text-recognition-devanagari:16.0.1' // To recognize Japanese script implementation 'com.google.mlkit:text-recognition-japanese:16.0.1' // To recognize Korean script implementation 'com.google.mlkit:text-recognition-korean:16.0.1' }
Untuk menggunakan model di Layanan Google Play:
dependencies { // To recognize Latin script implementation 'com.google.android.gms:play-services-mlkit-text-recognition:19.0.1' // To recognize Chinese script implementation 'com.google.android.gms:play-services-mlkit-text-recognition-chinese:16.0.1' // To recognize Devanagari script implementation 'com.google.android.gms:play-services-mlkit-text-recognition-devanagari:16.0.1' // To recognize Japanese script implementation 'com.google.android.gms:play-services-mlkit-text-recognition-japanese:16.0.1' // To recognize Korean script implementation 'com.google.android.gms:play-services-mlkit-text-recognition-korean:16.0.1' }
Jika memilih untuk menggunakan model ini di Layanan Google Play, Anda dapat mengonfigurasi aplikasi untuk mengunduh model secara otomatis ke perangkat setelah aplikasi Anda diinstal dari Play Store. Untuk melakukannya, tambahkan ke file
AndroidManifest.xml
aplikasi Anda:<application ...> ... <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="ocr" > <!-- To use multiple models: android:value="ocr,ocr_chinese,ocr_devanagari,ocr_japanese,ocr_korean,..." --> </application>
Anda juga dapat memeriksa ketersediaan model dan meminta download secara eksplisit melalui layanan Google Play ModuleInstallClient API. Jika Anda tidak mengaktifkan model waktu penginstalan mengunduh atau meminta unduhan eksplisit, model diunduh pertama kali saat Anda menjalankan pemindai. Permintaan yang Anda buat sebelum download selesai tidak akan memberikan hasil.
1. Membuat instance TextRecognizer
Membuat instance TextRecognizer
, dengan meneruskan opsi
yang terkait dengan library yang Anda deklarasikan dependensinya di atas:
// When using Latin script library val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) // When using Chinese script library val recognizer = TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build()) // When using Devanagari script library val recognizer = TextRecognition.getClient(DevanagariTextRecognizerOptions.Builder().build()) // When using Japanese script library val recognizer = TextRecognition.getClient(JapaneseTextRecognizerOptions.Builder().build()) // When using Korean script library val recognizer = TextRecognition.getClient(KoreanTextRecognizerOptions.Builder().build())
// When using Latin script library TextRecognizer recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS); // When using Chinese script library TextRecognizer recognizer = TextRecognition.getClient(new ChineseTextRecognizerOptions.Builder().build()); // When using Devanagari script library TextRecognizer recognizer = TextRecognition.getClient(new DevanagariTextRecognizerOptions.Builder().build()); // When using Japanese script library TextRecognizer recognizer = TextRecognition.getClient(new JapaneseTextRecognizerOptions.Builder().build()); // When using Korean script library TextRecognizer recognizer = TextRecognition.getClient(new KoreanTextRecognizerOptions.Builder().build());
2. Menyiapkan gambar input
Untuk mengenali teks dalam gambar, buat objek InputImage
dari
baik Bitmap
, media.Image
, ByteBuffer
, array byte, atau file pada
perangkat seluler. Lalu, teruskan objek InputImage
ke
Metode processImage
TextRecognizer
.
Anda dapat membuat InputImage
dari berbagai sumber, masing-masing akan dijelaskan di bawah ini.
Menggunakan media.Image
Untuk membuat InputImage
dari objek media.Image
, seperti saat Anda mengambil gambar dari
kamera perangkat, teruskan objek media.Image
dan objek
rotasi ke InputImage.fromMediaImage()
.
Jika Anda menggunakan
library CameraX, OnImageCapturedListener
dan
Class ImageAnalysis.Analyzer
menghitung nilai rotasi
keamanan untuk Anda.
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
Jika Anda tidak menggunakan pustaka kamera yang memberi derajat rotasi gambar, Anda bisa menghitungnya dari derajat rotasi perangkat dan orientasi kamera sensor di perangkat:
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
Lalu, teruskan objek media.Image
dan
nilai derajat rotasi ke InputImage.fromMediaImage()
:
val image = InputImage.fromMediaImage(mediaImage, rotation)
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
Menggunakan URI file
Untuk membuat InputImage
dari URI file, teruskan konteks aplikasi dan URI file ke
InputImage.fromFilePath()
. Hal ini berguna ketika Anda
gunakan intent ACTION_GET_CONTENT
untuk meminta pengguna memilih
gambar dari aplikasi galeri mereka.
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
InputImage image;
try {
image = InputImage.fromFilePath(context, uri);
} catch (IOException e) {
e.printStackTrace();
}
Menggunakan ByteBuffer
atau ByteArray
Untuk membuat InputImage
dari ByteBuffer
atau ByteArray
, hitung gambar terlebih dahulu
derajat rotasi seperti yang dijelaskan sebelumnya untuk input media.Image
.
Lalu, buat objek InputImage
dengan buffer atau array, beserta elemen
tinggi, lebar, format encoding warna, dan derajat rotasi:
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
Menggunakan Bitmap
Untuk membuat InputImage
dari objek Bitmap
, buat deklarasi berikut:
val image = InputImage.fromBitmap(bitmap, 0)
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
Gambar direpresentasikan oleh objek Bitmap
bersama dengan derajat rotasi.
3. Memproses gambar
Teruskan gambar ke metode process
:
val result = recognizer.process(image) .addOnSuccessListener { visionText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Task<Text> result = recognizer.process(image) .addOnSuccessListener(new OnSuccessListener<Text>() { @Override public void onSuccess(Text visionText) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
4. Ekstrak teks dari blok teks yang dikenali
Jika operasi pengenalan teks berhasil, objek Text
akan diteruskan ke
pemroses yang berhasil. Objek Text
berisi teks lengkap yang dikenali di
gambar dan nol atau beberapa objek TextBlock
.
Setiap TextBlock
mewakili blok teks persegi panjang,
yang berisi nol atau beberapa objek Line
. Masing-masing
Objek Line
mewakili baris teks, yang berisi nol
objek Element
atau lebih. Setiap Element
objek mewakili kata atau entitas seperti kata, yang berisi nol atau lebih
Objek Symbol
. Setiap Symbol
mewakili karakter, digit, atau entitas seperti kata.
Untuk setiap TextBlock
, Line
,
Element
dan Symbol
objek, Anda
bisa mendapatkan teks yang dikenali di area, koordinat pembatas
wilayah dan banyak atribut lain seperti informasi rotasi, skor keyakinan
dll.
Contoh:
val resultText = result.text for (block in result.textBlocks) { val blockText = block.text val blockCornerPoints = block.cornerPoints val blockFrame = block.boundingBox for (line in block.lines) { val lineText = line.text val lineCornerPoints = line.cornerPoints val lineFrame = line.boundingBox for (element in line.elements) { val elementText = element.text val elementCornerPoints = element.cornerPoints val elementFrame = element.boundingBox } } }
String resultText = result.getText(); for (Text.TextBlock block : result.getTextBlocks()) { String blockText = block.getText(); Point[] blockCornerPoints = block.getCornerPoints(); Rect blockFrame = block.getBoundingBox(); for (Text.Line line : block.getLines()) { String lineText = line.getText(); Point[] lineCornerPoints = line.getCornerPoints(); Rect lineFrame = line.getBoundingBox(); for (Text.Element element : line.getElements()) { String elementText = element.getText(); Point[] elementCornerPoints = element.getCornerPoints(); Rect elementFrame = element.getBoundingBox(); for (Text.Symbol symbol : element.getSymbols()) { String symbolText = symbol.getText(); Point[] symbolCornerPoints = symbol.getCornerPoints(); Rect symbolFrame = symbol.getBoundingBox(); } } } }
Panduan gambar input
-
Agar ML Kit dapat mengenali teks secara akurat, gambar input harus berisi teks yang diwakili oleh data piksel yang memadai. Idealnya, setiap karakter minimal harus 16x16 piksel. Umumnya tidak ada akurasi keuntungan akurasi untuk karakter yang menjadi lebih besar dari 24x24 {i>pixel<i}.
Jadi, misalnya, gambar 640x480 mungkin cocok untuk memindai kartu nama yang menempati lebar penuh gambar. Untuk memindai dokumen yang dicetak pada kertas berukuran huruf, gambar 720x1280 piksel mungkin diperlukan.
-
Fokus gambar yang buruk dapat memengaruhi akurasi pengenalan teks. Jika Anda tidak mendapatkan hasil yang dapat diterima, coba minta pengguna untuk mengambil ulang gambar.
-
Jika Anda mengenali teks dalam aplikasi {i>real-time<i}, Anda harus mempertimbangkan dimensi keseluruhan gambar input. Lebih kecil gambar dapat diproses lebih cepat. Untuk mengurangi latensi, pastikan teks menempati sebanyak gambar sebaik mungkin, dan ambil gambar dengan resolusi yang lebih rendah (mengingat akurasi persyaratan yang disebutkan di atas). Untuk informasi selengkapnya, lihat Tips untuk meningkatkan performa.
Tips untuk meningkatkan performa
- Jika Anda menggunakan
Camera
ataucamera2
API, men-throttle panggilan ke detektor. Jika video baru {i>frame<i} menjadi tersedia saat detektor sedang berjalan, hapus {i>frame<i} tersebut. LihatVisionProcessorBase
dalam aplikasi contoh panduan memulai untuk digunakan sebagai contoh. - Jika Anda menggunakan
CameraX
API, pastikan strategi tekanan balik ditetapkan ke nilai defaultnyaImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
. Hal ini menjamin hanya satu gambar yang akan dikirimkan untuk analisis pada satu waktu. Jika lebih banyak gambar yang dihasilkan ketika penganalisis sedang sibuk, mereka akan dibuang secara otomatis dan tidak diantrekan pengiriman. Setelah gambar yang dianalisis ditutup dengan memanggil ImageProxy.close(), gambar terbaru berikutnya akan dikirim. - Jika Anda menggunakan output detektor untuk menempatkan grafik
gambar input, pertama-tama dapatkan hasilnya dari ML Kit, lalu render gambar
dan overlay dalam satu langkah. Tindakan ini merender ke permukaan tampilan
hanya sekali untuk setiap {i>input frame<i}. Lihat
CameraSourcePreview
danGraphicOverlay
dalam aplikasi contoh panduan memulai sebagai contoh. - Jika Anda menggunakan Camera2 API, ambil gambar dengan
Format
ImageFormat.YUV_420_888
. Jika Anda menggunakan Camera API versi lama, ambil gambar dengan FormatImageFormat.NV21
. - Sebaiknya ambil gambar dengan resolusi yang lebih rendah. Namun, perlu diingat persyaratan dimensi gambar API ini.