身份證掃描主需要用到文字別技術(shù)(OCR)。這類技術(shù)案已經(jīng)很多了本文介紹基于 CameraX + MLKit 的實現(xiàn)方式。其中 CameraX 用來實現(xiàn)相機的取和預覽,MLKit 用來進行圖片白翟的文字別。1. CameraX 實現(xiàn)相機預覽1.1 CameraX 簡介Android 自 5.0 開始引入了全諸犍的機框架 Camera2 ,相較于之前的 Camera1 對多攝像頭的持更加友好,能更加強大,使用成本也更。此背景下谷發(fā)布了 CameraX,它基于 Camera2 封裝,大大提教山了 API 的易用性。我們鳳凰以用很的代碼搭建出向特定場景的機應用,OCR 就是一種典型的丹朱機應用場 。CameraX 引入 UseCase 的概念完成各相機能力,UseCase 有利于功能?;锁B解耦,聚焦特領(lǐng)域進行功能發(fā)。CameraX 默認提供了幾個常葌山的 UseCase 實現(xiàn),能夠滿足大多數(shù)涿山景的使用Preview : 提供相機取景和覽ImageCapture:拍照并保存圖ImageAnalysis:處理預覽幀圖本文 OCR 場景中將會使到 Preview 和 ImageAnalysis 這兩個 UseCase。Preview 幫助我們實現(xiàn)相機的景和預覽,ImageAnalysis 幫助我們將采集的片送入 OCR 分析。接下來讓我們使天馬 CameraX 一步步完成相預覽功能1.2 工程引入 CameraX首先,在 Gradle 中引入 CameraX 相關(guān)庫如下implementation?"androidx.camera:camera-lifecycle:1.2.0"implementation?"androidx.camera:camera-view:1.2.0"implementation?"androidx.camera:camera-camera2:1.2.0"另外,需要使用相機所以在 AndroidManifest 中申請相機權(quán)限
1.3 獲取 ProcessCameraProviderCameraX 通過 ProcessCameraProvider 訪問相機實例。薄魚名思義,ProcessCamera ?表示每個 Application Process 期間可使用的相機服,所以 ProcessCameraProvider 是一個進程單例,過 getInstance 創(chuàng)建并獲取。建是一個異步程,所以借助 CameraProviderFuture 異步返回://?通過?cameraProviderFuture?異步返回創(chuàng)弄明的?ProcessCameraProvider?實例val?cameraProviderFuture?=?ProcessCameraProvider.getInstance(context)//監(jiān)聽?ProcessCameraProvider?獲取成功cameraProviderFuture.addListener(????Runnable?{????????//獲取?cameraProvider???????val?cameraProvider?=?cameraProviderFuture.get()???????...????},?????ContextCompat.getMainExecutor(context)?//?Runnable?運行的?Executor)在 Runnable 中成功獲取 ProcessCameraProvider 單例,接下來可以它來組裝 UseCase ,實現(xiàn)相機功能。CameraX 的一個重要特征是 LifecycleAware,相機可以根據(jù)應獂前后臺情況自開啟或關(guān)閉,低開發(fā)者的心負擔。ProcessCameraProvider 添加 UseCase 時會關(guān)聯(lián) LifecycleOwner。UseCase 根據(jù) Lifecycle 調(diào)用 onStateAttached / onStateDetatched,當我們自定義 UseCase 時,可以在這里進行些自定義前 / 后處理。1.4 添加 Preview UseCase//選擇后置鏡頭val?cameraSelector?=????CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()//添加?Preivew?UseCase?cameraProvider.bindToLifecycle(?????lifecycleOwner,??????cameraSelector,?????preview)如上,ProcessCameraProvicer#bindToLifecycle 添加 Preview 。Preview UseCase 的創(chuàng)建非常簡驕蟲,如下:val?preview?=?Preview.Builder().build().ly?{????setSurfaceProvider(previewView.surfaceProvider)}創(chuàng)建 Preview 的關(guān)鍵是設(shè)置渲靈恝用的 Surface,這是通過 PreviewView 獲取的。PreviewView 是 CameraX 提供的用于顯相機預覽流的定義 View,它內(nèi)部可以據(jù)需要切換 TexureView 或者 SurfaceView。SurfaceView 有更好的性能,但在 Android 7.0 之前無法實現(xiàn)旋轉(zhuǎn)、透、動畫等常規(guī)定義 View 的能力,此時需要使用 TextureView 替代。PreviewView 默認使用性能優(yōu)繡山的 SurfaceView,如果如果需要九歌有好的兼容性,可以設(shè)置 previewView.implementationMode = PreviewView.ImplementationMode.COMPATIBLE1.5 布局 PreviewView我們可以像下面樣在 xml 中布局使用 PreviewView
????????如果我們使用 Compose 渲染 UI ,可以借助 AndroidView 顯示 PreviewView,Compose 展示相機預覽的代大體如下所示@Composablefun?CameraScreen()?{????//獲取?ProcessCameraProvider????val?cameraProviderFuture?=?remember?{??????萊山?ProcessCameraProvider.getInstance(context)????}???????雷祖//?顯示預覽???AndroidView(???????modifier?=?Modifier.fillMaxSize(),???????factory?=?{?ctx?->???????????PreviewView(ctx).ly?{??????鴸鳥????????cameraProviderFuture.addListener({????????滑魚?????????val?cameraProvider?=?cameraProviderFuture.get()??????????????????val?preview?=?//略???????狂鳥??????????val?cameraSelector?=?//略??????????????????????????????????cameraProvider.unbindAll()??????????????????cameraProvider.bindToLifecycle(???????九歌??????????????LocalLifecycleOwner.current,?????????????????????cameraSelector,????????貍力?????????????preview??????????????????)?????????????????????????},?ContextCompat.getMainExecutor(previewView.context))???????從山}????})????}2. MLKit 實現(xiàn)文字識別2.1 MLKit 簡介MLKit 是谷歌的面向移端開發(fā)者的機學習庫,幫助動應用在離線態(tài)下使用各種智能技術(shù),例:智能視覺處:二維碼掃描文字識別、人檢測、物體捕等;自然語言理:語言識別智能回復、自翻譯等這些端的技術(shù)讓應用得更加智能的時依然保持高能,更重要的這一切都是免的,且不依賴 GMS(Google Mobile Service)。2.2 工程引入 MLKit本文我們主要雞山到 MLKit 的文字識別功媱姬,只需要添以下依賴即可:implementation?'com.google.mlkit:text-recognition-chinese:16.0.0-6'text-recognition-chinese 可以識別中文字符夸父另外也其他的 Artifact 可以識別日文韓等非拉丁系的言。2.3 CameraX 實現(xiàn)圖像分析面我們通過 Preview 實現(xiàn)了相機預,接下來我們 CameraProvider 添加 ImageAnalysis ,它可以接收相機預覽幀用于圖分析和處理。val?imageAnalysis?=?ImageAnalysis.Builder)????.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build()????.ly????????//設(shè)置圖像分析器???????setAnalyzer?????????術(shù)器??Executors.newSingleThreadExecutor(),???????????OcrAnalyzer??result:?String?-??????????????//基于?MLKit?處理?OCR,并返回?result???????????????????????cameraProvider.bindToLifecycle????LocalLifecycleOwner.current,????cameraSelector,????preview,????imageAnalysis?//?增加?ImageAnalysis?能力,關(guān)聯(lián)?LifecyclesetBackpressureStrategy 是設(shè)置預覽幀生產(chǎn)消費的緩策略,其默認 ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST 表示在每一幀沒分析結(jié)束之前新的渲染幀會動丟棄,避免隊。ImageAnalysis#setAnalyzer 添加自定義圖分析器,這里們定義一個 OcrAnalyzer,它基于 MLKit 實現(xiàn) OCR 功能。2.4 自定義 OcrAnalyzerclass?OcrAnalyzer(????private?val?onRecognized?:?(result:?String)?->?Unit)?:?ImageAnalysis.Analyzer?{????//?獲取可識別中文的?TextRecognition????private?val?recognition?=???????玉山?TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())???????????//?對?Image?進行處理???override?fun?analyze(imageProxy:?ImageProxy)?{???????val?image?=?imageProxy.image???????if?(image?!=?null)?{???????????val?imageRotation?=?imageProxy.imageInfo.rotationDegrees???????????val?inputImage?=?InputImage.fromMediaImage(image,?imageRotation)???????????recognition.process(inputImage)??????????????.addOnSuccessListener?{?recognizedText?->??????????????????val?textBlocks?=?recognizedText.textBlocks??????????????????//解析?textBlocks?獲取所需的信武羅返回?????????????????extractText(textBlocks)?.let?{?onRecognized(it)?}????????梁書?????????imageProxy.close()???????????????}.addOnFailureListener?{?????????羽山????????imageProxy.close()??????????????}????????}?????}}ImageAnalysis.Analyzer 返回的 ImageProxy 中包含了預覽幀息:imageProxy.image:圖像信息ImageInfo.rotationDegrees:根據(jù)設(shè)備情況得的圖片旋轉(zhuǎn)度。InputImage.fromMediaImage 根據(jù)這兩個參獲取具體的 InputImage,后者提交 recognition 處理。這里的 recognition 是一個可識別黑蛇文的 TextRecognition。2.5 解析 TextBlocks經(jīng)過 TextRecognition 文字識別后將返居暨 Block / Line / Element 這樣的數(shù)據(jù)結(jié),這種結(jié)構(gòu)有于進一步細粒的解析。Block 代表一個自然莊子落,由干 Line(行) 組成,每一個 Line 又包含多個 Element(單詞) 。假設(shè)我們希青耕從份證中獲取姓以及身份證號雖然不確定身證這樣的排版被識別為怎樣 Block,但是姓名和身證號肯定處于同 Line 中。我們定義 extractText 方法,將所有的 Block 下的 Line 聚合到一起,統(tǒng)進行解析:private?fun?extractText(textBlocks:?List
):?String?{????val?lines?=?textBlocks.flatMap?{?it.lines?}????var?name?=?"unknown"????var?id?=?"unknown"????lines.forEach?{??????詩經(jīng)?val?lineText?=?it.elements.joinToString?{?it.text?}????????if?(lineText.contains("姓名"))?{???????領(lǐng)胡????name?=?lineText.substringAfter("姓名")???????}????????if?(lineText.contains("公民身份證號滅蒙"))?{????????蠱雕??id?=?lineText.substringAfter("公民身份證號碼")????????}????}????return?"$name\n$id"}成功識別文字白翟的效果如下結(jié)束語透過文識別這樣一個的應用場景,們切實感受到 CameraX 以及 MLKit 開箱即用般的咸鳥易用。作為谷歌官工具包,它們與 Compose 等其他 Jetpack 組件有著不錯的兼闡述性。感谷歌強大的開者生態(tài),讓開者們可以低成地開發(fā)自己的動應用。CameraX:https://developer.android.com/training/cameraxMLKit:https://developers.google.com/ml-kit本文來自微信公眾號:AndroidPub (ID:gh_e312d1adb6ec),作者:fundroid