Görüntülerdeki metinleri tanımak için Makine Öğrenimi Kiti'ni kullanabilirsiniz. ML Kit'te, resimlerdeki metinlerin (ör. sokak tabelalarındaki metinler) tanınmaya uygun genel amaçlı bir API'ye ve belge metinlerini tanımak için optimize edilmiş bir API'ye sahip olması gerekir. Genel amaçlı API'de hem cihaz üzerinde hem bulut tabanlı modeller bulunur. Doküman metni tanıma yalnızca bulut tabanlı bir model olarak kullanılabilir. Bulut ve cihaz üzerinde modellerin karşılaştırması için genel bakış bölümüne bakın.
Başlamadan önce
- Henüz yapmadıysanız Firebase'i Android projenize ekleyin.
- Modül (uygulama düzeyinde) Gradle dosyanıza (genellikle
app/build.gradle
) ML Kit Android kitaplıkları için bağımlılıkları ekleyin:apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-vision:24.0.3' }
-
İsteğe bağlı ancak önerilir: Cihaz üzerinde API'yi kullanıyorsanız uygulamanızı Play Store'dan yüklendikten sonra ML modelini cihaza otomatik olarak indirecek şekilde yapılandırın.
Bunu yapmak için uygulamanızın
AndroidManifest.xml
dosyasına aşağıdaki beyanı ekleyin:<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="ocr" /> <!-- To use multiple models: android:value="ocr,model2,model3" --> </application>
Yükleme zamanı modellerinin indirilmesini etkinleştirmezseniz model, cihaz üzerinde algılayıcıyı ilk kez çalıştırdığınızda indirilir. İndirme işlemi tamamlanmadan önce yaptığınız istekler sonuç vermez. -
Bulut tabanlı modeli kullanmak istiyorsanız ve henüz projenizde Cloud tabanlı API'leri etkinleştirmediyseniz bunu hemen yapın:
- Firebase konsolunun ML Kit API'leri sayfasını açın.
-
Projenizi daha önce Blaze fiyatlandırma planına yükseltmediyseniz Yükselt'i tıklayarak yükseltme yapabilirsiniz. (Yalnızca projeniz Blaze planında değilse yükseltme yapmanız istenir.)
Bulut tabanlı API'ler yalnızca Blaze düzeyindeki projelerde kullanılabilir.
- Cloud tabanlı API'ler henüz etkinleştirilmemişse Cloud tabanlı API'leri etkinleştir'i tıklayın.
Yalnızca cihaz üzerindeki modeli kullanmak istiyorsanız bu adımı atlayabilirsiniz.
Artık resimlerdeki metinleri tanımaya hazırsınız.
Giriş resmi kuralları
-
Makine Öğrenimi Kiti'nin metni doğru bir şekilde tanıyabilmesi için giriş resimleri, yeterli piksel verisiyle temsil edilen metin içermelidir. İdeal olarak, Latin metinleri için her karakter en az 16x16 piksel olmalıdır. Çince, Japonca ve Korece metinler (yalnızca bulut tabanlı API'ler tarafından desteklenir) için her karakter 24x24 piksel olmalıdır. Tüm dillerde, karakterlerin 24x24 pikselden büyük olması genellikle herhangi bir doğruluk avantajı sağlamaz.
Bu nedenle, örneğin, 640x480 boyutundaki bir resim, resmin tam genişliğini kaplayan bir kartviziti taramak için iyi sonuç verebilir. Harf boyutunda kağıda basılı bir dokümanı taramak için 720x1280 piksel boyutunda bir resim gerekli olabilir.
-
Kötü resim odağı, metin tanıma doğruluğunu olumsuz etkileyebilir. Kabul edilebilir sonuçlar alamıyorsanız kullanıcıdan resmi yeniden çekmesini isteyin.
-
Metinleri gerçek zamanlı bir uygulamada tanıyorsanız giriş resimlerinin genel boyutlarını da göz önünde bulundurmak isteyebilirsiniz. Daha küçük resimler daha hızlı işlenebilir. Bu nedenle, gecikmeyi azaltmak için görüntüleri düşük çözünürlükte çekin (yukarıdaki doğruluk koşullarını göz önünde bulundurun) ve metnin, resmin olabildiğince büyük bir kısmını kapladığından emin olun. Gerçek zamanlı performansı iyileştirmeye yönelik ipuçları konusunu da inceleyin.
Resimlerdeki metinleri tanıyın
Cihaz üzerinde veya bulut tabanlı bir model kullanarak görüntüdeki metinleri tanımak için metin tanıyıcıyı aşağıda açıklanan şekilde çalıştırın.
1. Metin tanıyıcıyı çalıştır
Bir görüntüdeki metni tanımak içinBitmap
, media.Image
, ByteBuffer
, bayt dizisi veya cihazdaki bir dosyadan FirebaseVisionImage
nesnesi oluşturun. Ardından FirebaseVisionImage
nesnesini FirebaseVisionTextRecognizer
öğesinin processImage
yöntemine iletin.
Resminizden bir
FirebaseVisionImage
nesnesi oluşturun.-
media.Image
nesnesinden birFirebaseVisionImage
nesnesi oluşturmak için (örneğin, bir cihazın kamerasından resim çekerken)media.Image
nesnesini ve resmin dönüşünüFirebaseVisionImage.fromMediaImage()
yönüne geçirin.KameraX kitaplığını kullanırsanız
OnImageCapturedListener
veImageAnalysis.Analyzer
sınıfları rotasyon değerini sizin için hesaplar. Bu nedenle,FirebaseVisionImage.fromMediaImage()
işlevini çağırmadan önce rotasyonu, ML Kit'inROTATION_
sabit değerlerinden birine dönüştürmeniz yeterlidir:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
Resmin dönüşünü gösteren bir kamera kitaplığı kullanmıyorsanız cihazın dönüşüne ve cihazdaki kamera sensörünün yönüne göre hesaplama yapabilirsiniz:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
Daha sonra,
media.Image
nesnesini ve döndürme değeriniFirebaseVisionImage.fromMediaImage()
değerine iletin:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Dosya URI'sinden bir
FirebaseVisionImage
nesnesi oluşturmak için uygulama bağlamını ve dosya URI'siniFirebaseVisionImage.fromFilePath()
öğesine iletin. Bu, kullanıcıdan galeri uygulamasından resim seçmesini istemek içinACTION_GET_CONTENT
niyeti kullandığınızda yararlı olur.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Bir
ByteBuffer
veya bayt dizisindenFirebaseVisionImage
nesnesi oluşturmak için önceliklemedia.Image
girişi için yukarıda açıklandığı gibi görüntü döndürmesini hesaplayın.Ardından resmin yüksekliği, genişliği, renk kodlama biçimini ve dönüşünü içeren bir
FirebaseVisionImageMetadata
nesnesi oluşturun:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
FirebaseVisionImage
nesnesi oluşturmak için arabelleği veya diziyi ve meta veri nesnesini kullanın:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Bitmap
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
nesnesinin temsil ettiği resim, ek döndürme gerekmeden dik olmalıdır.
-
FirebaseVisionTextRecognizer
öğesinin bir örneğini alın.Cihaz üzerinde modeli kullanmak için:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Bulut tabanlı modeli kullanmak için:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getCloudTextRecognizer(); // Or, to change the default settings: // FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() // .getCloudTextRecognizer(options);
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudTextRecognizerOptions options = new FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build();
Kotlin+KTX
val detector = FirebaseVision.getInstance().cloudTextRecognizer // Or, to change the default settings: // val detector = FirebaseVision.getInstance().getCloudTextRecognizer(options)
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudTextRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build()
Son olarak, resmi
processImage
yöntemine iletin:Java
Task<FirebaseVisionText> result = detector.processImage(image) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() { @Override public void onSuccess(FirebaseVisionText firebaseVisionText) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
val result = detector.processImage(image) .addOnSuccessListener { firebaseVisionText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2. Tanınan metin bloklarındaki metni ayıkla
Metin tanıma işlemi başarılı olursa başarı işleyiciye birFirebaseVisionText
nesnesi iletilir. FirebaseVisionText
nesnesi, resimde tanınan tam metni ve sıfır veya daha fazla TextBlock
nesnesini içerir.
Her TextBlock
, sıfır veya daha fazla Line
nesne içeren dikdörtgen bir metin blokunu temsil eder. Her Line
nesnesi, kelimeleri ve kelime benzeri varlıkları (tarihler, sayılar vb.) temsil eden sıfır veya daha fazla Element
nesne içerir.
Her TextBlock
, Line
ve Element
nesnesi için bölgede tanınan metni ve bölgenin sınırlayıcı koordinatlarını alabilirsiniz.
Örnek:
Java
String resultText = result.getText(); for (FirebaseVisionText.TextBlock block: result.getTextBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockLanguages = block.getRecognizedLanguages(); Point[] blockCornerPoints = block.getCornerPoints(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionText.Line line: block.getLines()) { String lineText = line.getText(); Float lineConfidence = line.getConfidence(); List<RecognizedLanguage> lineLanguages = line.getRecognizedLanguages(); Point[] lineCornerPoints = line.getCornerPoints(); Rect lineFrame = line.getBoundingBox(); for (FirebaseVisionText.Element element: line.getElements()) { String elementText = element.getText(); Float elementConfidence = element.getConfidence(); List<RecognizedLanguage> elementLanguages = element.getRecognizedLanguages(); Point[] elementCornerPoints = element.getCornerPoints(); Rect elementFrame = element.getBoundingBox(); } } }
Kotlin+KTX
val resultText = result.text for (block in result.textBlocks) { val blockText = block.text val blockConfidence = block.confidence val blockLanguages = block.recognizedLanguages val blockCornerPoints = block.cornerPoints val blockFrame = block.boundingBox for (line in block.lines) { val lineText = line.text val lineConfidence = line.confidence val lineLanguages = line.recognizedLanguages val lineCornerPoints = line.cornerPoints val lineFrame = line.boundingBox for (element in line.elements) { val elementText = element.text val elementConfidence = element.confidence val elementLanguages = element.recognizedLanguages val elementCornerPoints = element.cornerPoints val elementFrame = element.boundingBox } } }
Gerçek zamanlı performansı iyileştirmeye yönelik ipuçları
Gerçek zamanlı bir uygulamada metinleri tanımak için cihaz üzerindeki modeli kullanmak istiyorsanız en iyi kare hızlarını elde etmek için aşağıdaki yönergeleri uygulayın:
- Metin tanıyıcıya yapılan çağrıları kısıtlayın. Metin tanıyıcı çalışırken yeni bir video karesi açılırsa kareyi bırakın.
- Giriş görüntüsünün üzerine grafik yerleştirmek için metin tanıyıcının çıkışını kullanıyorsanız önce ML Kit'ten sonucu alın, ardından görüntüyü ve bindirmeyi tek bir adımda oluşturun. Böylece, her giriş karesi için görüntü yüzeyinde yalnızca bir kez oluşturma yaparsınız.
-
Camera2 API'yi kullanıyorsanız görüntüleri
ImageFormat.YUV_420_888
biçiminde çekin.Eski Kamera API'sini kullanıyorsanız görüntüleri
ImageFormat.NV21
biçiminde çekin. - Görüntüleri daha düşük çözünürlükte çekmeyi düşünün. Ancak bu API'nin resim boyutu şartlarını da göz önünde bulundurun.
Sonraki adımlar
- Cloud API kullanan bir uygulamanın üretimine dağıtmadan önce yetkisiz API erişiminin etkilerini önlemek ve azaltmak için ek adımlar atmanız gerekir.
Belge resimlerindeki metinleri tanıyın
Bir dokümandaki metni tanımak için bulut tabanlı belge metni tanıyıcıyı aşağıda açıklandığı şekilde yapılandırıp çalıştırın.
Aşağıda açıklanan belge metni tanıma API'si, belge görüntüleriyle çalışırken daha kullanışlı olması amaçlanan bir arayüz sağlar. Bununla birlikte, FirebaseVisionTextRecognizer
API tarafından sağlanan arayüzü tercih ederseniz bulut metin tanıyıcıyı yoğun metin modelini kullanacak şekilde yapılandırarak dokümanları taramak için bu arayüzü kullanabilirsiniz.
Doküman metni tanıma API'sini kullanmak için:
1. Metin tanıyıcıyı çalıştır
Bir görüntüdeki metni tanımak içinBitmap
, media.Image
, ByteBuffer
, bayt dizisi veya cihazdaki bir dosyadan FirebaseVisionImage
nesnesi oluşturun.
Ardından FirebaseVisionImage
nesnesini FirebaseVisionDocumentTextRecognizer
öğesinin processImage
yöntemine iletin.
Resminizden bir
FirebaseVisionImage
nesnesi oluşturun.-
media.Image
nesnesinden birFirebaseVisionImage
nesnesi oluşturmak için (örneğin, bir cihazın kamerasından resim çekerken)media.Image
nesnesini ve resmin dönüşünüFirebaseVisionImage.fromMediaImage()
yönüne geçirin.KameraX kitaplığını kullanırsanız
OnImageCapturedListener
veImageAnalysis.Analyzer
sınıfları rotasyon değerini sizin için hesaplar. Bu nedenle,FirebaseVisionImage.fromMediaImage()
işlevini çağırmadan önce rotasyonu, ML Kit'inROTATION_
sabit değerlerinden birine dönüştürmeniz yeterlidir:Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { private int degreesToFirebaseRotation(int degrees) { switch (degrees) { case 0: return FirebaseVisionImageMetadata.ROTATION_0; case 90: return FirebaseVisionImageMetadata.ROTATION_90; case 180: return FirebaseVisionImageMetadata.ROTATION_180; case 270: return FirebaseVisionImageMetadata.ROTATION_270; default: throw new IllegalArgumentException( "Rotation must be 0, 90, 180, or 270."); } } @Override public void analyze(ImageProxy imageProxy, int degrees) { if (imageProxy == null || imageProxy.getImage() == null) { return; } Image mediaImage = imageProxy.getImage(); int rotation = degreesToFirebaseRotation(degrees); FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation); // Pass image to an ML Kit Vision API // ... } }
Kotlin+KTX
private class YourImageAnalyzer : ImageAnalysis.Analyzer { private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) { 0 -> FirebaseVisionImageMetadata.ROTATION_0 90 -> FirebaseVisionImageMetadata.ROTATION_90 180 -> FirebaseVisionImageMetadata.ROTATION_180 270 -> FirebaseVisionImageMetadata.ROTATION_270 else -> throw Exception("Rotation must be 0, 90, 180, or 270.") } override fun analyze(imageProxy: ImageProxy?, degrees: Int) { val mediaImage = imageProxy?.image val imageRotation = degreesToFirebaseRotation(degrees) if (mediaImage != null) { val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation) // Pass image to an ML Kit Vision API // ... } } }
Resmin dönüşünü gösteren bir kamera kitaplığı kullanmıyorsanız cihazın dönüşüne ve cihazdaki kamera sensörünün yönüne göre hesaplama yapabilirsiniz:
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } /** * 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, Context context) 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); // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360; // Return the corresponding FirebaseVisionImageMetadata rotation value. int result; switch (rotationCompensation) { case 0: result = FirebaseVisionImageMetadata.ROTATION_0; break; case 90: result = FirebaseVisionImageMetadata.ROTATION_90; break; case 180: result = FirebaseVisionImageMetadata.ROTATION_180; break; case 270: result = FirebaseVisionImageMetadata.ROTATION_270; break; default: result = FirebaseVisionImageMetadata.ROTATION_0; Log.e(TAG, "Bad rotation value: " + rotationCompensation); } return result; }
Kotlin+KTX
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 90) ORIENTATIONS.append(Surface.ROTATION_90, 0) ORIENTATIONS.append(Surface.ROTATION_180, 270) ORIENTATIONS.append(Surface.ROTATION_270, 180) } /** * 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, context: Context): 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) // On most devices, the sensor orientation is 90 degrees, but for some // devices it is 270 degrees. For devices with a sensor orientation of // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees. val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360 // Return the corresponding FirebaseVisionImageMetadata rotation value. val result: Int when (rotationCompensation) { 0 -> result = FirebaseVisionImageMetadata.ROTATION_0 90 -> result = FirebaseVisionImageMetadata.ROTATION_90 180 -> result = FirebaseVisionImageMetadata.ROTATION_180 270 -> result = FirebaseVisionImageMetadata.ROTATION_270 else -> { result = FirebaseVisionImageMetadata.ROTATION_0 Log.e(TAG, "Bad rotation value: $rotationCompensation") } } return result }
Daha sonra,
media.Image
nesnesini ve döndürme değeriniFirebaseVisionImage.fromMediaImage()
değerine iletin:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Dosya URI'sinden bir
FirebaseVisionImage
nesnesi oluşturmak için uygulama bağlamını ve dosya URI'siniFirebaseVisionImage.fromFilePath()
öğesine iletin. Bu, kullanıcıdan galeri uygulamasından resim seçmesini istemek içinACTION_GET_CONTENT
niyeti kullandığınızda yararlı olur.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin+KTX
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Bir
ByteBuffer
veya bayt dizisindenFirebaseVisionImage
nesnesi oluşturmak için önceliklemedia.Image
girişi için yukarıda açıklandığı gibi görüntü döndürmesini hesaplayın.Ardından resmin yüksekliği, genişliği, renk kodlama biçimini ve dönüşünü içeren bir
FirebaseVisionImageMetadata
nesnesi oluşturun:Java
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build();
Kotlin+KTX
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
FirebaseVisionImage
nesnesi oluşturmak için arabelleği veya diziyi ve meta veri nesnesini kullanın:Java
FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata); // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);
Kotlin+KTX
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
Bitmap
nesnesindenFirebaseVisionImage
nesnesi oluşturmak için:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
nesnesinin temsil ettiği resim, ek döndürme gerekmeden dik olmalıdır.
-
FirebaseVisionDocumentTextRecognizer
örneği alın:Java
FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer();
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages FirebaseVisionCloudDocumentRecognizerOptions options = new FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(Arrays.asList("en", "hi")) .build(); FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options);
Kotlin+KTX
val detector = FirebaseVision.getInstance() .cloudDocumentTextRecognizer
// Or, to provide language hints to assist with language detection: // See https://cloud.google.com/vision/docs/languages for supported languages val options = FirebaseVisionCloudDocumentRecognizerOptions.Builder() .setLanguageHints(listOf("en", "hi")) .build() val detector = FirebaseVision.getInstance() .getCloudDocumentTextRecognizer(options)
Son olarak, resmi
processImage
yöntemine iletin:Java
detector.processImage(myImage) .addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText>() { @Override public void onSuccess(FirebaseVisionDocumentText result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
detector.processImage(myImage) .addOnSuccessListener { firebaseVisionDocumentText -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
2. Tanınan metin bloklarındaki metni ayıkla
Metin tanıma işlemi başarılı olursa bir FirebaseVisionDocumentText
nesnesi döndürür. FirebaseVisionDocumentText
nesnesi, resimde tanınan tam metni ve tanınan dokümanın yapısını yansıtan nesne hiyerarşisini içerir:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
Her Block
, Paragraph
, Word
ve Symbol
nesnesi için bölgede tanınan metni ve bölgenin sınırlayıcı koordinatlarını alabilirsiniz.
Örnek:
Java
String resultText = result.getText(); for (FirebaseVisionDocumentText.Block block: result.getBlocks()) { String blockText = block.getText(); Float blockConfidence = block.getConfidence(); List<RecognizedLanguage> blockRecognizedLanguages = block.getRecognizedLanguages(); Rect blockFrame = block.getBoundingBox(); for (FirebaseVisionDocumentText.Paragraph paragraph: block.getParagraphs()) { String paragraphText = paragraph.getText(); Float paragraphConfidence = paragraph.getConfidence(); List<RecognizedLanguage> paragraphRecognizedLanguages = paragraph.getRecognizedLanguages(); Rect paragraphFrame = paragraph.getBoundingBox(); for (FirebaseVisionDocumentText.Word word: paragraph.getWords()) { String wordText = word.getText(); Float wordConfidence = word.getConfidence(); List<RecognizedLanguage> wordRecognizedLanguages = word.getRecognizedLanguages(); Rect wordFrame = word.getBoundingBox(); for (FirebaseVisionDocumentText.Symbol symbol: word.getSymbols()) { String symbolText = symbol.getText(); Float symbolConfidence = symbol.getConfidence(); List<RecognizedLanguage> symbolRecognizedLanguages = symbol.getRecognizedLanguages(); Rect symbolFrame = symbol.getBoundingBox(); } } } }
Kotlin+KTX
val resultText = result.text for (block in result.blocks) { val blockText = block.text val blockConfidence = block.confidence val blockRecognizedLanguages = block.recognizedLanguages val blockFrame = block.boundingBox for (paragraph in block.paragraphs) { val paragraphText = paragraph.text val paragraphConfidence = paragraph.confidence val paragraphRecognizedLanguages = paragraph.recognizedLanguages val paragraphFrame = paragraph.boundingBox for (word in paragraph.words) { val wordText = word.text val wordConfidence = word.confidence val wordRecognizedLanguages = word.recognizedLanguages val wordFrame = word.boundingBox for (symbol in word.symbols) { val symbolText = symbol.text val symbolConfidence = symbol.confidence val symbolRecognizedLanguages = symbol.recognizedLanguages val symbolFrame = symbol.boundingBox } } } }
Sonraki adımlar
- Cloud API kullanan bir uygulamanın üretimine dağıtmadan önce yetkisiz API erişiminin etkilerini önlemek ve azaltmak için ek adımlar atmanız gerekir.