🚀 Real-Time Text Recognition in Android with CameraX, ML Kit, and Jetpack Compose! 📱✨

Kaan Enes KAPICI
4 min readSep 28, 2024

--

Text recognition v2

Herkese selamlar. Günümüzün hızlı dijital dünyasında, mobil uygulamalara gerçek zamanlı metin tanımayı entegre etmek büyük önem kazandı. Kamera akışından metinleri anında yakalayan ve kullanıcıya sorunsuz bir deneyim sunan uygulamalar oluşturmayı düşünün. Bu blogda, Android’de CameraX, ML Kit ve Jetpack Compose kullanarak güçlü bir gerçek zamanlı metin tanıma özelliği oluşturmayı inceleyeceğiz. İster bir belge tarayıcı, ister bir dil çeviri aracı veya canlı metin çıkarma gerektiren başka bir uygulama geliştiriyor olun, bu adım adım kılavuz vizyonunuzu hayata geçirmek için en yeni araç ve teknolojilerden yararlanmanıza yardımcı olacaktır. Haydi başlayalım!

Konuya geçmeden önce bu yazıdaki anlatılan projenin tamamına şuradaki linkten ulaşabilirsiniz ➡️ https://github.com/kaaneneskpc/TextRecognition

Entegrasyon 🖥️

Bir Android uygulaması geliştirirken olmazsa olmaz kütüphaneleri entegre ederek başlamamız gerekiyor. İşte kullanacağımız kütüphaneler:

// Add the dependency to your build.gradle.kts file:

dependencies {
implementation("androidx.camera:camera-camera2:1.3.4")
implementation("androidx.camera:camera-extensions:1.3.4")
implementation("androidx.camera:camera-lifecycle:1.3.4")
implementation("com.google.accompanist:accompanist-permissions:0.31.6-rc")
implementation("com.google.mlkit:text-recognition":16.0.0")
}

CameraX: Kamera işlevlerini entegre etmek için esnek ve kullanımı kolay bir API sağlar.

ML Kit: Cihaz üzerinde gerçek zamanlı metin tanımaya olanak tanıyarak hızlı ve verimli çalışır.

Accompanist: Jetpack Compose uygulamalarında izinleri yönetmek için kullanılır. Özellikle Android 6.0 ve sonrası için çalışma zamanı izinlerini talep etmek ve yönetmek için gereklidir.

Konfigürasyon 👨‍💻

Başlangıçta, gerekli izinlerin kullanıcıdan alınması ve bu izinlerin garanti edilmesi gerekir. Eğer kullanıcı izni vermemişse, işlem yapılmamalı ve bir uyarı mesajı gösterilmelidir.

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun TextRecognitionScreen() {
//Bu, kamera izninin durumunun, kullanıcı arayüzünün yeniden oluşturulması boyunca hatırlanacağı anlamına gelir.
val cameraPermissionState: PermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)

MainContent(
//kamera izninin verilip verilmediğini gösterir.
hasPermission = cameraPermissionState.status.isGranted,
//yukarıdaki değişkenin referansıdır ve izin alınmasını sağlar.
onRequestPermission = cameraPermissionState::launchPermissionRequest
)
}

@Composable
private fun MainContent(
hasPermission: Boolean,
onRequestPermission: () -> Unit
) {
if (hasPermission) {
CameraScreen()
} else {
NoPermissionScreen(onRequestPermission)
}
}

NoPermissionScreen'de bir Text ve bir Button bulunur. Kullanıcıya iznin olmadığını ve izin alması gerektiğini belirten bir mesaj gösterilir. Button'a tıklanıldığında, ilgili izinlerin alınması sağlanır.

CameraScreen'de ise, tüm alanı kapsayan bir View nesnesi bulunur. Bu nesne, kamera akışını görüntüler ve başka bir alandaki metinleri tanımayı sağlar. Altında ise kameranın yakaladığı metnin gösterildiği bir alan bulunur:

AndroidView(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
factory = {
context ->
PreviewView(context).apply {
//CameraX kütüphanesinden gelen bir View'dır ve kamera önizlemesini görüntülemek için kullanılır. context parametresi ile oluşturulur.
layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
setBackgroundColor(Color.BLACK)
//PreviewView'ın uyumluluk modunda çalışmasını sağlar. Bu, daha eski cihazlarda daha iyi performans sağlayabilir.
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
//PreviewView.ScaleType.FILL_START: Kamera önizlemesinin nasıl ölçekleneceğini belirler. FILL_START, önizlemenin View'ı doldurmasını ve sol üst köşeden başlamasını sağlar.
scaleType = PreviewView.ScaleType.FILL_START
}.also { previewView ->
//Tanıma işini başlatır.
startTextRecognition(
context = context,
cameraController = cameraController,
lifecycleOwner = lifecycleOwner,
previewView = previewView,
onDetectedTextUpdated = ::onTextUpdated
)
}
}
)

Tanıma İşlemi

Şimdi tanıma işlemini gerçekleştiren kod bloğuna göz atalım:

private fun startTextRecognition(
context: Context,
cameraController: LifecycleCameraController,
lifecycleOwner: LifecycleOwner,
previewView: PreviewView,
onDetectedTextUpdated: (String) -> Unit
) {
//kamera kontrolcüsünün görüntü analiz boyutu için hedef en boy oranını 16:9 olarak ayarlar.
cameraController.imageAnalysisTargetSize = CameraController.OutputSize(AspectRatio.RATIO_16_9)
//kamera kontrolcüsüne görüntü analizörü olarak TextRecognitionAnalyzer sınıfını ayarlar.
cameraController.setImageAnalysisAnalyzer(
ContextCompat.getMainExecutor(context),
TextRecognitionAnalyzer(onDetectedTextUpdated = onDetectedTextUpdated)
)
//kamera önizlemesinin yaşam döngüsünü uygulama yaşam döngüsüyle senkronize eder ve kaynakların doğru bir şekilde yönetilmesini sağlar.
cameraController.bindToLifecycle(lifecycleOwner)
previewView.controller = cameraController
}

Son olarak, tanıma işlemini gerçekleştiren TextRecognitionAnalyzer sınıfımıza bakalım:

class TextRecognitionAnalyzer(
private val onDetectedTextUpdated: (String) -> Unit
) : ImageAnalysis.Analyzer {

companion object {
// Metin tanıma işlemi arasındaki gecikmeyi milisaniye cinsinden belirtir.
// Bu, işlemcinin aşırı yüklenmesini önlemek için kullanılır.
const val THROTTLE_TIMEOUT_MS = 1_000L
}

private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
//TextRecognizerOptions.DEFAULT_OPTIONS, Varsayılan metin tanıma seçeneklerini kullanır
private val textRecognizer: TextRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)

@OptIn(ExperimentalGetImage::class)
override fun analyze(imageProxy: ImageProxy) {
scope.launch {
// InputImage, ML Kit tarafından metin tanıma işlemi için kullanılan bir sınıftır.
// imageProxy.imageInfo.rotationDegrees, görüntünün döndürülme açısını belirtir.
val mediaImage: Image = imageProxy.image ?: run { imageProxy.close(); return@launch }
val inputImage: InputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)

suspendCoroutine { continuation ->
//Ekrandaki resmi analiz eder.
textRecognizer.process(inputImage)
.addOnSuccessListener { visionText: Text ->
// Algılanan metin visionText nesnesinde bulunur. Ve update edilerek ekranda gösterilir.
val detectedText: String = visionText.text
if (detectedText.isNotBlank()) {
onDetectedTextUpdated(detectedText)
}
}
.addOnCompleteListener {
continuation.resume(Unit)
}
}

delay(THROTTLE_TIMEOUT_MS)
}.invokeOnCompletion { exception ->
//Hata oluştuğunda ImageProxy nesnesini kapatır. Bu, kaynakların serbest bırakılması için önemlidir.
exception?.printStackTrace()
imageProxy.close()
}
}
}

TextRecognitionAnalyzer sınıfı, kamera tarafından yakalanan görüntüleri analiz ederek metin tanıma işlemini gerçekleştirir. Google ML Kit'in metin tanıma istemcisini kullanır ve algılanan metni belirtilen bir callback fonksiyonu aracılığıyla iletir. İşlem arka planda bir coroutine içinde çalıştırılır ve işlemcinin aşırı yüklenmesini önlemek için bir gecikme eklenir. İşlem tamamlandığında veya bir hata oluştuğunda kaynaklar serbest bırakılır.

🎉CameraX, ML Kit ve Jetpack Compose’u entegre ederek Android uygulamamızda güçlü bir gerçek zamanlı metin tanıma özelliği geliştirdik. Kullanıcılar kameralarını herhangi bir metne doğrultarak uygulamanın tanıdığı içeriği anında görüntüleyebilirler. Bu özellik, belgeleri taramaktan gerçek zamanlı çeviri araçları oluşturmaya kadar pek çok kullanım senaryosuna uygundur. CameraX’in güçlü kamera kontrolü, ML Kit’in güvenilir makine öğrenimi yetenekleri ve Jetpack Compose’un modern UI çerçevesiyle, işlevsel ve şık bir uygulama geliştirdik.

Buraya kadar gelip yazımı okuduğunuz için teşekkür ediyorum! 🙏
Bir sonraki yazımda görüşmek üzere ✌️

Kaynakça:

--

--

Kaan Enes KAPICI
Kaan Enes KAPICI

Written by Kaan Enes KAPICI

Hi everybody, I’m Kaan. Senior Application(Android) Engineer at @TurkTelekom/Innova - Ex @Qnb Love cats and dogs.🐶🐈. Writing whatever I want..

No responses yet