实现功能,一个最简demo说明:
依赖
因为是实验性质,这里都是beta版本
// CameraX core library
def camerax_version = '1.1.0-beta01'
implementation "androidx.camera:camera-core:$camerax_version"
// CameraX Camera2 extensions
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:$camerax_version"
//ML Kit 中文识别
implementation 'com.google.mlkit:text-recognition-chinese:16.0.0-beta3'
CameraX调起相机预览
官方文档
官方文档有些晦涩难懂
示例代码:
layout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/container">
<androidx.camera.view.PreviewView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/previewView" />
</FrameLayout>
Activity
/**
* https://developer.android.google.cn/training/camerax/preview?hl=zh_cn#implementation
* 没有写申请权限代码
* @author markrenChina
*/
class MainActivity : AppCompatActivity() {
private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
//用于分析的线程
private lateinit var cameraExecutor: ExecutorService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/**
* 创建的实例ProcessCameraProvider。这用于将摄像机的生命周期绑定到生命周期所有者。
* 由于CameraX具有生命周期感知功能,因此省去了打开和关闭相机的任务
*/
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
/**
* 将侦听器添加到中cameraProviderFuture。添加一个Runnable作为一个参数。
* 添加作为第二个参数。这会返回在主线程上运行的。ContextCompat.getMainExecutor()Executor
*/
cameraProviderFuture.addListener(Runnable {
//用于将相机的生命周期绑定到LifecycleOwner应用程序的过程中。
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
cameraExecutor = Executors.newSingleThreadExecutor()
}
private fun bindPreview(cameraProvider : ProcessCameraProvider) {
//初始化Preview对象,调用其上的对象,从取景器中获取表面提供程序,然后在预览中进行设置。
val preview : Preview = Preview.Builder()
.build()
val cameraSelector : CameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
val previewView = findViewById<PreviewView>(R.id.previewView)
preview.setSurfaceProvider(previewView.surfaceProvider)
//分析器
val imageAnalyzer = ImageAnalysis.Builder()
.build()
.also {
it.setAnalyzer(cameraExecutor, ChineseTextAnalyzer { text ->
Log.d("MainActivity", "res: $text")
})
}
cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview,imageAnalyzer)
}
}
自定义中文识别分析器
官方外网
最简实现:
typealias RecognitionListener = ( text : String) -> Unit
/**
* 自定义中文分析器
* @author markrenChina
*/
class ChineseTextAnalyzer(
listener :RecognitionListener?= null
) : ImageAnalysis.Analyzer{
private val listeners = ArrayList<RecognitionListener>().apply { listener?.let { add(it) } }
fun onFrameAnalyzed(listener: RecognitionListener) = listeners.add(listener)
private val recognizer = TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
@SuppressLint("UnsafeOptInUsageError")
override fun analyze(image: ImageProxy) {
// If there are no listeners attached, we don't need to perform analysis
if (listeners.isEmpty()) {
image.close()
return
}
val currentTime : Any
// Keep track of frames analyzed
currentTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now()
}else {
System.currentTimeMillis()
}
//获取image,用mediaImage.close()是不安全的
val mediaImage = image.image
mediaImage?.let {
val photo = InputImage.fromMediaImage(mediaImage,image.imageInfo.rotationDegrees)
recognizer.process(photo).addOnSuccessListener { text: Text ->
listeners.forEach { it(text.text) }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
Log.d("ChineseTextAnalyzer", "analyze: duration ${Duration.between(currentTime as Instant,Instant.now()).nano} nanos")
}else {
Log.d("ChineseTextAnalyzer", "analyze: duration ${System.currentTimeMillis() - (currentTime as Long)} Millis")
}
}
}
image.close()
}
}
这种实现下,解析速度非常的慢,所以,以上代码只是一个demo,不是实际使用的代码。
附
一个封装过的aar
使用aar效果图,比demo多了一些相机相关的代码,需要注册CameraActivity: