【Android App】人脸识别中扫描识别二维码实战解析(附源码和演示 超详细)

news2024/9/30 11:22:28

需要源码请点赞关注收藏后评论区留言私信~~~

一、扫描识别二维码

不仅可以利用zxing库生成二维码,同样利用zxing库可以扫描二维码并解析得到原始文本,此时除了给build.gradle添加如下一行依赖配置

implementation 'com.google.zxing:core:3.4.1'

还需要给App工程引入代码包com.app.zxing 可以私信博主要

同时扫描会用到手机摄像头,因此要给App添加相机权限,如果识别出二维码之时需要震动手机提醒用户,还得申请震动权限

使用Zxing库在代码中增加扫码的支撑操作,主要实现三个功能点:

(1)初始化相机并开始扫码

因为com.app.zxing包重新封装系统的相机工具,并提供了扫码专用的相机管理器CameraManager,所以若要打开相机只需调用CameraManager的openDriver方法,关闭相机则需要调用closeDriver方法

(2)处理扫码结束后的提示音响

通常扫码结束会发出滴的声音,提示用户已经识别出二维码内容,请及时关注App后续处理,这个提示音可采用媒体播放器MediaPlayer播放,在扫码前初始化播放器对象,待扫码完成再调用播放器的start方法,除了滴的提示音,震动提示也很常见

(3)处理扫码识别到的文本信息

扫码识别的二维码内容其实是一个字符串,有时为HTTP链接,有时为其他协议的地址,总之拿到结果字符串后,App还得根据链接地址区分处理,要么打开新链接页面,要么完成支付操作,要么启动某个App

扫码后识别字符串文本效果如下 字符串可以自己手动输入

读者可以自行扫描下方二维码体验效果 

 

 

 代码如下

package com.example.face;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.app.zxing.camera.CameraManager;
import com.app.zxing.decoding.CaptureActivityHandler;
import com.app.zxing.decoding.InactivityTimer;
import com.app.zxing.view.ViewfinderView;
import com.example.face.util.QrcodeUtil;
import com.google.zxing.Result;

public class ScanQrcodeActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private final static String TAG = "ScanQrcodeActivity";
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private ViewfinderView vv_finder; // 定义一个扫码视图对象
    private boolean hasSurface = false; // 是否创建了渲染表面
    private CaptureActivityHandler mHandler; // 捕捉图像的处理器
    private InactivityTimer mTimer; // 结束活动的计时器
    private MediaPlayer mPlayer; // 声明一个媒体播放器对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan_qrcode);
        findViewById(R.id.iv_back).setOnClickListener(v -> finish());
        TextView tv_title = findViewById(R.id.tv_title);
        tv_title.setText("二维码扫描/条形码扫描");
        TextView tv_option = findViewById(R.id.tv_option);
        tv_option.setVisibility(View.VISIBLE);
        tv_option.setText("相册");
        tv_option.setOnClickListener(v -> {
            // 创建一个内容获取动作的意图(准备跳到系统相册)
            Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
            albumIntent.setType("image/*"); // 类型为图像
            startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
        });
        CameraManager.init(getApplication(), CameraManager.QR_CODE);
        vv_finder = findViewById(R.id.vv_finder);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mTimer = new InactivityTimer(this);
        SurfaceView sv_scan = findViewById(R.id.sv_scan);
        // 从表面视图获取表面持有者
        SurfaceHolder surfaceHolder = sv_scan.getHolder();
        if (hasSurface) { // 已创建渲染表面
            initCamera(surfaceHolder); // 初始化相机
        } else { // 未创建渲染表面
            surfaceHolder.addCallback(this);
        }
        initBeepSound(); // 初始化哔哔音效
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mHandler != null) {
            mHandler.quitSynchronously();
            mHandler = null;
        }
        CameraManager.get().closeDriver();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTimer.shutdown();
    }

    // 处理实时扫描获得的二维码信息
    public void handleDecode(Result result, Bitmap barcode) {
        mTimer.onActivity();
        beepAndVibrate(); // 震动手机并发出哔的一声
        // 读取二维码分析后的结果字符串
        String resultStr = result.getText();
        if (TextUtils.isEmpty(resultStr)) {
            Toast.makeText(this, "扫码失败或者结果为空", Toast.LENGTH_SHORT).show();
        } else {
            //Toast.makeText(this, "扫码结果为"+resultStr, Toast.LENGTH_SHORT).show();
            gotoResultPage(resultStr); // 跳到扫描结果页面
        }
    }

    // 跳到扫描结果页面
    private void gotoResultPage(String resultStr) {
        Intent intent = new Intent(this, ScanResultActivity.class);
        intent.putExtra("result", resultStr);
        startActivity(intent);
    }

    // 初始化相机
    private void initCamera(SurfaceHolder surfaceHolder) {
        try {
            CameraManager.get().openDriver(surfaceHolder);
            if (mHandler == null) {
                mHandler = new CaptureActivityHandler(this, null, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 在渲染表面变更时触发
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

    // 在渲染表面创建时触发
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!hasSurface) {
            hasSurface = true;
            initCamera(holder);
        }
    }

    // 在渲染表面销毁时触发
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        hasSurface = false;
    }

    public ViewfinderView getViewfinderView() {
        return vv_finder;
    }

    public Handler getHandler() {
        return mHandler;
    }

    // 描绘扫码时的动态横杠
    public void drawViewfinder() {
        vv_finder.drawViewfinder();
    }

    // 初始化哔哔音效
    private void initBeepSound() {
        if (mPlayer == null) {
            // 设置当前页面的音频流类型
            setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mPlayer = new MediaPlayer(); // 创建一个媒体播放器
            // 设置媒体播放器的音频流类型
            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            // 设置媒体播放器的播放结束监听器
            mPlayer.setOnCompletionListener(player -> player.seekTo(0));
            try (AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.beep)) {
                // 设置媒体播放器的媒体数据来源
                mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                mPlayer.setVolume(0.1f, 0.1f); // 设置媒体播放器的左右声道音量
                mPlayer.prepare(); // 媒体播放器准备就绪
            } catch (Exception e) {
                e.printStackTrace();
                mPlayer = null;
            }
        }
    }

    // 震动手机并发出哔的一声
    private void beepAndVibrate() {
        if (mPlayer != null) {
            mPlayer.start(); // 媒体播放器开始播放
        }
        // 从系统服务中获取震动器
        Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
        vibrator.vibrate(200); // 命令震动器震动若干秒
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回
            if (intent.getData() != null) { // 从相册选择一张照片
                // 开启分线程从相册的图片Uri中解析二维码
                new Thread(() -> parserImage(intent.getData())).start();
            }
        }
    }

    // 从相册的图片Uri中解析二维码
    private void parserImage(Uri uri) {
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
            Result result = QrcodeUtil.parserQrcode(bitmap); // 从位图中解析二维码
            if (result == null) {
                Looper.prepare();
                Toast.makeText(this, "无法解析图片中的二维码", Toast.LENGTH_SHORT).show();
                Looper.loop();
            } else {
                String resultStr = QrcodeUtil.reEncode(result.toString());
                Log.d(TAG, "resultStr="+resultStr);
                gotoResultPage(resultStr); // 跳到扫描结果页面
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

创作不易 觉得有帮助请点赞关注收藏~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文读懂什么是云原生|推荐收藏

Forrester数据显示,在2021年,全球云原生应用持续上升,组织中容器和无服务器技术的使用率在一年内都增长了75%以上。 Gartner预测,到2025年,将会有超过95%的新数字工作负载被部署在云原生平台上。 “未来的软件一定是长…

Qt第二十六章:QWidget、QMainWindow自定义标题栏

工具类(读者直接复制到项目中) class QCustomTitleBar:def __init__(self, window: QtWidgets):self.window window# 默认标题栏高度 必须设self.DEFAULT_TITILE_BAR_HEIGHT 40# 存储父类的双击事件self.mouseDoubleClickEvent_parent self.window.mo…

【数学】旋转后仍为函数图像问题

∣旋转后仍为函数图像问题NightguardSeries.∣\begin{vmatrix}\huge{\textsf{ 旋转后仍为函数图像问题 }}\\\texttt{ Nightguard Series. }\end{vmatrix}∣∣∣∣∣​ 旋转后仍为函数图像问题 Nightguard Series. ​∣∣∣∣∣​ ♣例1\clubsuit \textsf{例1}♣例1 f(x)ln⁡(x…

经典bloom算法(**布隆过滤器**)-levelDB拆分

bloom算法(布隆过滤器) 原理 先说一下什么是布隆过滤器,Bloom Filter是1970年由布隆提出的,它实际上是一个很长的二进制向量,和一系列随机值映射的函数,主要用于判断一个元素是否在一个集合中。 通常判断一个元素是否在一个集合…

Hasse diagram

In order theory, a Hasse diagram (/ˈhsə/; German: [ˈhasə]) is a type of mathematical diagram used to represent a finite partially ordered set, in the form of a drawing of its transitive reduction. Concretely, for a partially ordered set (S, ≤) one rep…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校学生宿舍管理信息系统3x4rz

做毕业设计一定要选好题目。毕设想简单,其实很简单。这里给几点建议: 1:首先,学会收集整理,年年专业都一样,岁岁毕业人不同。很多人在做毕业设计的时候,都犯了一个错误,那就是不借鉴…

記錄下用google colab 进行GPU(TPU)训练

文章目录温馨提示打开网站上传资源下载资源到google colab温馨提示 需要科学上网,没有的话可以点这个 https://shandianpro.com/#/register?codewCXwkCOU下个clashx进行 挂载 https://download.csdn.net/download/monk96/87231589 配置自行百度 打开网站 google…

Win11系统提示backgroundtaskhost.exe系统错误解决方法

Win11系统提示backgroundtaskhost.exe系统错误解决方法分享。backgroundTaskHost.exe是与Microsoft Cortana的虚拟助手相关联的关键系统进程。近期有Win11用户在电脑的使用中遇到了系统提示“backgroundTaskHost.exe – ApplicATIon Error”的错误,今天我们一起来看…

[附源码]计算机毕业设计JAVA学生考试成绩分析系统

[附源码]计算机毕业设计JAVA学生考试成绩分析系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM my…

疫情可视化part3

前言 之前在part2中说的添加自定义主题配色已经开发完成了,除此之外我还添加了一些的3d特效。 前期文章 这是part1的文章:https://blog.csdn.net/xi1213/article/details/126824752这是part2的文章:https://blog.csdn.net/xi1213/article/…

[附源码]Python计算机毕业设计Django基于VUE的网上订餐系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

【Linux】进程

1.linux操作系统要不要管理进程呢?必须要!!!!!!!!! 2.linux是如何管理大量进程的呢?先组织,再描述。 1.什么是进程 进程就是系统运行中…

WordPress批量修改数据库内文章内容文字关键字标题

WordPress网站内容标题文字一键修改,注意到了网站上很多要一个个的修改,那工作了巨大,怎么快速在数据库中用SQL命令批量替换呢? 通过数据库替换方法 1.进入宝塔面板-数据库-选择对应的数据库-管理数据库-登录进来。就可以直接对数…

2022年小美赛“认证杯”数学建模ABCD题初步分析选题建议

​ 2022年小美赛数学建模赛题已经发布: A题 翼龙是如何飞行的 B题 序列的遗传过程 C题 对人类活动进行分类 D题 是否应长期禁止野生动物贸易 总体来说,从赛题难度来看B>A>C>D,其中CD属于ICM交叉学科类赛题,难度系数相对…

腾讯云原生安全“3+1”一体化方案发布,重构云上安全防御体系

12月1日,2022腾讯全球数字生态大会上,以“安全守护,行稳致远”为主题的「云原生安全专场」顺利召开,论坛深入讨论了云原生安全的行业发展趋势、技术探索、产品创新和落地实践。 会上,腾讯安全发布了云原生安全“31”一…

java面向对象-----再谈方法

目录 方法的重载(overload) 可变个数的形参 方法参数的值传递机制 基本数据类型的参数传递 引用数据类型的参数传递 递归(recursion)方法 总结 方法的重载(overload) 重载的概念 :在同一个类中,允许存在一个以上的同名方法,只要它们的参…

基于粒子群优化的神经网络PID控制(Matlab)代码实现

🍒🍒🍒欢迎关注🌈🌈🌈 📝个人主页:我爱Matlab 👍点赞➕评论➕收藏 养成习惯(一键三连)🌻🌻🌻 🍌希…

“空间代谢组学“用于食管鳞状细胞癌早期筛查的研究

​ 代谢组学文献分享—研究背景 近几年代谢组学的研究如火如荼的开展,极大地促进了各学科的发展,如疾病诊断与治疗、营养学、环境毒理学、进化和发育及药物等;与此同时,质谱成像技术(mass spectrometry imaging, MSI…

动态规划思想

1.动态规划思想:因为计算量太大而提出的解放方式。将一件大的事情分成若干个小的事情。2.找一个最优的隐藏序列,结合动态规划思想,可以把这个隐藏序列分成多个时间步,如果每个时间步都是最优的,那么最终的这个序列就是…

软件测试流程分享

工作以来,大大小小参与的项目也有十几个了,涵盖财务类、保险类、OA办公类软件,从测试流程上看,基本也都大同小异,这里将常见的测试流程做一些梳理,供刚入行的朋友学习参考,也欢迎大家完善补充。…