关于Android开发摄像头识别二维码/条形码的那些事

您所在的位置:网站首页 摄像头识别条形码怎么弄 关于Android开发摄像头识别二维码/条形码的那些事

关于Android开发摄像头识别二维码/条形码的那些事

2024-07-12 12:02| 来源: 网络整理| 查看: 265

随着代码更新迭代,发展迅速的前提下,作为一个java后端很苦恼的就是接触一些自己不擅长的领域,,现如今有公司都封装了业务类,所谓万物皆可以调用,那么今天就来说一说如何编写摄像头识别二维码/条形码业务类的实例代码;(博主在Android也是新手,只能总结经验,希望可以帮助到大家) 首先,所谓的业务类就是自己先编写这块业务的主要代码,然后需要这块业务时直接调用即可,这样可以调高代码的复用率与减少工作量,那么接下来让我们先了解了解安卓实现摄像头识别二维码/条形码的几种实现方式 第一种(也是博主使用的一种):使用Google ML Kit(Google ML Kit是一种强大的机器学习库,支持二维码和条形码扫描。它简单易用,支持多种格式。)第二种:使用ZXing库(ZXing是一个开源的条形码和二维码图像处理库,广泛用于Android应用中。)博主第一次实例尝试用到,但是发现不太好用,因为还要自己下载ZXing第三种:使用Google Vision API(Google Vision API是另一种处理图像的强大工具,但它的使用相比ML Kit更复杂。)第四种:使用OpenCV(OpenCV是一种计算机视觉库,可以处理图像和视频数据。)第五种:使用Firebase ML Kit(Firebase ML Kit与Google ML Kit类似,但集成了Firebase的更多功能。) 总结

以上几种方式都可以用于在Android应用中实现摄像头识别二维码。选择哪种方式主要取决于具体需求、技术栈和开发者的熟悉程度。Google ML Kit和ZXing是最常用和最推荐的方法,因为它们易于集成且功能强大。

下面可以写业务类了,但是写之前先配置相关的配置文件 其中比较重要的一点是: 在AndroidManifest.xml中一定配置摄像机权限 并在应用中声明相机使用权限 { try { cameraProvider = cameraProviderFuture.get(); bindPreview(); } catch (ExecutionException | InterruptedException e) { Log.e(TAG, "摄像头初始化失败。", e); Toast.makeText(context, "摄像头初始化失败。", Toast.LENGTH_SHORT).show(); } }, ContextCompat.getMainExecutor(context)); } private void bindPreview() { Preview preview = new Preview.Builder().build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), new ImageAnalysis.Analyzer() { @Override public void analyze(@NonNull ImageProxy imageProxy) { if (!isPaused) { analyzeImage(imageProxy); } else { imageProxy.close(); } } }); camera = cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, preview, imageAnalysis); } public void startCamera() { - 定义一个名为 startCamera 的公共方法。ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(context); - 获取 ProcessCameraProvider 的实例,它是用来控制摄像头的类。cameraProviderFuture.addListener(() -> { - 为 cameraProviderFuture 添加一个监听器,当获取 ProcessCameraProvider 实例完成时调用。try { cameraProvider = cameraProviderFuture.get(); bindPreview(); } - 在尝试块中获取 ProcessCameraProvider 实例并调用 bindPreview 方法。catch (ExecutionException | InterruptedException e) { - 捕捉执行和中断异常。Log.e(TAG, "摄像头初始化失败。", e); - 如果发生异常,记录错误日志。Toast.makeText(context, "摄像头初始化失败。", Toast.LENGTH_SHORT).show(); - 显示初始化失败的吐司消息。}, ContextCompat.getMainExecutor(context)); - 指定监听器在主线程上执行。

private void bindPreview() { - 定义一个名为 bindPreview 的私有方法。Preview preview = new Preview.Builder().build(); - 创建一个新的 Preview 实例,它用来管理摄像头预览。CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build(); - 创建一个 CameraSelector 实例,选择后置摄像头。preview.setSurfaceProvider(previewView.getSurfaceProvider()); - 设置预览视图的表面提供者。ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build(); - 创建一个 ImageAnalysis 实例,用于处理摄像头的图像数据。imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), new ImageAnalysis.Analyzer() { ... }); - 设置图像分析器,使用主线程执行分析任务。if (!isPaused) { analyzeImage(imageProxy); } else { imageProxy.close(); } - 如果扫描没有暂停,则调用 analyzeImage 方法分析图像,否则关闭 imageProxy。cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, preview, imageAnalysis); - 将摄像头绑定到生命周期所有者,开始预览和图像分析。 2. 二维码识别 ML Kit:用于文本识别和条形码扫描 @ExperimentalGetImage private void analyzeImage(ImageProxy imageProxy) { // 调用二维码/条形码识别 BarcodeScanning.getClient() .process(image) .addOnSuccessListener(barcodes -> { if (!barcodes.isEmpty()) { for (Barcode barcode : barcodes) { Log.d(TAG, "检测到条码: " + barcode.getDisplayValue()); Toast.makeText(context, "扫描结果: " + barcode.getDisplayValue(), Toast.LENGTH_SHORT).show(); pauseScanning(); } } else { Log.d(TAG, "未检测到条码"); } }) .addOnFailureListener(e -> { Log.e(TAG, "条码扫描失败。错误信息:" + e.getMessage(), e); }) .addOnCompleteListener(task -> { if (pendingTasks.decrementAndGet() == 0) { imageProxy.close(); } Log.d(TAG, "条码扫描完成"); }); }

@ExperimentalGetImage - 注解,表示使用实验性的 getImage 方法。private void analyzeImage(ImageProxy imageProxy) { - 定义一个名为 analyzeImage 的私有方法。Image mediaImage = imageProxy.getImage(); - 获取 ImageProxy 中的 Image 实例。if (mediaImage != null) { - 检查 mediaImage 是否为空。InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); - 从 mediaImage 创建一个 InputImage 实例,并根据图像信息设置旋转角度。BarcodeScanner scanner = BarcodeScanning.getClient(); - 获取条码扫描客户端。scanner.process(image) - 处理图像进行条码扫描。.addOnSuccessListener(barcodes -> { ... }) - 成功时的回调,处理检测到的条码。for (Barcode barcode : barcodes) { Log.d(TAG, "检测到条码: " + barcode.getDisplayValue()); Toast.makeText(context, "扫描结果: " + barcode.getDisplayValue(), Toast.LENGTH_SHORT).show(); } - 遍历并显示检测到的条码。imageProxy.close(); - 关闭 imageProxy 以释放资源。.addOnFailureListener(e -> { Log.e(TAG, "条码扫描失败。错误信息:" + e.getMessage(), e); imageProxy.close(); }); - 失败时的回调,记录错误并关闭 imageProxy。} else { imageProxy.close(); } - 如果 mediaImage 为空,关闭 imageProxy。 业务底层逻辑 摄像头初始化:通过ProcessCameraProvider实例化摄像头并绑定生命周期。预览配置:通过Preview和PreviewView设置摄像头预览。文本识别和二维码扫描:使用ML Kit的文本识别和条形码扫描器对图像进行处理,提取所需的信息。 下面是Activity中调用了,其中这个类继承了AppCompatActivity 类定义与成员变量 private static final int CAMERA_PERMISSION_REQUEST_CODE = 1001; private QRCodeScanner qrCodeScanner; private static final int CAMERA_PERMISSION_REQUEST_CODE = 1001; - 定义一个静态常量,用于标识摄像头权限请求的请求码。private QRCodeScanner qrCodeScanner; - 定义一个 QRCodeScanner 类型的私有成员变量,用于管理二维码扫描功能。 onCreate 方法 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qrcodescanner); PreviewView previewView = findViewById(R.id.previewView); qrCodeScanner = new QRCodeScanner(this, previewView); if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { qrCodeScanner.startCamera(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); } } @Override - 标记方法重写。protected void onCreate(Bundle savedInstanceState) { - 定义 onCreate 方法,当活动创建时调用。super.onCreate(savedInstanceState); - 调用父类的 onCreate 方法。setContentView(R.layout.activity_qrcodescanner); - 设置活动的布局文件为 activity_qrcodescanner。PreviewView previewView = findViewById(R.id.previewView); - 获取布局中的 PreviewView 视图,用于显示摄像头预览。qrCodeScanner = new QRCodeScanner(this, previewView); - 创建 QRCodeScanner 对象,传入上下文和 PreviewView。if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { - 检查是否已授予摄像头权限。qrCodeScanner.startCamera(); - 如果已授予权限,则启动摄像头。} else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); } - 否则请求摄像头权限。 onRequestPermissionsResult 方法  @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (qrCodeScanner != null) { qrCodeScanner.startCamera(); } else { Toast.makeText(this, "初始化失败,请重试", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(this, "需要摄像头权限", Toast.LENGTH_SHORT).show(); } } } @Override - 标记方法重写。public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - 定义 onRequestPermissionsResult 方法,当权限请求结果返回时调用。super.onRequestPermissionsResult(requestCode, permissions, grantResults); - 调用父类的 onRequestPermissionsResult 方法。if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { - 检查请求码是否与摄像头权限请求码匹配。if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - 检查权限请求结果是否为授予权限。if (qrCodeScanner != null) { qrCodeScanner.startCamera(); } - 如果 qrCodeScanner 不为空,则启动摄像头。else { Toast.makeText(this, "初始化失败,请重试", Toast.LENGTH_SHORT).show(); } - 如果 qrCodeScanner 为空,显示初始化失败的吐司消息。} else { Toast.makeText(this, "需要摄像头权限", Toast.LENGTH_SHORT).show(); } - 如果未授予权限,显示需要摄像头权限的吐司消息。 总结 Activity 是一个活动类,负责管理摄像头权限请求和启动摄像头预览。onCreate 方法中初始化了 QRCodeScanner 对象,并检查和请求摄像头权限。onRequestPermissionsResult 方法处理权限请求的结果,并根据结果启动摄像头或显示相应的消息。 最后前段页面 在avtivity-mian.xml中写上前端代码,就ok了

最后总结其他的方法实现: 1. 使用ZXing库

步骤:

添加依赖: implementation 'com.journeyapps:zxing-android-embedded:4.3.0' implementation 'com.google.zxing:core:3.4.1' 初始化和使用: IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("扫描二维码"); integrator.setCameraId(0); // Use a specific camera of the device integrator.setBeepEnabled(true); integrator.setBarcodeImageEnabled(true); integrator.initiateScan(); 接收结果: @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null) { if (result.getContents() == null) { Log.d("QRCodeScanner", "Cancelled scan"); Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show(); } else { Log.d("QRCodeScanner", "Scanned"); Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show(); } } else { super.onActivityResult(requestCode, resultCode, data); } } 2. 使用Google Vision API

步骤:

添加依赖: implementation 'com.google.android.gms:play-services-vision:20.1.3' 初始化和使用: BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context) .setBarcodeFormats(Barcode.ALL_FORMATS) .build(); CameraSource cameraSource = new CameraSource.Builder(context, barcodeDetector) .setFacing(CameraSource.CAMERA_FACING_BACK) .setRequestedPreviewSize(1280, 1024) .setRequestedFps(2.0f) .setAutoFocusEnabled(true) .build(); 处理结果: barcodeDetector.setProcessor(new Detector.Processor() { @Override public void release() {} @Override public void receiveDetections(Detector.Detections detections) { final SparseArray barcodes = detections.getDetectedItems(); if (barcodes.size() != 0) { // Process the barcode Log.d(TAG, "检测到条码: " + barcodes.valueAt(0).displayValue); } } }); 3. 使用OpenCV

步骤:

添加依赖: implementation project(':opencv') 使用OpenCV处理图像数据: public void processFrame(Mat frame) { // Convert frame to grayscale Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY); // Detect QR code Mat points = new Mat(); QRCodeDetector qrCodeDetector = new QRCodeDetector(); String decodedText = qrCodeDetector.detectAndDecode(frame, points); if (!decodedText.isEmpty()) { Log.d(TAG, "检测到二维码: " + decodedText); } }

4. 使用Firebase ML Kit

步骤:

添加依赖: implementation 'com.google.firebase:firebase-ml-vision:24.0.3' implementation 'com.google.firebase:firebase-ml-vision-barcode-model:16.0.2' 使用Firebase的ML Kit进行二维码扫描: FirebaseVisionBarcodeDetectorOptions options = new FirebaseVisionBarcodeDetectorOptions.Builder() .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE) .build(); FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance() .getVisionBarcodeDetector(options); detector.detectInImage(image) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(List barcodes) { for (FirebaseVisionBarcode barcode : barcodes) { Log.d(TAG, "检测到条码: " + barcode.getDisplayValue()); } } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "条码扫描失败。错误信息:" + e.getMessage(), e); } }); 最后声明:这篇稿子是基于我个人的学习和经验总结,同时参考了相关的公开文档和资源,最后集成的这边文章!!!对各位有帮助就好!!! 完工躺平 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3