google 的ML Kit 还提供了 文字识别、人脸检测、姿势坚持、拍照细分、图像标签、对象检测和跟踪、数字墨水识别等
利用机器学习套件的条形码扫描 API,您可以读取使用大多数标准条形码格式编码的数据。条形码扫描在设备上执行,不需要网络连接
官网地址:https://developers.google.com/ml-kit/vision/barcode-scanning?hl=zh-cn
读取大多数标准格式
线性格式:Codabar、Code 39、Code 93、Code 128、EAN-8、EAN-13、ITF、UPC-A、UPC-E
2D 格式:Aztec、Data Matrix、PDF417、二维码我
我们一起来看看Android的实现吧
导入
def camerax_version = "1.3.0-alpha02"
api "androidx.camera:camera-core:${camerax_version}"
api "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
api "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX View class
api "androidx.camera:camera-view:${camerax_version}"
api 'com.google.mlkit:barcode-scanning:17.0.3'
view_preview_view.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/pv_preview"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
CameraPreviewView.kt
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.util.Size
import android.view.LayoutInflater
import android.widget.FrameLayout
import android.widget.Toast
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.lifecycle.*
import com.google.mlkit.vision.barcode.BarcodeScanner
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import java.util.concurrent.Executors
/**
*@author: JayQiu
*@create: 2023/2/28
*@description:
*/
class CameraPreviewView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private val TAG = CameraPreviewView::class.java.simpleName
var mPreviewView: PreviewView
private var mCamera: Camera? = null
private var mScanner: BarcodeScanner? = null
private var mCameraAnalysis: ImageAnalysis? = null
private var mCameraProvider: ProcessCameraProvider? = null
// 默认使用后置摄像头
private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA//当前相机
private val mPreview by lazy(LazyThreadSafetyMode.NONE) {
Preview.Builder().setTargetAspectRatio((AspectRatio.RATIO_4_3)).build()
}
private var mOnScannerListener: OnScannerListener? = null
init {
inflate(context, R.layout.view_preview_view, this)
mPreviewView = findViewById(R.id.pv_preview)
val options = BarcodeScannerOptions.Builder().setBarcodeFormats(
Barcode.FORMAT_QR_CODE, Barcode.FORMAT_AZTEC
).build()
mScanner = BarcodeScanning.getClient(options)
}
fun startCamera(lifecycleOwner: LifecycleOwner) {
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
mCameraProvider = cameraProviderFuture.get()
startPreview(lifecycleOwner)
}, ContextCompat.getMainExecutor(context))
}
fun switchCamera(lifecycleOwner: LifecycleOwner) {
cameraSelector = if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
startPreview(lifecycleOwner)
}
/**
* 开启预览
*/
private fun startPreview(lifecycleOwner: LifecycleOwner) {
try {
initCameraAnalysis()
// 解除相机之前的所有绑定
mCameraProvider?.unbindAll()
// 绑定前面用于预览和拍照的UseCase到相机上
mCamera = mCameraProvider?.bindToLifecycle(lifecycleOwner, cameraSelector, mPreview, mCameraAnalysis)
// 设置用于预览的view
mPreview.setSurfaceProvider(mPreviewView.surfaceProvider)
} catch (exc: Exception) {
exc.printStackTrace()
Toast.makeText(context, "相机启动失败,${exc.message}", Toast.LENGTH_SHORT).show()
mOnScannerListener?.onFailureListener(exc)
}
}
@SuppressLint("UnsafeOptInUsageError")
private fun initCameraAnalysis() {
mCameraAnalysis = ImageAnalysis.Builder().setTargetResolution(Size(720, 1280))
// 仅将最新图像传送到分析仪,并在到达图像时将其丢弃。
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).setImageQueueDepth(1).build()
mCameraAnalysis?.setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy ->
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
mScanner?.process(image)?.addOnSuccessListener { barcodeList ->
val barcode = barcodeList.getOrNull(0)
// `rawValue` is the decoded value of the barcode
barcode?.rawValue?.let { value ->
Log.e(TAG, "==value=====$value")
mOnScannerListener?.onSuccessListener(value)
}
}?.addOnFailureListener { e ->
mOnScannerListener?.onFailureListener(e)
}?.addOnCompleteListener {
mediaImage.close()
imageProxy.close()
}
}
}
}
fun addOnScannerListener(onScannerListener: OnScannerListener) {
this.mOnScannerListener = onScannerListener
}
interface OnScannerListener {
fun onSuccessListener(value: String)
fun onFailureListener(e: Exception)
}
}
pv_surface_preview.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.threehalf.scanning.CameraPreviewView
android:layout_width="match_parent"
android:id="@+id/pv_surface_preview"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
/**
*@author: JayQiu
*@create: 2023/2/28
*@description:
*/
class ActScanning : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.act_scanning)
val view= findViewById<CameraPreviewView>(R.id.pv_surface_preview)
view.startCamera(this)
}
}
网友评论